diff --git a/CycloBranch.sln b/CycloBranch.sln new file mode 100644 index 0000000..cae5bf9 --- /dev/null +++ b/CycloBranch.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CycloBranch", "CycloBranch\CycloBranch.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.ActiveCfg = Debug|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.Build.0 = Debug|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|x64 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.Build.0 = Debug|x64 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.ActiveCfg = Release|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|Win32.Build.0 = Release|Win32 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|x64 + {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/CycloBranch/CycloBranch.vcxproj b/CycloBranch/CycloBranch.vcxproj new file mode 100644 index 0000000..58c9984 --- /dev/null +++ b/CycloBranch/CycloBranch.vcxproj @@ -0,0 +1,562 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {B12702AD-ABFB-343A-A199-8E24837244A3} + Qt4VSv1.0 + CycloBranch + + + + Application + v110 + + + Application + v110 + + + Application + v110 + + + Application + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + $(SolutionDir)$(Platform)\$(Configuration)\ + + + $(SolutionDir)$(Platform)\$(Configuration)\ + + + $(SolutionDir)$(Platform)\$(Configuration)\ + + + $(SolutionDir)$(Platform)\$(Configuration)\ + false + + + + UNICODE;WIN32;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions) + .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories) + Disabled + ProgramDatabase + MultiThreadedDebugDLL + false + + + Windows + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;%(AdditionalLibraryDirectories) + true + qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;%(AdditionalDependencies) + + + + + UNICODE;WIN32;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions) + .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories) + Disabled + ProgramDatabase + MultiThreadedDebugDLL + false + + + Windows + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;%(AdditionalLibraryDirectories) + true + qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;%(AdditionalDependencies) + + + + + UNICODE;WIN32;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions) + .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories) + + MultiThreadedDLL + false + + + Windows + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;%(AdditionalLibraryDirectories) + false + qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;%(AdditionalDependencies) + + + + + UNICODE;WIN32;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions) + .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories) + ProgramDatabase + MultiThreadedDLL + true + Level3 + true + true + true + true + + + Windows + $(OutDir)\$(ProjectName).exe + $(QTDIR)\lib;%(AdditionalLibraryDirectories) + true + qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;%(AdditionalDependencies) + true + true + UseLinkTimeCodeGeneration + + + + + + + + + + + + + + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cLinearWidget.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 cLinearWidget.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 cLinearWidget.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 cLinearWidget.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 cCyclicWidget.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 cCyclicWidget.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 cCyclicWidget.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 cCyclicWidget.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 cBranchedWidget.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 cBranchedWidget.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 cBranchedWidget.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 cBranchedWidget.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 cFragmentIonsListWidget.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 cFragmentIonsListWidget.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 cFragmentIonsListWidget.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 cFragmentIonsListWidget.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 cGraphReaderThread.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 cGraphReaderThread.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 cGraphReaderThread.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 cGraphReaderThread.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" + + + Moc%27ing cSpectrumComparatorThread.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" + Moc%27ing cSpectrumComparatorThread.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" + Moc%27ing cSpectrumComparatorThread.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" + Moc%27ing cSpectrumComparatorThread.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) + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing cGraphicalSpectrumWidget.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 cGraphicalSpectrumWidget.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 cGraphicalSpectrumWidget.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 cGraphicalSpectrumWidget.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 cSpectrumDetailWidget.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 cSpectrumDetailWidget.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 cSpectrumDetailWidget.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 cSpectrumDetailWidget.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 cMainWindow.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 cMainWindow.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 cMainWindow.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 cMainWindow.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 cMainThread.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 cMainThread.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 cMainThread.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 cMainThread.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 cParametersWidget.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 cParametersWidget.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 cParametersWidget.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 cParametersWidget.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 cGraphWidget.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 cGraphWidget.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 cGraphWidget.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 cGraphWidget.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 cAboutWidget.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 cAboutWidget.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 cAboutWidget.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 cAboutWidget.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" + + + + + + + + + + + \ No newline at end of file diff --git a/CycloBranch/CycloBranch.vcxproj.filters b/CycloBranch/CycloBranch.vcxproj.filters new file mode 100644 index 0000000..cd10613 --- /dev/null +++ b/CycloBranch/CycloBranch.vcxproj.filters @@ -0,0 +1,283 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;cxx;c;def + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + moc;h;cpp + False + + + {50123869-bff2-4b54-9131-0bf502edae17} + cpp;moc + False + + + {a1c6ca65-210f-46fd-bdf0-d6b5297a74ff} + cpp;moc + False + + + {d9a9fe3c-960f-406f-a2ad-2f11cb56f027} + + + {bdb0c1fb-0940-4611-a53d-01314629c624} + + + {8344fcea-7ee5-4f94-88f9-373484a9244f} + + + {f88212ab-d8b0-416c-855e-cca9b97df52b} + + + {ca6be5b6-1c11-4f58-9fba-b869dc6b4a7d} + + + {ede1a4b0-ffbc-4a56-8e82-02552392966b} + + + + + Source Files\core + + + Source Files\core + + + Source Files\core + + + Source Files\core + + + Source Files\core + + + Source Files\core + + + Source Files\core + + + Source Files\core + + + Source Files\core + + + Source Files\core + + + Source Files + + + Source Files\core + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\gui + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\gui + + + Source Files\gui + + + Source Files\gui + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\gui + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\gui + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\gui + + + Source Files\core + + + Source Files\parallel + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\parallel + + + Source Files\gui + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\gui + + + Source Files\gui + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files\gui + + + + + Header Files\gui + + + Header Files\gui + + + Header Files\gui + + + Header Files\gui + + + Header Files\gui + + + Header Files\core + + + Header Files\gui + + + Header Files\gui + + + Header Files\parallel + + + Header Files\parallel + + + Header Files\gui + + + Header Files\gui + + + Header Files\gui + + + Header Files\gui + + + + + Header Files\core + + + Header Files\core + + + Header Files\core + + + Header Files\core + + + Header Files\core + + + Header Files\core + + + Header Files\core + + + Header Files\core + + + Header Files\core + + + Header Files\core + + + Header Files\core + + + \ No newline at end of file diff --git a/CycloBranch/CycloBranch.vcxproj.user b/CycloBranch/CycloBranch.vcxproj.user new file mode 100644 index 0000000..dfe0f79 --- /dev/null +++ b/CycloBranch/CycloBranch.vcxproj.user @@ -0,0 +1,25 @@ + + + + PATH=$(QTDIR)\bin%3b"$(QTDIR)\bin%3b$(PATH) + C:\Qt\5.1.1\msvc2012_64\ + + + PATH=$(QTDIR)\bin%3b"$(QTDIR)\bin%3b$(PATH) + C:\Qt\5.1.1\msvc2012_64\ + + + C:\Qt\5.1.1\msvc2012_64 + PATH=$(QTDIR)\bin%3b"$(QTDIR)\bin%3b$(PATH) + + + WindowsLocalDebugger + + + C:\Qt\5.1.1\msvc2012_64 + PATH=$(QTDIR)\bin%3b%PATH%%3b"$(PATH) + WindowsLocalDebugger + + + + \ No newline at end of file diff --git a/CycloBranch/core/cBrick.cpp b/CycloBranch/core/cBrick.cpp new file mode 100644 index 0000000..504e093 --- /dev/null +++ b/CycloBranch/core/cBrick.cpp @@ -0,0 +1,423 @@ +#include "core/cBrick.h" + + +int getNumberOfBricks(string& composition) { + if (composition.size() == 0) { + return 0; + } + + int count = 0; + for (int i = 0; i < (int)composition.size(); i++) { + if (composition[i] == '-') { + count++; + } + } + return ++count; +} + + +string stripHTML(string& htmlstring) { + string s; + bool add = true; + + for (int i = 0; i < (int)htmlstring.size(); i++) { + if (htmlstring[i] == '<') { + add = false; + continue; + } + if (htmlstring[i] == '>') { + add = true; + continue; + } + if (add) { + s += htmlstring[i]; + } + } + return s; +} + + +cBrick::cBrick() { + clear(); +} + + +void cBrick::clear() { + name = ""; + acronyms.clear(); + references.clear(); + summary = ""; + mass = 0; + composition = ""; + artificial = false; +} + + +bool cBrick::empty() { + if ((name.size() == 0) && (summary.size() == 0) && (mass == 0)) return true; + return false; +} + + +string& cBrick::getName() { + return name; +} + + +void cBrick::setName(string& name) { + this->name = name; +} + + +string& cBrick::getSummary() { + return summary; +} + + +vector& cBrick::getAcronyms() { + return acronyms; +} + + +vector& cBrick::getReferences() { + return references; +} + + +string& cBrick::getComposition() { + return composition; +} + + +string cBrick::getReverseComposition() { + string reversename = ""; + vector blocks; + explodeToStringComposition(blocks); + for (int i = 0; i < (int)blocks.size(); i++) { + reversename += blocks[(int)blocks.size() - i - 1]; + if (i < (int)blocks.size() - 1) { + reversename += '-'; + } + } + return reversename; +} + + +double cBrick::getMass() { + return mass; +} + + +void cBrick::setMass(double mass) { + this->mass = mass; +} + + +void cBrick::setComposition(string& composition, bool normalize) { + this->composition = composition; + if (normalize) { + normalizeComposition(); + } +} + + +void cBrick::setSummary(string& summary) { + this->summary = summary; +} + + +void cBrick::setAcronyms(string& acronyms) { + string s = ""; + int i = 0; + while (i < (int)acronyms.size()) { + if (acronyms[i] == '/') { + if (s.compare("") != 0) { + this->acronyms.push_back(s); + } + s = ""; + } + else { + s += acronyms[i]; + } + i++; + } + if (s.compare("") != 0) { + this->acronyms.push_back(s); + } +} + + +void cBrick::setReferences(string& references) { + string s = ""; + int i = 0; + while (i < (int)references.size()) { + if (references[i] == '/') { + if (s.compare("") != 0) { + this->references.push_back(s); + } + s = ""; + } + else { + s += references[i]; + } + i++; + } + if (s.compare("") != 0) { + this->references.push_back(s); + } +} + + +void cBrick::normalizeComposition() { + vector bricks; + explodeToIntComposition(bricks); + sort(bricks.begin(), bricks.end()); + + composition = ""; + for (int i = 0; i < (int)bricks.size(); i++) { + composition += to_string((long long)bricks[i]); + if (i < (int)bricks.size() - 1) { + composition += "-"; + } + } +} + + +void cBrick::explodeToIntComposition(vector& bricks) { + if (composition.compare("") == 0) { + return; + } + + bricks.clear(); + int item; + int first = 0; + int last = (int)composition.find('-'); + while (last != string::npos) { + item = atoi(composition.substr(first, last - first).c_str()); + bricks.push_back(item); + first = last+1; + last = (int)composition.find('-',first); + } + item = atoi(composition.substr(first).c_str()); + bricks.push_back(item); +} + + +void cBrick::explodeToStringComposition(vector& bricks) { + if (composition.compare("") == 0) { + return; + } + + bricks.clear(); + string item; + int first = 0; + int last = (int)composition.find('-'); + while (last != string::npos) { + item = composition.substr(first, last - first); + bricks.push_back(item); + first = last+1; + last = (int)composition.find('-',first); + } + item = composition.substr(first); + bricks.push_back(item); +} + + +string cBrick::getAcronymsAsString() { + string s = ""; + for (int i = 0; i < (int)acronyms.size(); i++) { + s += acronyms[i]; + if (i < (int)acronyms.size() - 1) { + s += "/"; + } + } + return s; +} + + +string cBrick::getFirstAcronymAsString() { + if (acronyms.size() == 0) { + return ""; + } + return acronyms[0]; +} + + +string cBrick::getAcronymsWithReferencesAsHTMLString() { + string s = ""; + regex rx; + bool correctreference; + + for (int i = 0; i < (int)acronyms.size(); i++) { + + correctreference = false; + + try { + + // ChemSpider + if (!correctreference) { + rx = "^CSID: [0-9]+$"; + if (regex_search(references[i], rx)) { + s += ""; + s += acronyms[i]; + s += ""; + correctreference = true; + } + } + + // PubChem + if (!correctreference) { + rx = "^CID: [0-9]+$"; + if (regex_search(references[i], rx)) { + s += ""; + s += acronyms[i]; + s += ""; + correctreference = true; + } + } + + // PDB + if (!correctreference) { + rx = "^PDB: [A-Z]+$"; + if (regex_search(references[i], rx)) { + s += ""; + s += acronyms[i]; + s += ""; + correctreference = true; + } + } + + // smiles in ChemSpider + if (!correctreference) { + rx = " in CSID: [0-9]+$"; + if (regex_search(references[i], rx)) { + s += ""; + s += acronyms[i]; + s += ""; + correctreference = true; + } + } + + // smiles in PubChem + if (!correctreference) { + rx = " in CID: [0-9]+$"; + if (regex_search(references[i], rx)) { + s += ""; + s += acronyms[i]; + s += ""; + correctreference = true; + } + } + + // smiles in Norine + if (!correctreference) { + rx = " in: NOR"; + if (regex_search(references[i], rx)) { + s += ""; + s += acronyms[i]; + s += ""; + correctreference = true; + } + } + + } + catch (std::regex_error& e) { + e; + // nothing to do + } + + if (!correctreference) { + s += acronyms[i]; + } + + if (i < (int)acronyms.size() - 1) { + s += "/"; + } + } + return s; +} + + +void cBrick::setArtificial(bool artificial) { + this->artificial = artificial; +} + + +bool cBrick::isArtificial() { + return artificial; +} + + +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()); + + os.write((char *)&mass, sizeof(double)); + + size = (int)composition.size(); + os.write((char *)&size, sizeof(int)); + os.write(composition.c_str(), composition.size()); + + 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()); + + is.read((char *)&mass, sizeof(double)); + + is.read((char *)&size, sizeof(int)); + composition.resize(size); + is.read(&composition[0], composition.size()); + + is.read((char *)&artificial, sizeof(bool)); +} + diff --git a/CycloBranch/core/cBrick.h b/CycloBranch/core/cBrick.h new file mode 100644 index 0000000..d586515 --- /dev/null +++ b/CycloBranch/core/cBrick.h @@ -0,0 +1,233 @@ +/** + \file cBrick.h + \brief The representation of a brick. +*/ + + +#ifndef _CBRICK_H +#define _CBRICK_H + +#include +#include +#include +#include +#include +#include + +using namespace std; + + +/** + \brief Get the number of bricks in a composition. + \param composition string containing ids of bricks separated by '-' + \retval number number of bricks +*/ +int getNumberOfBricks(string& composition); + + +/** + \brief Strip HTML tags from a HTML string. + \param htmlstring reference to a string with HTML tags + \retval string stripped string +*/ +string stripHTML(string& htmlstring); + + +/** + \brief The class representing a building block (brick). +*/ +class cBrick { + string name; + vector acronyms; + vector references; + string summary; + double mass; + string composition; + bool artificial; + +public: + + /** + \brief The constructor. + */ + cBrick(); + + + /** + \brief Clear all variables. + */ + void clear(); + + + /** + \brief Test whether the brick is empty. + \retval true if the brick is empty + */ + bool empty(); + + + /** + \brief Access to a string variable which stores a full name of the brick. + \retval reference to a string + */ + string& getName(); + + + /** + \brief Set a full name of the brick. + \param name reference to a string + */ + void setName(string& name); + + + /** + \brief Access to a string variable which stores a summary molecular formula of the brick. + \retval reference to a string + */ + string& getSummary(); + + + /** + \brief Access to a vector of strings which stores acronyms of all izomers corresponding to the brick. + \retval reference to a vector of strings + */ + vector& getAcronyms(); + + + /** + \brief Access to a vector of strings which stores references (e.g., to ChemSpider) of all izomers corresponding to the brick. + \retval reference to a vector of strings + */ + vector& getReferences(); + + + /** + \brief Access to a string containing composition of the brick (ids of bricks separated by '-') + \retval reference to a string + */ + string& getComposition(); + + + /** + \brief Reverse the composition of the brick. + \retval string with reverted composition of bricks (ids of bricks separated by '-') + */ + string getReverseComposition(); + + + /** + \brief Get the mass of the brick. + \retval double mass + */ + double getMass(); + + + /** + \brief Set the mass of the brick. + \param mass mass of the brick + */ + void setMass(double mass); + + + /** + \brief Set the composition of the brick. + \param composition reference to a string with composition (ids of bricks separated by '-') + \param normalize if true then ids of bricks are sorted in ascending order + */ + void setComposition(string& composition, bool normalize); + + + /** + \brief Set the summary molecular formula of the brick. + \param summary reference to a string + */ + void setSummary(string& summary); + + + /** + \brief Set acronyms of all izomers corresponding to the brick. + \param acronyms reference to a string where the acronyms are separated by '/' + */ + void setAcronyms(string& acronyms); + + + /** + \brief Set references (e.g., to ChemSpider) of all izomers corresponding to the brick. + \param references reference to a string where references to izomers are separated by '/' + */ + void setReferences(string& references); + + + /** + \brief Normalize the composition of the brick (ids of bricks are sorted in ascending order). + */ + void normalizeComposition(); + + + /** + \brief Explode the composition of the brick into a vector of intergers (ids of subbricks). + \param bricks reference to a vector of integers + */ + void explodeToIntComposition(vector& bricks); + + + /** + \brief Explode the composition of the brick into a vector of strings (ids of subbricks). + \param bricks reference to a vector of strings + */ + void explodeToStringComposition(vector& bricks); + + + /** + \brief Get all acronyms. + \retval string acronyms of all izomers separated by '/' + */ + string getAcronymsAsString(); + + + /** + \brief Get the first acronym. + \retval string acronym of the first izomer + */ + string getFirstAcronymAsString(); + + + /** + \brief Get all acronyms with HTML links to theirs references. + \retval string acronyms of all izomers with HTML references separated by '/' + */ + string getAcronymsWithReferencesAsHTMLString(); + + + /** + \brief Set a flag determining whether the brick is a calculated mass block or a regular brick. + \param artificial true when the brick is a calculated mass block; false when the brick is a regular brick. + */ + void setArtificial(bool artificial); + + + /** + \brief Get a flag determining whether the brick is a calculated mass block or a regular brick. + \retval bool true when the brick is a calculated mass block; false when the brick is a regular brick. + */ + bool isArtificial(); + + + /** + \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 + diff --git a/CycloBranch/core/cBricksDatabase.cpp b/CycloBranch/core/cBricksDatabase.cpp new file mode 100644 index 0000000..9236a5b --- /dev/null +++ b/CycloBranch/core/cBricksDatabase.cpp @@ -0,0 +1,499 @@ +#include "core/cBricksDatabase.h" + + +#include "gui/cMainThread.h" + + +bool compareBrickMasses(cBrick& a, cBrick& b) { + return (a.getMass() < b.getMass()); +} + + +void getNameOfCompositionFromIntVector(string& composition, vector& combarray) { + composition = ""; + for (int i = 0; i < (int)combarray.size(); i++) { + if (combarray[i] > 0) { + composition += to_string(combarray[i]); + } + if ((i < (int)combarray.size() - 1) && (combarray[i + 1] > 0)) { + composition += "-"; + } + } +} + + +string& getReversedNameOfCompositionFromStringVector(string& composition, vector& stringcomposition) { + composition = ""; + for (int i = (int)stringcomposition.size() - 1; i >= 0; i--) { + composition += stringcomposition[i]; + if (i > 0) { + composition += "-"; + } + } + return composition; +} + + +void generateBricksPermutations(vector& bricks, vector& currentpermutation, vector& permutations) { + if (bricks.size() == 0) { + string s = ""; + for (int i = 0; i < (int)currentpermutation.size(); i++) { + s += currentpermutation[i]; + if (i < (int)currentpermutation.size() - 1) { + s += "-"; + } + } + permutations.push_back(s); + } + else { + for (int i = 0; i < (int)bricks.size(); i++) { + currentpermutation.push_back(bricks[i]); + vector subbricks = bricks; + subbricks.erase(subbricks.begin() + i); + generateBricksPermutations(subbricks, currentpermutation, permutations); + currentpermutation.pop_back(); + } + } +} + + +bool cBricksDatabase::nextCombination(vector& combarray, int numberofbasicbricks, int maximumbricksincombination, double maximumcumulativemass) { + int pointer = 0; + int cyFlag = 0; + do { + combarray[pointer]++; + + // set combarray[pointer] to the maximum value when outside of the mass range + if ((cyFlag == 0) && (combarray[pointer] <= numberofbasicbricks) && (maximumcumulativemass > 0) && (getMassOfComposition(combarray, maximumbricksincombination) > maximumcumulativemass)) { + combarray[pointer] = numberofbasicbricks + 1; + } + + if (combarray[pointer] <= numberofbasicbricks) { + + if (cyFlag > 0) { + + for (int i = pointer - 1; i >= 0; i--) { + combarray[i] = combarray[pointer]; + } + + // skip combinations outside of the mass range + while ((combarray[pointer] <= numberofbasicbricks) && (pointer < maximumbricksincombination - 1) && (maximumcumulativemass > 0) && (getMassOfComposition(combarray, maximumbricksincombination) > maximumcumulativemass)) { + pointer++; + combarray[pointer]++; + + for (int i = pointer - 1; i >= 0; i--) { + combarray[i] = combarray[pointer]; + } + } + + if ((combarray[pointer] > numberofbasicbricks) || ((maximumcumulativemass > 0) && (getMassOfComposition(combarray, maximumbricksincombination) > maximumcumulativemass))) { + return false; + } + + } + + return true; + } + else { + cyFlag = 1; + pointer++; + } + } while (pointer < maximumbricksincombination); + + return false; +} + + +cBricksDatabase::cBricksDatabase() { + bricks.clear(); +} + + +int cBricksDatabase::loadFromPlainTextStream(ifstream &stream, string& errormessage) { + string s; + cBrick b; + size_t pos; + double mass; + + bool error = false; + errormessage = ""; + + while (stream.good()) { + getline(stream,s); + + // skip a comment + if ((s.length() > 0) && (s[0] == '#')) { + continue; + } + + // replaces commas with dots + pos = s.find(','); + while (pos != string::npos) { + s.replace(pos, 1, "."); + pos = s.find(','); + } + + b.clear(); + + // load the name + pos = s.find('\t'); + if (pos != string::npos) { + b.setName(s.substr(0, pos)); + s = s.substr(pos + 1); + } + else { + break; + } + + // load acronyms + pos = s.find('\t'); + if (pos != string::npos) { + b.setAcronyms(s.substr(0, pos)); + s = s.substr(pos + 1); + } + else { + break; + } + + // load summary + pos = s.find('\t'); + if (pos != string::npos) { + b.setSummary(s.substr(0, pos)); + s = s.substr(pos + 1); + } + else { + break; + } + + // load the mass (unused !) + pos = s.find('\t'); + if (pos != string::npos) { + sscanf_s(s.substr(0, pos).c_str(), "%lf", &mass); + s = s.substr(pos + 1); + } + else { + break; + } + + // load references + b.setReferences(s); + + // store brick + if (!b.empty()) { + + // calculate mass from the summary + b.setMass(getMassFromResidueSummary(b.getSummary(), error, errormessage)); + + if (error) { + break; + } + + if (b.getMass() == 0) { + error = true; + errormessage = "Invalid brick no. " + to_string(size() + 1) + ".\n\n"; + break; + } + + bricks.push_back(b); + //cout << b.getSummary() << " " << b.getMass() << endl; + } + } + + if (error) { + return -1; + } + + sortbyMass(); + + return 0; +} + + +int cBricksDatabase::size() { + return (int)bricks.size(); +} + + +void cBricksDatabase::print(/*ostream &stream*/) { + for (int i = 0; i < size(); i++) { + printf("%i %s %lf\n", i + 1, bricks[i].getAcronymsAsString().c_str(), bricks[i].getMass()); + } +} + + +void cBricksDatabase::sortbyMass() { + sort(bricks.begin(), bricks.end(), compareBrickMasses); +} + + +cBrick& cBricksDatabase::operator[](int position) { + return bricks[position]; +} + + +double cBricksDatabase::getMassOfComposition(vector& combarray, int maximumbricksincombination) { + double mass = 0; + for (int i = 0; i < maximumbricksincombination; i++) { + if (combarray[i] > 0) { + mass += bricks[combarray[i] - 1].getMass(); + } + } + return mass; +} + + +string cBricksDatabase::getRealName(string& composition) { + cBrick b; + b.setComposition(composition, false); + + vector items; + b.explodeToIntComposition(items); + + string s = ""; + for (int i = 0; i < (int)items.size(); i++) { + s += "[" + bricks[items[i]-1].getName() + "]"; + if (i < (int)items.size() - 1) { + s += "-"; + } + } + + return s; +} + + +string cBricksDatabase::getAcronymName(string& composition, bool useHTMLReferences) { + cBrick b; + b.setComposition(composition, false); + + vector items; + b.explodeToIntComposition(items); + + string s = ""; + for (int i = 0; i < (int)items.size(); i++) { + s += "["; + if (useHTMLReferences) { + s += bricks[items[i]-1].getAcronymsWithReferencesAsHTMLString(); + } + else { + s += bricks[items[i]-1].getAcronymsAsString(); + } + s += "]"; + if (i < (int)items.size() - 1) { + s += "-"; + } + } + + return s; +} + + +string cBricksDatabase::getTagName(string& composition) { + cBrick b; + b.setComposition(composition, false); + + vector items; + b.explodeToIntComposition(items); + + string s = ""; + for (int i = 0; i < (int)items.size(); i++) { + s += "["; + s += bricks[items[i]-1].getFirstAcronymAsString(); + s += "]"; + if (i < (int)items.size() - 1) { + s += "-"; + } + } + + return s; +} + + +string cBricksDatabase::getAcronymNameOfTPeptide(string& tcomposition, bool useHTMLReferences) { + string comp = tcomposition; + + int leftbracket = getNumberOfBricks(comp.substr(0, comp.find('('))); + comp[comp.find('(')] = '-'; + + if (comp[0] == '-') { + comp.erase(comp.begin()); + } + + int rightbracket = getNumberOfBricks(comp.substr(0, comp.find(')'))) - 1; + comp[comp.find(')')] = '-'; + + if (comp.back() == '-') { + comp.erase(comp.end() - 1); + } + + cBrick b; + b.setComposition(comp, false); + + vector items; + b.explodeToIntComposition(items); + + string s = ""; + for (int i = 0; i < (int)items.size(); i++) { + + if (i == leftbracket) { + if (leftbracket > 0) { + s += " "; + } + s += "( "; + } + + s += "["; + if (useHTMLReferences) { + s += bricks[items[i]-1].getAcronymsWithReferencesAsHTMLString(); + } + else { + s += bricks[items[i]-1].getAcronymsAsString(); + } + s += "]"; + + if (i == rightbracket) { + s += " ) "; + } + else { + if ((i < (int)items.size() - 1) && (leftbracket != i + 1)) { + s += "-"; + } + } + + } + + return s; +} + + +string cBricksDatabase::getTagNameOfTPeptide(string& tcomposition) { + string comp = tcomposition; + int leftbracket = getNumberOfBricks(comp.substr(0, comp.find('('))); + comp[comp.find('(')] = '-'; + int rightbracket = getNumberOfBricks(comp.substr(0, comp.find(')'))); + comp[comp.find(')')] = '-'; + + cBrick b; + b.setComposition(comp, false); + + vector items; + b.explodeToIntComposition(items); + + string s = ""; + for (int i = 0; i < (int)items.size(); i++) { + s += "["; + s += bricks[items[i]-1].getFirstAcronymAsString(); + s += "]"; + if (i < (int)items.size() - 1) { + if (i == leftbracket - 1) { + s += "\\("; + } + else if (i == rightbracket - 1) { + s += "\\)"; + } + else { + s += "-"; + } + } + } + + return s; +} + + +void cBricksDatabase::clear() { + bricks.clear(); +} + + +bool cBricksDatabase::replaceAcronymsByIDs(string& sequence) { + string s = ""; + string acronym; + bool insidebrick = false; + bool found = false; + //regex rx; + //rx = "^\\d*\\.?\\d*$"; + + for (int i = 0; i < (int)sequence.size(); i++) { + if (sequence[i] == '[') { + acronym = ""; + insidebrick = true; + continue; + } + + if (sequence[i] == ']') { + found = false; + for (int j = 0; j < (int)bricks.size(); j++) { + for (int k = 0; k < (int)bricks[j].getAcronyms().size(); k++) { + if (acronym.compare(bricks[j].getAcronyms()[k]) == 0) { + s += to_string(j + 1); + found = true; + break; + } + } + if (found) { + break; + } + } + + // valinomycin oznaci i neco navic pri connect a 1,1,1 + //if (!found) { + // if (regex_search(acronym, rx)) { + // found = true; + // } + //} + + if (!found) { + return false; + } + + insidebrick = false; + continue; + } + + if (insidebrick) { + acronym += sequence[i]; + } + else { + s += sequence[i]; + } + } + + sequence = s; + + return true; +} + + +void cBricksDatabase::push_back(cBrick& brick) { + bricks.push_back(brick); +} + + +void cBricksDatabase::removeLastBrick() { + bricks.pop_back(); +} + + +void cBricksDatabase::store(ofstream& os) { + int size; + + size = (int)bricks.size(); + os.write((char *)&size, sizeof(int)); + + for (int i = 0; i < (int)bricks.size(); i++) { + bricks[i].store(os); + } +} + + +void cBricksDatabase::load(ifstream& is) { + int size; + + is.read((char *)&size, sizeof(int)); + bricks.resize(size); + + for (int i = 0; i < (int)bricks.size(); i++) { + bricks[i].load(is); + } +} + diff --git a/CycloBranch/core/cBricksDatabase.h b/CycloBranch/core/cBricksDatabase.h new file mode 100644 index 0000000..969c17b --- /dev/null +++ b/CycloBranch/core/cBricksDatabase.h @@ -0,0 +1,217 @@ +/** + \file cBricksDatabase.h + \brief The representation of a database of bricks. +*/ + + +#ifndef _CBRICKSDATABASE_H +#define _CBRICKSDATABASE_H + +#include +#include +#include +#include +#include + + +#include "core/cBrick.h" + + +using namespace std; + + +class cMainThread; + + +/** + \brief Compare masses of two bricks. + \param a first brick + \param b second brick + \retval bool true if the mass of \a a is less than the mass of \a b +*/ +bool compareBrickMasses(cBrick& a, cBrick& b); + + +/** + \brief Convert vector of ids of bricks into a string. + \param composition reference to a string where ids of bricks separated by '-' will be stored + \param combarray reference to an input integer vector of ids of bricks +*/ +void getNameOfCompositionFromIntVector(string& composition, vector& combarray); + + +/** + \brief Convert vector of ids of bricks into a string having reversed ids of bricks. + \param composition reference to a string where ids of bricks separated by '-' will be stored + \param stringcomposition reference to an input string vector of ids of bricks + \retval string reference to a string where ids of bricks separated by '-' will be stored +*/ +string& getReversedNameOfCompositionFromStringVector(string& composition, vector& stringcomposition); + + +/** + \brief Generate permutations of bricks. + \param bricks reference to an input vector of strings (ids of bricks) + \param currentpermutation reference to an empty vector of strings (auxiliary parameter) + \param permutations reference to an empty output vector of strings where the result will be stored +*/ +void generateBricksPermutations(vector& bricks, vector& currentpermutation, vector& permutations); + + +/** + \brief The class representing a database of building blocks (bricks). +*/ +class cBricksDatabase { + + vector bricks; + +public: + + /** + \brief Get next combination of bricks. + \param combarray reference to an input/output vector of integers + \param numberofbasicbricks initial number of bricks in a database + \param maximumbricksincombination maximum number of combined bricks + \param maximumcumulativemass maximum cummulative mass of combined bricks + \retval bool true when a valid vector is stored in combarray, false when all valid vectors were already generated + */ + bool nextCombination(vector& combarray, int numberofbasicbricks, int maximumbricksincombination, double maximumcumulativemass); + + + /** + \brief The constructor. + */ + cBricksDatabase(); + + + /** + \brief Load the database of bricks from a plain text stream. + \param stream reference to an input file stream + \param errormessage reference to a string where an error message might be stored + \retval int 0 when the database was successfully loaded, -1 when an error occurred (\a errormessage is filled up) + */ + int loadFromPlainTextStream(ifstream &stream, string& errormessage); + + + /** + \brief Get the number of bricks in the database. + \retval int number of bricks + */ + int size(); + + + /** + \brief Print the database of bricks. + */ + void print(/*ostream &stream*/); + + + /** + \brief Sort the database of bricks by mass in ascending order. + */ + void sortbyMass(); + + + /** + \brief Overloaded operator []. + \param position of the brick in the vector of bricks + \retval cBrick reference to a brick + */ + cBrick& operator[](int position); + + + /** + \brief Get the mass of a composition of bricks. + \param combarray reference to an input integer vector of ids + \param maximumbricksincombination maximum number of bricks in a combination + \retval double cumulative mass of the bricks in the \a combarray + */ + double getMassOfComposition(vector& combarray, int maximumbricksincombination); + + + /** + \brief Get the real name of a peptide from a composition. + \param composition reference to a string containing ids of bricks separated by '-' + \retval string name of the peptide + */ + string getRealName(string& composition); + + + /** + \brief Get the name of a peptide composed from acronyms of bricks. + \param composition reference to a string containing ids of bricks separated by '-' + \param useHTMLReferences if true then each acronym is converted to a link to its reference (e.g., in ChemSpider) + \retval string name of the peptide + */ + string getAcronymName(string& composition, bool useHTMLReferences); + + + /** + \brief Get a peptide sequence tag from a composition. + \param composition reference to a string containing ids of bricks separated by '-' + \retval string sequence tag + */ + string getTagName(string& composition); + + + /** + \brief Get the name of a branched peptide composed from acronyms of bricks. + \param tcomposition reference to a string containing ids of bricks separated by '-', the branch is specified by '(' and ')'; example: 1-2-3(4-5)6-7 + \param useHTMLReferences if true then each acronym is converted to a link to its reference (e.g., in ChemSpider) + \retval string name of the peptide + */ + string getAcronymNameOfTPeptide(string& tcomposition, bool useHTMLReferences); + + + /** + \brief Get a peptide sequence tag of a branched peptide from a composition. + \param tcomposition reference to a string containing ids of bricks separated by '-', the branch is specified by '(' and ')'; example: 1-2-3(4-5)6-7 + \retval string sequence tag + */ + string getTagNameOfTPeptide(string& tcomposition); + + + /** + \brief Clear the vector of bricks. + */ + void clear(); + + + /** + \brief Replace acronyms of bricks by ids. + \param sequence reference to an input/output string containing acronyms/ids of bricks + \retval bool true when the replacement was successful, false when an acronym of a brick is unknown + */ + bool replaceAcronymsByIDs(string& sequence); + + + /** + \brief Push a new brick into the vector of bricks. + \param brick an inserted brick + */ + void push_back(cBrick& brick); + + + /** + \brief Remove the last brick from the vector of bricks if possible. + */ + void removeLastBrick(); + + + /** + \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/cCandidate.cpp b/CycloBranch/core/cCandidate.cpp new file mode 100644 index 0000000..7c87673 --- /dev/null +++ b/CycloBranch/core/cCandidate.cpp @@ -0,0 +1,973 @@ +#include "core/cCandidate.h" + +#include "core/cCandidateSet.h" + + +void cCandidate::updateInternalComposition() { + internalcomposition = ""; + for (int i = 0; i < (int)composition.size(); i++) { + internalcomposition += composition[i]; + if (i < (int)composition.size() - 1) { + internalcomposition += "-"; + } + } + + numberofinternalbricks = getNumberOfBricks(internalcomposition); +} + + +void cCandidate::getPermutationsIter(cCandidateSet& permutations, vector& currentcandidate, int position, bool* terminatecomputation) { + if (*terminatecomputation) { + return; + } + + vector bricks, currentpermutation; + vector localpermutations; + + bricks.clear(); + localpermutations.clear(); + + if (position < (int)composition.size()) { + cBrick b; + b.setComposition(composition[position], false); + b.explodeToStringComposition(bricks); + generateBricksPermutations(bricks, currentpermutation, localpermutations); + + for (int k = 0; k < (int)localpermutations.size(); k++) { + currentcandidate.push_back(localpermutations[k]); + getPermutationsIter(permutations, currentcandidate, position + 1, terminatecomputation); + currentcandidate.pop_back(); + } + } + else { + cCandidate c(currentcandidate, path, startmodifID, endmodifID, middlemodifID, branchstart, branchend); + permutations.getSet().insert(c); + } +} + + +void cCandidate::attachSubBranchCandidates(cCandidate& candidate, cCandidateSet& result, peptideType peptidetype, bool* terminatecomputation) { + if (*terminatecomputation) { + return; + } + + int start = candidate.branchstart; + int end = candidate.branchend; + + if (peptidetype == branched) { + if (start == 0) { + start = 1; + } + + if (end == candidate.numberofinternalbricks - 1) { + end--; + } + } + + if (end <= start) { + return; + } + + cCandidate c; + for (int i = start; i <= end; i++) { + for (int j = i + 1; j <= end; j++) { + c = candidate; + c.branchstart = i; + c.branchend = j; + result.getSet().insert(c); + } + } +} + + +void cCandidate::attachAllBranches(cCandidate& candidate, cCandidateSet& result, peptideType peptidetype, bool* terminatecomputation) { + cCandidate c; + int start, end; + int cumsize = 0; + for (int i = 0; i < (int)candidate.composition.size(); i++) { + start = cumsize; + cumsize += getNumberOfBricks(candidate.composition[i]); + end = cumsize - 1; + c = candidate; + c.branchstart = start; + c.branchend = end; + attachSubBranchCandidates(c, result, peptidetype, terminatecomputation); + } +} + + +void cCandidate::getPartialRotations(string& composition, vector& rotations) { + cBrick b; + string s; + vector bricks; + b.setComposition(composition, false); + b.explodeToStringComposition(bricks); + + int count = (int)bricks.size(); + for (int i = 0; i < count; i++) { + s = ""; + for (int j = 0; j < count; j++) { + s += bricks[(i + j) % count]; + if (j < count - 1) { + s += "-"; + } + } + rotations.push_back(s); + //cout << s << endl; + } + + /* + int position; + int count = getNumberOfBricks(rotation); + for (int i = 0; i < count - 1; i++) { + position = (int)rotation.find('-'); + if (position == string::npos) { + cout << "Sequence cannot be rotated." << endl; + exit(1); + } + else { + rotation = rotation.substr(position + 1) + "-" + rotation.substr(0, position); + rotations.push_back(rotation); + } + } + */ +} + + +void cCandidate::getPartialLassoRotations(string& composition, vector& lassorotations, int branchstart, int branchend) { + cBrick b; + string s; + bool leftbracketput; + vector bricks; + b.setComposition(composition, false); + b.explodeToStringComposition(bricks); + int count = (int)bricks.size(); + for (int i = 0; i < count; i++) { + s = ""; + leftbracketput = false; + for (int j = 0; j < count; j++) { + if (branchstart == (i + j) % count) { + //s += "("; + if (j > 0) { + s += "-"; + } + leftbracketput = true; + } + s += bricks[(i + j) % count]; + if (branchend == (i + j) % count) { + if (!leftbracketput) { + break; + } + //s += ")"; + if (j < count - 1) { + s += "-"; + } + } + else { + if ((j < count - 1) && (branchstart != (i + j + 1) % count)) { + s += "-"; + } + } + } + + if (leftbracketput) { + vector v; + vector ne; + v.push_back(s); + cCandidate c(v, ne, startmodifID, endmodifID, middlemodifID, (branchstart + count - i) % count, (branchend + count - i) % count); + lassorotations.push_back(c); + //cout << s << endl; + } + } +} + + +cCandidate::cCandidate() { + clear(); +} + + +cCandidate::cCandidate(vector& composition, vector& path, int startmodifID, int endmodifID, int middlemodifID, int middlepos) { + setCandidate(composition, path, startmodifID, endmodifID, middlemodifID, middlepos); +} + + +cCandidate::cCandidate(vector& composition, vector& path, int startmodifID, int endmodifID, int middlemodifID, int branchstart, int branchend) { + setCandidate(composition, path, startmodifID, endmodifID, middlemodifID, branchstart, branchend); +} + + +void cCandidate::setCandidate(vector& composition, vector& path, int startmodifID, int endmodifID, int middlemodifID, int middlepos) { + this->composition = composition; + updateInternalComposition(); + + this->startmodifID = startmodifID; + this->endmodifID = endmodifID; + this->middlemodifID = middlemodifID; + this->path = path; + + if (middlepos == -1) { + middlemodifID = 0; + branchstart = -1; + branchend = -1; + return; + } + + branchstart = 0; + for (int i = 0; i < middlepos; i++) { + branchstart += getNumberOfBricks(composition[i]); + } + branchend = branchstart + getNumberOfBricks(composition[middlepos]) - 1; +} + + +void cCandidate::setCandidate(vector& composition, vector& path, int startmodifID, int endmodifID, int middlemodifID, int branchstart, int branchend) { + this->composition = composition; + updateInternalComposition(); + + this->startmodifID = startmodifID; + this->endmodifID = endmodifID; + this->middlemodifID = middlemodifID; + this->branchstart = branchstart; + this->branchend = branchend; + this->path = path; +} + + +void cCandidate::clear() { + composition.clear(); + internalcomposition = ""; + numberofinternalbricks = 0; + startmodifID = 0; + endmodifID = 0; + middlemodifID = 0; + branchstart = -1; + branchend = -1; + path.clear(); +} + + +string& cCandidate::getComposition() { + return internalcomposition; +} + + +void cCandidate::revertComposition() { + cBrick b1, b2; + int temp; + + for(int i = 0; i < (int)composition.size() / 2; i++) { + b1.setComposition(composition[i], false); + b2.setComposition(composition[(int)composition.size()-i-1], false); + composition[i] = b2.getReverseComposition(); + composition[(int)composition.size()-i-1] = b1.getReverseComposition(); + } + + if ((int)composition.size() % 2 == 1) { + b1.setComposition(composition[(int)composition.size() / 2], false); + composition[(int)composition.size() / 2] = b1.getReverseComposition(); + } + + updateInternalComposition(); + + temp = startmodifID; + startmodifID = endmodifID; + endmodifID = temp; + + if ((branchstart != -1) && (branchend != -1)) { + temp = numberofinternalbricks - branchstart - 1; + branchstart = numberofinternalbricks - branchend - 1; + branchend = temp; + } + +} + + +void cCandidate::prepareBranchedCandidate(cCandidateSet& result, peptideType peptidetype, bool* terminatecomputation) { + cCandidate c; + result.getSet().clear(); + + // branching is unknown + if ((branchstart == -1) && (branchend == -1)) { + attachAllBranches(*this, result, peptidetype, terminatecomputation); + } + // branching is determined by a modification of the T-branch + else { + attachSubBranchCandidates(*this, result, peptidetype, terminatecomputation); + } + + if (peptidetype == branched) { + + // below, middlemodifID is always > 0 because branchstart == 0 (or branchend == 0) + + // startmodifID and middlemodifID collide on the first detected combination of bricks + if (branchstart == 0) { + if (startmodifID > 0) { + c = *this; + c.startmodifID = middlemodifID; + c.middlemodifID = startmodifID; + attachSubBranchCandidates(c, result, peptidetype, terminatecomputation); + } + else { + c = *this; + c.startmodifID = middlemodifID; + c.middlemodifID = 0; + c.branchstart = -1; + c.branchend = -1; + attachAllBranches(c, result, peptidetype, terminatecomputation); + } + } + + // endmodifID and middlemodifID collide on the last detected combination of bricks + if (branchend == numberofinternalbricks - 1) { + if (endmodifID > 0) { + c = *this; + c.endmodifID = middlemodifID; + c.middlemodifID = endmodifID; + attachSubBranchCandidates(c, result, peptidetype, terminatecomputation); + } + else { + c = *this; + c.endmodifID = middlemodifID; + c.middlemodifID = 0; + c.branchstart = -1; + c.branchend = -1; + attachAllBranches(c, result, peptidetype, terminatecomputation); + } + } + + } + +} + + +string cCandidate::getTComposition() { + vector brickscomposition; + cBrick b; + string s = ""; + + b.clear(); + b.setComposition(internalcomposition, false); + b.explodeToStringComposition(brickscomposition); + for (int i = 0; i < (int)brickscomposition.size(); i++) { + if (branchstart == i) { + s += "("; + } + s += brickscomposition[i]; + if (branchend == i) { + s += ")"; + } + else { + if ((i < (int)brickscomposition.size() - 1) && (branchstart != i + 1)) { + s += "-"; + } + } + } + return s; +} + + +string cCandidate::getRevertedTComposition(bool usebrackets) { + cBrick b, b2; + vector brickscomposition; + b.setComposition(internalcomposition, false); + b2.setComposition(b.getReverseComposition(), false); + b2.explodeToStringComposition(brickscomposition); + + int bstart = numberofinternalbricks - branchend - 1; + int bend = numberofinternalbricks - branchstart - 1; + + string s = ""; + for (int i = 0; i < (int)brickscomposition.size(); i++) { + if (bstart == i) { + s += "("; + } + s += brickscomposition[i]; + if (bend == i) { + s += ")"; + } + else { + if ((i < (int)brickscomposition.size() - 1) && (bstart != i + 1)) { + s += "-"; + } + } + } + + int p11 = (int)s.find('('); + int p12 = (int)s.find(')') - p11 + 1; + string t = getTComposition(); + int p21 = (int)t.find('('); + int p22 = (int)t.find(')') - p21 + 1; + s.replace(p11, p12, t, p21, p22); + + if (!usebrackets) { + s[s.find('(')] = '-'; + s[s.find(')')] = '-'; + + if (s[0] == '-') { + s.erase(s.begin()); + } + + if (s[s.size() - 1] == '-') { + s.erase(s.end() - 1); + } + } + + return s; +} + + +string cCandidate::getAcronymsTComposition(cBricksDatabase& brickdatabase) { + vector brickscomposition; + cBrick b; + string s = ""; + + b.clear(); + b.setComposition(internalcomposition, false); + b.explodeToStringComposition(brickscomposition); + for (int i = 0; i < (int)brickscomposition.size(); i++) { + if (branchstart == i) { + s += " ( "; + } + s += brickdatabase.getAcronymName(brickscomposition[i], true); + if (branchend == i) { + s += " ) "; + } + else { + if ((i < (int)brickscomposition.size() - 1) && (branchstart != i + 1)) { + s += "-"; + } + } + } + return s; +} + + +string cCandidate::getRealNameTComposition(cBricksDatabase& brickdatabase) { + vector brickscomposition; + cBrick b; + string s = ""; + + b.clear(); + b.setComposition(internalcomposition, false); + b.explodeToStringComposition(brickscomposition); + for (int i = 0; i < (int)brickscomposition.size(); i++) { + if (branchstart == i) { + s += " ( "; + } + s += brickdatabase.getRealName(brickscomposition[i]); + if (branchend == i) { + s += " ) "; + } + else { + if ((i < (int)brickscomposition.size() - 1) && (branchstart != i + 1)) { + s += "-"; + } + } + } + return s; +} + + +int cCandidate::getBranchSize() { + if ((branchstart >= 0) && (branchend >= 0)) { + return branchend-branchstart; + } + return 0; +} + + +int cCandidate::getBranchStart() { + return branchstart; +} + + +int cCandidate::getBranchEnd() { + return branchend; +} + + +void cCandidate::getBackboneAcronyms(cBricksDatabase& bricksdatabase, vector& acronyms) { + vector bricks; + cBrick b; + b.clear(); + b.setComposition(getComposition(), false); + b.explodeToIntComposition(bricks); + + acronyms.clear(); + for (int i = 0; i < (int)bricks.size(); i++) { + if ((branchstart >= 0) && (branchend >= 0) && ((i <= branchstart) || (i > branchend))) { + acronyms.push_back(bricksdatabase[bricks[i] - 1].getAcronymsAsString()); + } + } +} + + +void cCandidate::getBranchAcronyms(cBricksDatabase& bricksdatabase, vector& acronyms) { + vector bricks; + cBrick b; + b.clear(); + b.setComposition(getComposition(), false); + b.explodeToIntComposition(bricks); + + acronyms.clear(); + for (int i = 0; i < (int)bricks.size(); i++) { + if ((branchstart >= 0) && (branchend >= 0) && (i > branchstart) && (i <= branchend)) { + acronyms.push_back(bricksdatabase[bricks[i] - 1].getAcronymsAsString()); + } + } +} + + +void cCandidate::getPermutationsOfBranches(vector& tpermutations) { + tpermutations.resize(6); + for (int i = 0; i < (int)tpermutations.size(); i++) { + tpermutations[i].clear(); + } + + vector defaultintcomposition, intcomposition, tempintvector; + cBrick b; + b.clear(); + b.setComposition(internalcomposition, false); + defaultintcomposition.clear(); + b.explodeToIntComposition(defaultintcomposition); + + // 0 = n-terminal + tpermutations[0].id = 0; + tpermutations[0].bricks = defaultintcomposition; + tpermutations[0].startmodifID = startmodifID; + tpermutations[0].endmodifID = endmodifID; + tpermutations[0].middlemodifID = middlemodifID; + tpermutations[0].tcomposition = getTComposition(); + tpermutations[0].middlebranchstart = branchstart; + tpermutations[0].middlebranchend = branchend; + + + // first and second branch - revert order and switch + intcomposition.clear(); + tpermutations[1].tcomposition = ""; + + // push reverted second branch into intcomposition + for (int i = branchend; i >= branchstart; i--) { + intcomposition.push_back(defaultintcomposition[i]); + + if (i == branchstart) { + if (tpermutations[1].tcomposition.size() > 0) { + tpermutations[1].tcomposition.back() = '('; + } + else { + tpermutations[1].tcomposition += '('; + } + } + + tpermutations[1].tcomposition += to_string(defaultintcomposition[i]) + "-"; + } + tpermutations[1].middlebranchstart = (int)intcomposition.size() - 1; + + // push reverted first branch into intcomposition + for (int i = branchstart - 1; i >= 0; i--) { + intcomposition.push_back(defaultintcomposition[i]); + tpermutations[1].tcomposition += to_string(defaultintcomposition[i]) + "-"; + } + tpermutations[1].middlebranchend = (int)intcomposition.size() - 1; + tpermutations[1].tcomposition.back() = ')'; + + // push third branch into intcomposition + for (int i = branchend + 1; i < (int)defaultintcomposition.size(); i++) { + intcomposition.push_back(defaultintcomposition[i]); + tpermutations[1].tcomposition += to_string(defaultintcomposition[i]) + "-"; + } + + // 1 = middle modification type dependent + tpermutations[1].id = 1; + tpermutations[1].bricks = intcomposition; + tpermutations[1].startmodifID = middlemodifID; + tpermutations[1].endmodifID = endmodifID; + tpermutations[1].middlemodifID = startmodifID; + if (tpermutations[1].tcomposition.back() != ')') { + tpermutations[1].tcomposition = tpermutations[1].tcomposition.substr(0,tpermutations[1].tcomposition.size() - 1); + } + + + // first and third branch - revert order and switch + intcomposition.clear(); + tpermutations[2].tcomposition = ""; + int interpos = 0; + + for (int i = (int)defaultintcomposition.size() - 1; i >= 0; i--) { + + if (i == branchend) { + if (tpermutations[2].tcomposition.size() > 0) { + tpermutations[2].tcomposition.back() = '('; + } + else { + tpermutations[2].tcomposition += '('; + } + tpermutations[2].middlebranchstart = (int)intcomposition.size(); + } + + if ((i >= branchstart) && (i <= branchend)) { + intcomposition.push_back(defaultintcomposition[branchstart+interpos]); + tpermutations[2].tcomposition += to_string(defaultintcomposition[branchstart+interpos]) + "-"; + interpos++; + } + else { + intcomposition.push_back(defaultintcomposition[i]); + tpermutations[2].tcomposition += to_string(defaultintcomposition[i]) + "-"; + } + + if (i == branchstart) { + tpermutations[2].middlebranchend = (int)intcomposition.size() - 1; + tpermutations[2].tcomposition.back() = ')'; + } + + } + + // 2 = c-terminal + tpermutations[2].id = 2; + tpermutations[2].bricks = intcomposition; + tpermutations[2].startmodifID = endmodifID; + tpermutations[2].endmodifID = startmodifID; + tpermutations[2].middlemodifID = middlemodifID; + if (tpermutations[2].tcomposition.back() != ')') { + tpermutations[2].tcomposition = tpermutations[2].tcomposition.substr(0,tpermutations[2].tcomposition.size() - 1); + } + + + // second and third branch - switch (3x) + for (int i = 0; i < 3; i++) { + intcomposition = tpermutations[i].bricks; + tempintvector.clear(); + tpermutations[i+3].tcomposition = ""; + + // backup the middle branch + for (int j = tpermutations[i].middlebranchstart + 1; j <= tpermutations[i].middlebranchend; j++) { + tempintvector.push_back(intcomposition[j]); + } + + // begin + for (int j = 0; j < tpermutations[i].middlebranchstart; j++) { + tpermutations[i+3].tcomposition += to_string(intcomposition[j]) + "-"; + } + + if (tpermutations[i+3].tcomposition.size() > 0) { + tpermutations[i+3].tcomposition.back() = '('; + } + else { + tpermutations[i+3].tcomposition += '('; + } + + // new middle start + tpermutations[i+3].tcomposition += to_string(intcomposition[tpermutations[i].middlebranchstart]) + "-"; + + // new middle + for (int j = tpermutations[i].middlebranchend + 1; j < (int)intcomposition.size(); j++) { + tpermutations[i+3].tcomposition += to_string(intcomposition[j]) + "-"; + } + tpermutations[i+3].tcomposition.back() = ')'; + + // erase the old middle branch + intcomposition.erase(intcomposition.begin() + tpermutations[i].middlebranchstart + 1, intcomposition.begin() + tpermutations[i].middlebranchend + 1); + + tpermutations[i+3].middlebranchstart = tpermutations[i].middlebranchstart; + tpermutations[i+3].middlebranchend = (int)intcomposition.size() - 1; + + // new end + for (int j = 0; j < (int)tempintvector.size(); j++) { + intcomposition.push_back(tempintvector[j]); + tpermutations[i+3].tcomposition += to_string(tempintvector[j]) + "-"; + } + tpermutations[i+3].id = i + 3; + tpermutations[i+3].bricks = intcomposition; + tpermutations[i+3].startmodifID = tpermutations[i].startmodifID; + tpermutations[i+3].endmodifID = tpermutations[i].middlemodifID; + tpermutations[i+3].middlemodifID = tpermutations[i].endmodifID; + if (tpermutations[i+3].tcomposition.back() != ')') { + tpermutations[i+3].tcomposition = tpermutations[i+3].tcomposition.substr(0,tpermutations[i+3].tcomposition.size() - 1); + } + } + // 3 = n-terminal + // 4 = middle modification type dependent + // 5 = c-terminal + + /* + for (int i = 0; i < 6; i++) { + if (tpermutations[i].middlebranchstart == tpermutations[i].middlebranchend) { + tpermutations[i].tcomposition[tpermutations[i].tcomposition.find('(')] = '-'; + tpermutations[i].tcomposition[tpermutations[i].tcomposition.find(')')] = '-'; + if (tpermutations[i].tcomposition[0] == '-') { + tpermutations[i].tcomposition.erase(tpermutations[i].tcomposition.begin()); + } + if (tpermutations[i].tcomposition.back() == '-') { + tpermutations[i].tcomposition.erase(tpermutations[i].tcomposition.end() - 1); + } + tpermutations[i].middlebranchstart = -1; + tpermutations[i].middlebranchend = -1; + } + } + */ +} + + +double cCandidate::getPrecursorMass(cBricksDatabase& brickdatabasewithcombinations, cParameters* parameters) { + cBrick b; + vector bricks; + b.setComposition(internalcomposition, false); + b.explodeToIntComposition(bricks); + + double mass = 0; + switch (parameters->peptidetype) + { + case linear: + case linearpolysaccharide: + mass = parameters->fragmentdefinitions[precursor_ion].massdifference + parameters->searchedmodifications[startmodifID].massdifference + parameters->searchedmodifications[endmodifID].massdifference; + break; + case cyclic: + mass = parameters->fragmentdefinitions[cyclic_precursor_ion].massdifference; + break; + case branched: + mass = parameters->fragmentdefinitions[precursor_ion].massdifference + parameters->searchedmodifications[startmodifID].massdifference + parameters->searchedmodifications[endmodifID].massdifference + parameters->searchedmodifications[middlemodifID].massdifference; + break; + case lasso: + mass = parameters->fragmentdefinitions[cyclic_precursor_ion].massdifference + parameters->searchedmodifications[middlemodifID].massdifference; + break; + } + + for (int i = 0; i < (int)bricks.size(); i++) { + mass += brickdatabasewithcombinations[bricks[i] - 1].getMass(); + } + + return mass; + +} + + +bool cCandidate::isEqualTo(cCandidate& candidate) { + if ((internalcomposition.compare(candidate.internalcomposition) == 0) + && (startmodifID == candidate.startmodifID) + && (endmodifID == candidate.endmodifID) + && (middlemodifID == candidate.middlemodifID) + && (branchstart == candidate.branchstart) + && (branchend == candidate.branchend)) { + return true; + } + return false; +} + + +void cCandidate::getPermutations(cCandidateSet& permutations, bool* terminatecomputation) { + vector currentcandidate; + permutations.getSet().clear(); + currentcandidate.clear(); + getPermutationsIter(permutations, currentcandidate, 0, terminatecomputation); +} + + +int cCandidate::getStartModifID() { + return startmodifID; +} + + +void cCandidate::setStartModifID(int id) { + startmodifID = id; +} + + +int cCandidate::getEndModifID() { + return endmodifID; +} + + +void cCandidate::setEndModifID(int id) { + endmodifID = id; +} + + + +int cCandidate::getMiddleModifID() { + return middlemodifID; +} + + +void cCandidate::setMiddleModifID(int id) { + middlemodifID = id; +} + + +bool cCandidate::compare(cCandidate& candidate) { + if (getComposition() < candidate.getComposition()) { + return true; + } + if (getComposition() > candidate.getComposition()) { + return false; + } + + if (startmodifID < candidate.startmodifID) { + return true; + } + if (startmodifID > candidate.startmodifID) { + return false; + } + + if (endmodifID < candidate.endmodifID) { + return true; + } + if (endmodifID > candidate.endmodifID) { + return false; + } + + if (middlemodifID < candidate.middlemodifID) { + return true; + } + if (middlemodifID > candidate.middlemodifID) { + return false; + } + + if (branchstart < candidate.branchstart) { + return true; + } + if (branchstart > candidate.branchstart) { + return false; + } + + if (branchend < candidate.branchend) { + return true; + } + if (branchend > candidate.branchend) { + return false; + } + + return false; +} + + +vector& cCandidate::getPath() { + return path; +} + + +bool cCandidate::hasEqualTPermutations(cCandidate& candidate) { + vector tpermutations1, tpermutations2; + getPermutationsOfBranches(tpermutations1); + candidate.getPermutationsOfBranches(tpermutations2); + + for (int i = 0; i < (int)tpermutations1.size(); i++) { + if ((tpermutations1[i].tcomposition.compare(tpermutations2[0].tcomposition) == 0) && + (tpermutations1[i].startmodifID == tpermutations2[0].startmodifID) && + (tpermutations1[i].endmodifID == tpermutations2[0].endmodifID) && + (tpermutations1[i].middlemodifID == tpermutations2[0].middlemodifID) && + (tpermutations1[i].middlebranchstart == tpermutations2[0].middlebranchstart) && + (tpermutations1[i].middlebranchend == tpermutations2[0].middlebranchend)) { + return true; + } + } + + return false; +} + + +bool cCandidate::hasOnlyArtificialBricks(cBricksDatabase& brickdatabasewithcombinations) { + if (numberofinternalbricks <= 2) { + cBrick b; + vector intcomposition; + b.setComposition(internalcomposition,false); + b.explodeToIntComposition(intcomposition); + for (int i = 0; i < (int)intcomposition.size(); i++) { + if (!brickdatabasewithcombinations[intcomposition[i] - 1].isArtificial()) { + return false; + } + } + return true; + } + return false; +} + + +void cCandidate::getRotations(vector& rotations, bool includerevertedrotations) { + rotations.clear(); + //rotations.push_back(composition); + getPartialRotations(internalcomposition, rotations); + + if (includerevertedrotations) { + cBrick brick; + brick.setComposition(internalcomposition, false); + //rotations.push_back(reversedcomposition); + getPartialRotations(brick.getReverseComposition(), rotations); + } +} + + +void cCandidate::getLassoRotations(vector& lassorotations, bool includerevertedrotations) { + lassorotations.clear(); + getPartialLassoRotations(internalcomposition, lassorotations, branchstart, branchend); + if (includerevertedrotations) { + getPartialLassoRotations(getRevertedTComposition(false), lassorotations, numberofinternalbricks - branchend - 1, numberofinternalbricks - branchstart - 1); + } +} + + +void cCandidate::store(ofstream& os) { + int size; + + os.write((char *)&startmodifID, sizeof(int)); + os.write((char *)&endmodifID, sizeof(int)); + os.write((char *)&middlemodifID, sizeof(int)); + os.write((char *)&branchstart, sizeof(int)); + os.write((char *)&branchend, sizeof(int)); + + size = (int)path.size(); + os.write((char *)&size, sizeof(int)); + for (int i = 0; i < (int)path.size(); i++) { + 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()); + + os.write((char *)&numberofinternalbricks, sizeof(int)); +} + + +void cCandidate::load(ifstream& is) { + int size; + + is.read((char *)&startmodifID, sizeof(int)); + is.read((char *)&endmodifID, sizeof(int)); + is.read((char *)&middlemodifID, sizeof(int)); + is.read((char *)&branchstart, sizeof(int)); + is.read((char *)&branchend, sizeof(int)); + + is.read((char *)&size, sizeof(int)); + path.resize(size); + for (int i = 0; i < (int)path.size(); i++) { + 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()); + + is.read((char *)&numberofinternalbricks, sizeof(int)); +} + + +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 new file mode 100644 index 0000000..4f0df3f --- /dev/null +++ b/CycloBranch/core/cCandidate.h @@ -0,0 +1,472 @@ +/** + \file cCandidate.h + \brief The representation of a peptide sequence candidate. +*/ + + +#ifndef _CCANDIDATE_H +#define _CCANDIDATE_H + +#include +#include +#include + +#include "core/cParameters.h" +#include "core/cFragmentIons.h" +#include "core/cBricksDatabase.h" +#include "core/cDeNovoGraphNode.h" + +class cCandidateSet; + + +using namespace std; + + +/** + \brief An auxiliary structure representing a branch permutation of a branched peptide. +*/ +struct TRotationInfo { + + /** + \brief Id of the rotation. + */ + int id; + + + /** + \brief Vector of ids of bricks. + */ + vector bricks; + + + /** + \brief Position of a brick where a branch of a branched peptide starts. + */ + int middlebranchstart; + + + /** + \brief Position of a brick where a branch of a branched peptide ends. + */ + int middlebranchend; + + + /** + \brief Id of a terminal modification (at the beginning of a spectrum). + */ + int startmodifID; + + + /** + \brief Id of a terminal modification (at the end of a spectrum). + */ + int endmodifID; + + + /** + \brief Id of a terminal modification of a branched peptide (in the middle of a spectrum). + */ + int middlemodifID; + + + /** + \brief Ids of bricks separated by '-', the branch is specified by '(' and ')'; example: 1-2-3(4-5)6-7. + */ + string tcomposition; + + + /** + \brief The constructor. + */ + TRotationInfo() { + clear(); + } + + + /** + \brief Clear the structure. + */ + void clear() { + id = 0; + bricks.clear(); + middlebranchstart = 0; + middlebranchend = 0; + startmodifID = 0; + endmodifID = 0; + middlemodifID = 0; + tcomposition = ""; + } + + + /** + \brief Test whether \a tcomposition starts with a bracket. + \retval bool true when \a tcomposition starts with a bracket + */ + bool startsWithBracket() { + if (tcomposition.size() == 0) { + return false; + } + return tcomposition[0] == '('; + } + + /** + \brief Test whether \a tcomposition ends with a bracket. + \retval bool true when \a tcomposition ends with a bracket + */ + bool endsWithBracket() { + if (tcomposition.size() == 0) { + return false; + } + return tcomposition.back() == ')'; + } + +}; + + +/** + \brief The class representing a peptide sequence candidate. +*/ +class cCandidate { + + int startmodifID; + int endmodifID; + int middlemodifID; + int branchstart; + int branchend; + vector path; + + vector composition; + string internalcomposition; + int numberofinternalbricks; + + void updateInternalComposition(); + + void getPermutationsIter(cCandidateSet& permutations, vector& currentcandidate, int position, bool* terminatecomputation); + + void attachSubBranchCandidates(cCandidate& candidate, cCandidateSet& result, peptideType peptidetype, bool* terminatecomputation); + + void attachAllBranches(cCandidate& candidate, cCandidateSet& result, peptideType peptidetype, bool* terminatecomputation); + + void getPartialRotations(string& composition, vector& rotations); + + void getPartialLassoRotations(string& composition, vector& lassorotations, int branchstart, int branchend); + +public: + + /** + \brief The default constructor. + */ + cCandidate(); + + + /** + \brief The constructor. + \param composition reference to a vector of strings where each string is a sequence of ids of bricks separated by '-' (each string corresponds to an edge in the de novo graph) + \param path reference to a path in the de novo graph which corresponds to a peptide sequence candidate + \param startmodifID id of a terminal modification (at the beginning of a spectrum) + \param endmodifID id of a terminal modification (at the end of a spectrum) + \param middlemodifID id of a terminal modification of a branched peptide (in the middle of a spectrum) + \param middlepos position in \a composition corresponding to a branch of a branched peptide + */ + cCandidate(vector& composition, vector& path, int startmodifID, int endmodifID, int middlemodifID, int middlepos); + + + /** + \brief The constructor. + \param composition reference to a vector of strings where each string is a sequence of ids of bricks separated by '-' (each string corresponds to an edge in the de novo graph) + \param path reference to a path in the de novo graph which corresponds to a peptide sequence candidate + \param startmodifID id of a terminal modification (at the beginning of a spectrum) + \param endmodifID id of a terminal modification (at the end of a spectrum) + \param middlemodifID id of a terminal modification of a branched peptide (in the middle of a spectrum) + \param branchstart position of a brick where a branch of a branched peptide starts (it is assumed that all strings in \a composition are concatenated) + \param branchend position of a brick where a branch of a branched peptide ends (it is assumed that all strings in \a composition are concatenated) + */ + cCandidate(vector& composition, vector& path, int startmodifID, int endmodifID, int middlemodifID, int branchstart, int branchend); + + + /** + \brief Set a peptide sequence candidate. + \param composition reference to a vector of strings where each string is a sequence of ids of bricks separated by '-' (each string corresponds to an edge in the de novo graph) + \param path reference to a path in the de novo graph which corresponds to a peptide sequence candidate + \param startmodifID id of a terminal modification (at the beginning of a spectrum) + \param endmodifID id of a terminal modification (at the end of a spectrum) + \param middlemodifID id of a terminal modification of a branched peptide (in the middle of a spectrum) + \param middlepos position in \a composition corresponding to a branch of a branched peptide + */ + void setCandidate(vector& composition, vector& path, int startmodifID, int endmodifID, int middlemodifID, int middlepos); + + + /** + \brief Set a peptide sequence candidate. + \param composition reference to a vector of strings where each string is a sequence of ids of bricks separated by '-' (each string corresponds to an edge in the de novo graph) + \param path reference to a path in the de novo graph which corresponds to a peptide sequence candidate + \param startmodifID id of a terminal modification (at the beginning of a spectrum) + \param endmodifID id of a terminal modification (at the end of a spectrum) + \param middlemodifID id of a terminal modification of a branched peptide (in the middle of a spectrum) + \param branchstart position of a brick where a branch of a branched peptide starts (it is assumed that all strings in \a composition are concatenated) + \param branchend position of a brick where a branch of a branched peptide ends (it is assumed that all strings in \a composition are concatenated) + */ + void setCandidate(vector& composition, vector& path, int startmodifID, int endmodifID, int middlemodifID, int branchstart, int branchend); + + + /** + \brief Clear the candidate. + */ + void clear(); + + + /** + \brief Access to the composition of the peptide sequence candidate. + \retval reference to a string of ids of bricks separated by '-' + */ + string& getComposition(); + + + /** + \brief Reverse the bricks composition of the candidate. + */ + void revertComposition(); + + + /** + \brief Prepare candidates of a branched or a lasso peptide. + \param result reference to an output set of possible peptide sequence candidates + \param peptidetype a type of an analyzed peptide + \param terminatecomputation pointer to a variable determining that the computation must be stopped + */ + void prepareBranchedCandidate(cCandidateSet& result, peptideType peptidetype, bool* terminatecomputation); + + + /** + \brief Get a T-composition of a branched peptide. + \retval string containing ids of bricks separated by '-', the branch is specified by '(' and ')'; example: 1-2-3(4-5)6-7 + */ + string getTComposition(); + + + /** + \brief Get a reverted T-composition of a branched peptide. + \param usebrackets if true then the branch is separated by '(' and ')' else '-' is used instead of brackets + \retval string containing ids of bricks separated by '-', the branch may be specified by '(' and ')'; example: 1-2-3(4-5)6-7 + */ + string getRevertedTComposition(bool usebrackets); + + + /** + \brief Get a T-composition of a branched peptide composed from acronyms of bricks. + \param brickdatabase reference to the database of bricks + \retval string containing acronyms of bricks separated by '-', the branch is specified by '(' and ')' + */ + string getAcronymsTComposition(cBricksDatabase& brickdatabase); + + + /** + \brief Get a T-composition of a branched peptide composed from real names of bricks. + \param brickdatabase reference to the database of bricks + \retval string containing real names of bricks separated by '-', the branch is specified by '(' and ')' + */ + string getRealNameTComposition(cBricksDatabase& brickdatabase); + + + /** + \brief Get a number of blocks forming a branch. + \retval int number of blocks + */ + int getBranchSize(); + + + /** + \brief Get starting position of a branch. + \retval int starting position of a branch + */ + int getBranchStart(); + + + /** + \brief Get end position of a branch. + \retval int end position of a branch + */ + int getBranchEnd(); + + + /** + \brief Get acronyms of blocks on a backbone of a branched peptide. + \param bricksdatabase reference to the database of bricks + \param acronyms an output vector of string acronyms + */ + void getBackboneAcronyms(cBricksDatabase& bricksdatabase, vector& acronyms); + + + /** + \brief Get acronyms of blocks on a branch of a branched peptide. + \param bricksdatabase reference to the database of bricks + \param acronyms an output vector of string acronyms + */ + void getBranchAcronyms(cBricksDatabase& bricksdatabase, vector& acronyms); + + + /** + \brief Get permutations of branches a branched peptide. + \param tpermutations reference to an output vector of auxiliary structures where permutations will be stored + */ + void getPermutationsOfBranches(vector& tpermutations); + + + /** + \brief Get the precursor mass of the peptide sequence candidate. + \param brickdatabasewithcombinations reference to an input database of bricks with combinations of bricks + \param parameters a pointer to the parameters of the application + \retval double precursor mass of the candidate + */ + double getPrecursorMass(cBricksDatabase& brickdatabasewithcombinations, cParameters* parameters); + + + /** + \brief Compare two candidates. + \param candidate reference to the other candidate + \retval bool true when the candidates are equal + */ + bool isEqualTo(cCandidate& candidate); + + + /** + \brief Get a set of candidates with permutations of bricks. + \param permutations reference to an output set of candidates + \param terminatecomputation pointer to a variable determining that the computation must be stopped + */ + void getPermutations(cCandidateSet& permutations, bool* terminatecomputation); + + + /** + \brief Get id of a terminal modification (at the beginning of a spectrum). + \retval int id of a terminal modification + */ + int getStartModifID(); + + + /** + \brief Set id of a terminal modification (at the beginning of a spectrum). + \param id of a terminal modification + */ + void setStartModifID(int id); + + + /** + \brief Get id of a terminal modification (at the end of a spectrum). + \retval int id of a terminal modification + */ + int getEndModifID(); + + + /** + \brief Set id of a terminal modification (at the end of a spectrum). + \param id of a terminal modification + */ + void setEndModifID(int id); + + + /** + \brief Get id of a terminal modification of a branched peptide (in the middle of a spectrum). + \retval int id of a terminal modification + */ + int getMiddleModifID(); + + + /** + \brief Set id of a terminal modification of a branched peptide (in the middle of a spectrum). + \param id of a terminal modification + */ + void setMiddleModifID(int id); + + + /** + \brief Compare two candidates. + \param candidate reference to the other candidate + \retval bool true when the other candidate is greater + */ + bool compare(cCandidate& candidate); + + + /** + \brief Get a path in the de novo graph corresponding to the peptide sequence candidate. + \retval vector reference to a vector of pairs node and edge + */ + vector& getPath(); + + + /** + \brief compare TPermutations of two candidates. + \param candidate reference to the second candidate + \retval true when candidates have equal TPermutations + */ + bool hasEqualTPermutations(cCandidate& candidate); + + + /** + \brief Check whether the candidate is composed exclusively from artificial bricks. + \param brickdatabasewithcombinations reference to an input database of bricks with combinations of bricks + \retval bool true when the candidate is composed exclusively from artificial bricks; false when the candidate constains a regular brick + */ + bool hasOnlyArtificialBricks(cBricksDatabase& brickdatabasewithcombinations); + + + /** + \brief Get rotations of a cyclic peptide sequence. + \param rotations reference to an output vector containing rotations of a sequence + \param includerevertedrotations if true then reverted rotations are also included + */ + void getRotations(vector& rotations, bool includerevertedrotations); + + + /** + \brief Get lasso rotations of a lasso peptide sequence. + \param lassorotations reference to an output vector containing lasso rotations of a sequence + \param includerevertedrotations if true then reverted lasso rotations are also included + */ + void getLassoRotations(vector& lassorotations, bool includerevertedrotations); + + + /** + \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 The structure defining a hash function of cCandidate. +*/ +struct hash_cCandidate { + + /** + \brief Hash a peptide sequence candidate. + \param candidate reference to a peptide sequence candidate + \retval size_t hashed candidate + */ + size_t operator()(const cCandidate& candidate) const { + return hash()(((cCandidate&)candidate).getComposition()); + } + +}; + + +/** + \brief Overloaded operator ==. + \param a first candidate + \param b second candidate + \retval bool true when candidates are equal +*/ +bool operator == (cCandidate const& a, cCandidate const& b); + + +#endif + diff --git a/CycloBranch/core/cCandidateSet.cpp b/CycloBranch/core/cCandidateSet.cpp new file mode 100644 index 0000000..f8d9d5e --- /dev/null +++ b/CycloBranch/core/cCandidateSet.cpp @@ -0,0 +1,17 @@ +#include "core/cCandidateSet.h" + + +cCandidateSet::cCandidateSet() { + candidates.clear(); +} + + +int cCandidateSet::size() { + return (int)candidates.size(); +} + + +unordered_set& cCandidateSet::getSet() { + return candidates; +} + diff --git a/CycloBranch/core/cCandidateSet.h b/CycloBranch/core/cCandidateSet.h new file mode 100644 index 0000000..8e2e984 --- /dev/null +++ b/CycloBranch/core/cCandidateSet.h @@ -0,0 +1,47 @@ +/** + \file cCandidateSet.h + \brief The representation of a set of peptide sequence candidates. +*/ + + +#ifndef _CCANDIDATESET_H +#define _CCANDIDATESET_H + +#include + +#include "core/cCandidate.h" + + +/** + \brief The class representing a set of peptide sequence candidates. +*/ +class cCandidateSet : public QMutex { + + unordered_set candidates; + +public: + + /** + \brief The constructor. + */ + cCandidateSet(); + + + /** + \brief Get the size of the set. + \retval int size of the set + */ + int size(); + + + /** + \brief Access to the set of candidates. + \retval unordered_set reference to the set of candidates + */ + unordered_set& getSet(); + +}; + + +#endif + diff --git a/CycloBranch/core/cDeNovoGraph.cpp b/CycloBranch/core/cDeNovoGraph.cpp new file mode 100644 index 0000000..cf97657 --- /dev/null +++ b/CycloBranch/core/cDeNovoGraph.cpp @@ -0,0 +1,1008 @@ +#include "core/cDeNovoGraph.h" + +#include "gui/cMainThread.h" + + +bool compareNodes(cDeNovoGraphNode& node1, cDeNovoGraphNode& node2) { + if (node1.getMZRatio() < node2.getMZRatio()) { + return true; + } + return false; +} + + +cDeNovoGraph::cDeNovoGraph() { + parameters = 0; + graph.clear(); + lastsystemnode = 0; + os = 0; + startnode = 0; + + graphreaderthread = 0; +} + + +bool cDeNovoGraph::findPath(int sourcenodeid, int edgeid, int targetnodeid, string& composition, string brickspath, int maximumbricksincombination, int depth) { + string localbrickpath; + + int count = getNumberOfBricks(brickspath); + + if ((depth > 1) && (sourcenodeid == targetnodeid)) { + cBrick b; + b.setComposition(brickspath, true); + if (composition.compare(b.getComposition()) == 0) { + //*os << endl << "brick: " << brickspath << " path: " << sourcenodeid << " "; + return true; + } + } + + if (count < maximumbricksincombination) { + for (int i = 0; i < (int)graph[sourcenodeid].size(); i++) { + if ((i == edgeid) && (depth == 0)) { + continue; + } + localbrickpath = brickspath; + if (localbrickpath.size() > 0) { + localbrickpath += '-'; + } + localbrickpath += graph[sourcenodeid][i].composition; + if (findPath(graph[sourcenodeid][i].targetnode, i, targetnodeid, composition, localbrickpath, maximumbricksincombination, depth + 1)) { + //*os << sourcenodeid << " "; + return true; + } + } + } + + return false; +} + + +void cDeNovoGraph::createVectorsOfEdges() { + for (int i = 0; i < (int)graph.size(); i++) { + graph[i].createVectorOfEdges(); + } +} + + +bool cDeNovoGraph::finishInPrecursor(int currentnode, double cummass) { + + if (graph[currentnode].size() == 0) { + if (currentnode == (int)graph.size() - 1) { + return true; + } + else { + return false; + } + } + + if (cummass > graph.back().getMZRatio()) { + return false; + } + + for (int i = 0; i < (int)graph[currentnode].size(); i++) { + if (finishInPrecursor(graph[currentnode][i].targetnode, cummass + graph[currentnode][i].massdifference)) { + return true; + } + } + + return false; +} + + +void cDeNovoGraph::initialize(cMainThread& os, cParameters& parameters) { + graph.clear(); + lastsystemnode = 0; + this->os = &os; + this->parameters = ¶meters; + startnode = 0; +} + + +int cDeNovoGraph::createGraph(bool& terminatecomputation) { + cDeNovoGraphNode node; + double mass; + double termmass; + int left, right, middle; + cEdge e, e1, e2; + double unchargedprecursormass = uncharge(parameters->precursormass, parameters->precursorcharge); + double unchargedmz; + int i; + + sortedpeaklist = parameters->peaklist; + // insert the single charged precursor, if neccessary + sortedpeaklist.sortbyMass(); + sortedpeaklist.cropMaximumMZRatio(unchargedprecursormass); + if ((sortedpeaklist.size() > 0) && (!isInPpmMassErrorTolerance(sortedpeaklist[sortedpeaklist.size() - 1].mzratio, unchargedprecursormass, parameters->precursormasserrortolerance))) { + cPeak p; + p.mzratio = unchargedprecursormass; + sortedpeaklist.add(p); + } + + *os << "Creating the de novo graph... " << endl; + + // deconvolution + sortedpeaklist.removeChargeVariants(parameters->precursorcharge, parameters->fragmentmasserrortolerance); + *os << "Number of nodes after deconvolution: " << sortedpeaklist.size() << endl; + + // remove water loss peaks + sortedpeaklist.removeNeutralLoss(- H2O, parameters->precursorcharge, parameters->fragmentmasserrortolerance); + *os << "Number of nodes when water loss ions are removed: " << sortedpeaklist.size() << endl; + + // remove ammonia loss peaks + sortedpeaklist.removeNeutralLoss(- NH3, parameters->precursorcharge, parameters->fragmentmasserrortolerance); + *os << "Number of nodes when ammonia loss ions are removed: " << sortedpeaklist.size() << endl; + + // insert system nodes + switch (parameters->peptidetype) + { + case cyclic: + node.clear(); + node.setMZRatio(parameters->fragmentdefinitions[b_ion].massdifference); + node.setIntensity(0); + node.addIonAnnotation(b_ion); + graph.push_back(node); + break; + case linear: + case branched: + node.clear(); + node.setMZRatio(0); + node.setIntensity(0); + node.addIonAnnotation(b_ion); + node.addIonAnnotation(y_ion); + graph.push_back(node); + + node.clear(); + node.setMZRatio(parameters->fragmentdefinitions[b_ion].massdifference); + node.setIntensity(0); + node.addIonAnnotation(b_ion); + graph.push_back(node); + + node.clear(); + node.setMZRatio(parameters->fragmentdefinitions[y_ion].massdifference); + node.setIntensity(0); + node.addIonAnnotation(y_ion); + graph.push_back(node); + + e.clear(); + e.composition = "0"; + e.targetnode = 1; + graph[0].insertTempEdge(e); + + e.clear(); + e.composition = "0"; + e.targetnode = 2; + graph[0].insertTempEdge(e); + + for (i = 1; i < (int)parameters->searchedmodifications.size(); i++) { + node.clear(); + + e.clear(); + e.composition = "0"; + e.targetnode = i + 2; + + if (parameters->searchedmodifications[i].nterminal) { + node.setMZRatio(parameters->fragmentdefinitions[b_ion].massdifference + parameters->searchedmodifications[i].massdifference); + node.setIntensity(0); + node.addIonAnnotation(b_ion); + } + + if (parameters->searchedmodifications[i].cterminal) { + node.setMZRatio(parameters->fragmentdefinitions[y_ion].massdifference + parameters->searchedmodifications[i].massdifference); + node.setIntensity(0); + node.addIonAnnotation(y_ion); + } + + graph.push_back(node); + graph[0].insertTempEdge(e); + } + + lastsystemnode = (int)graph.size() - 1; + startnode = 1; + + // to do - problem with e.targetnode + //sort(graph.begin() + 1, graph.end(), compareNodes); + + break; + case lasso: + node.clear(); + node.setMZRatio(0); + node.setIntensity(0); + node.addIonAnnotation(b_ion); + //node.addIonAnnotation(y_ion); + graph.push_back(node); + + node.clear(); + node.setMZRatio(parameters->fragmentdefinitions[b_ion].massdifference); + node.setIntensity(0); + node.addIonAnnotation(b_ion); + graph.push_back(node); + + //node.clear(); + //node.setMZRatio(parameters->fragmentdefinitions[y_ion].massdifference); + //node.setIntensity(0); + //node.addIonAnnotation(y_ion); + //graph.push_back(node); + + e.clear(); + e.composition = "0"; + e.targetnode = 1; + graph[0].insertTempEdge(e); + + //e.clear(); + //e.composition = "0"; + //e.targetnode = 2; + //graph[0].insertTempEdge(e); + + /* + for (i = 1; i < (int)parameters->searchedmodifications.size(); i++) { + node.clear(); + + e.clear(); + e.composition = "0"; + e.targetnode = i + 2; + + if (parameters->searchedmodifications[i].nterminal) { + node.setMZRatio(parameters->fragmentdefinitions[b_ion].massdifference + parameters->searchedmodifications[i].massdifference); + node.setIntensity(0); + node.addIonAnnotation(b_ion); + } + + if (parameters->searchedmodifications[i].cterminal) { + node.setMZRatio(parameters->fragmentdefinitions[y_ion].massdifference + parameters->searchedmodifications[i].massdifference); + node.setIntensity(0); + node.addIonAnnotation(y_ion); + } + + graph.push_back(node); + graph[0].insertTempEdge(e); + } + */ + + lastsystemnode = (int)graph.size() - 1; + startnode = 1; + break; + case linearpolysaccharide: + node.clear(); + node.setMZRatio(0); + node.setIntensity(0); + node.addIonAnnotation(ms_nterminal_ion_hplus); + //node.addIonAnnotation(ms_cterminal_ion_hplus); + graph.push_back(node); + + node.clear(); + node.setMZRatio(H2O + Hplus); + node.setIntensity(0); + node.addIonAnnotation(ms_nterminal_ion_hplus); + graph.push_back(node); + + //node.clear(); + //node.setMZRatio(H2O + Hplus); + //node.setIntensity(0); + //node.addIonAnnotation(ms_cterminal_ion_hplus); + //graph.push_back(node); + + e.clear(); + e.composition = "0"; + e.targetnode = 1; + graph[0].insertTempEdge(e); + + //e.clear(); + //e.composition = "0"; + //e.targetnode = 2; + //graph[0].insertTempEdge(e); + + for (i = 1; i < (int)parameters->searchedmodifications.size(); i++) { + node.clear(); + + e.clear(); + e.composition = "0"; + e.targetnode = i + 1;//2; + + //if (parameters->searchedmodifications[i].nterminal) { + node.setMZRatio(H2O + Hplus + parameters->searchedmodifications[i].massdifference); + node.setIntensity(0); + node.addIonAnnotation(ms_nterminal_ion_hplus); + //} + + //if (parameters->searchedmodifications[i].cterminal) { + // node.setMZRatio(H2O + Hplus +parameters->searchedmodifications[i].massdifference); + // node.setIntensity(0); + // node.addIonAnnotation(ms_cterminal_ion_hplus); + //} + + graph.push_back(node); + graph[0].insertTempEdge(e); + } + + lastsystemnode = (int)graph.size() - 1; + startnode = 1; + break; + default: + *os << "Undefined peptide type." << endl; + return -1; + } + + + // initialize nodes by mzratios from a sorted peak list + for (i = 0; i < sortedpeaklist.size(); i++) { + node.clear(); + node.setMZRatio(sortedpeaklist[i].mzratio); + node.setIntensity(sortedpeaklist[i].intensity); + graph.push_back(node); + } + + bricksdatabasewithcombinations = parameters->bricksdatabase; + *os << "Number of bricks: " << parameters->bricksdatabase.size() << endl; + *os << "Calculating number of brick combinations... "; + + // initialization for generating the combinations of bricks + vector combarray; + int numberofbasicbricks = bricksdatabasewithcombinations.size(); + string compositionname; + cBrick b; + bool usedbrick; + + long long totaltested = 0; + for (i = 0; i < parameters->maximumbricksincombination; i++) { + combarray.push_back(0); + } + + while (bricksdatabasewithcombinations.nextCombination(combarray, numberofbasicbricks, parameters->maximumbricksincombination, parameters->maximumcumulativemass)) { + if (terminatecomputation) { + return -1; + } + totaltested++; + } + + *os << "ok" << endl; + *os << "Combinations of bricks: " << totaltested << endl; + + totaltested = 0; + combarray.clear(); + for (i = 0; i < parameters->maximumbricksincombination; i++) { + combarray.push_back(0); + } + + // initialize edges + *os << "Generating combinations of bricks and generating edges... " << endl; + + int j = 0; + while (bricksdatabasewithcombinations.nextCombination(combarray, numberofbasicbricks, parameters->maximumbricksincombination, parameters->maximumcumulativemass)) { + + if (terminatecomputation) { + return -1; + } + + totaltested++; + + if (totaltested % 1000000 == 0) { + *os << totaltested << " "; + } + + if (totaltested % 10000000 == 0) { + *os << endl; + } + + usedbrick = false; + + getNameOfCompositionFromIntVector(compositionname, combarray); + if (j < numberofbasicbricks) { + bricksdatabasewithcombinations[j].setComposition(compositionname, true); + } + else { + b.clear(); + b.setMass(bricksdatabasewithcombinations.getMassOfComposition(combarray, parameters->maximumbricksincombination)); + b.setComposition(compositionname, true); + bricksdatabasewithcombinations.push_back(b); + } + + //cout << bricksdatabasewithcombinations.getAcronymName(bricksdatabasewithcombinations[j].getComposition(), false) << " " << bricksdatabasewithcombinations[j].getMass() << endl; + + i = startnode; + while (i < (int)graph.size()) { + + if (terminatecomputation) { + return -1; + } + + if (i <= lastsystemnode) { + if (getNumberOfBricks(bricksdatabasewithcombinations[j].getComposition()) > parameters->maximumbricksincombinationbegin) { + i = lastsystemnode + 1; + } + } + + if ((i > lastsystemnode) && (i < (int)graph.size() - 1)) { + if (getNumberOfBricks(bricksdatabasewithcombinations[j].getComposition()) > parameters->maximumbricksincombinationmiddle) { + i = (int)graph.size() - 1; + } + } + + if (i == (int)graph.size() - 1) { + if (getNumberOfBricks(bricksdatabasewithcombinations[j].getComposition()) > parameters->maximumbricksincombinationend) { + break; + } + } + + for (int k = 0; k < (int)parameters->fragmentionsfordenovograph.size(); k++) { + + if (/*!graph[i].ionannotation[parameters->fragmentionsfordenovograph[k]] ||*/ (parameters->fragmentionsfordenovograph[k] == precursor_ion)) { + continue; + } + + for (int m = 0; m < (int)parameters->fragmentionsfordenovograph.size(); m++) { + + // test for incompatible ion series + if ((!((parameters->fragmentdefinitions[parameters->fragmentionsfordenovograph[k]].nterminal == parameters->fragmentdefinitions[parameters->fragmentionsfordenovograph[m]].nterminal) && + (parameters->fragmentdefinitions[parameters->fragmentionsfordenovograph[k]].cterminal == parameters->fragmentdefinitions[parameters->fragmentionsfordenovograph[m]].cterminal))) && (parameters->fragmentionsfordenovograph[m] != precursor_ion)) { + continue; + } + + // terminal modifications + for (int n = 0; n < (int)parameters->searchedmodifications.size(); n++) { + + if ((n > 0) && (parameters->fragmentionsfordenovograph[m] != precursor_ion)) { + continue; + } + + // middle modifications for branched and lasso peptides + for (int p = 0; p < (int)parameters->searchedmodifications.size(); p++) { + + if ((p > 0) && ((parameters->peptidetype == linear) || (parameters->peptidetype == cyclic) || (parameters->peptidetype == linearpolysaccharide))) { + continue; + } + + termmass = 0; + + if (parameters->fragmentionsfordenovograph[m] == precursor_ion) { + + if ((parameters->peptidetype == linear) || ((parameters->peptidetype == linearpolysaccharide))) { + if ((n > 0) && ((parameters->fragmentdefinitions[parameters->fragmentionsfordenovograph[k]].nterminal && parameters->searchedmodifications[n].nterminal) || (parameters->fragmentdefinitions[parameters->fragmentionsfordenovograph[k]].cterminal && parameters->searchedmodifications[n].cterminal))) { + continue; + } + } + + if (parameters->peptidetype == branched) { + if ((n > 0) && (p > 0) && ((parameters->fragmentdefinitions[parameters->fragmentionsfordenovograph[k]].nterminal && parameters->searchedmodifications[n].nterminal && parameters->searchedmodifications[p].nterminal) || (parameters->fragmentdefinitions[parameters->fragmentionsfordenovograph[k]].cterminal && parameters->searchedmodifications[n].cterminal && parameters->searchedmodifications[p].cterminal))) { + continue; + } + } + + termmass = parameters->searchedmodifications[n].massdifference; + + } + + for (int z1 = 1; z1 <= parameters->precursorcharge; z1++) { + + for (int z2 = 1; z2 <= parameters->precursorcharge; z2++) { + + unchargedmz = uncharge(graph[i].getMZRatio(), z1); + if ((!isInPpmMassErrorTolerance(unchargedmz, unchargedprecursormass, parameters->fragmentmasserrortolerance)) && (unchargedmz > unchargedprecursormass)) { + continue; + } + + mass = bricksdatabasewithcombinations[j].getMass(); + mass -= parameters->fragmentdefinitions[parameters->fragmentionsfordenovograph[k]].massdifference; + mass += parameters->fragmentdefinitions[parameters->fragmentionsfordenovograph[m]].massdifference; + mass += termmass; + + if ((parameters->peptidetype == branched) || (parameters->peptidetype == lasso)) { + mass += parameters->searchedmodifications[p].massdifference; + } + + // precursor is connected from the right side (sequence tags) + if (i == (int)graph.size() - 1) { + mass = unchargedmz - mass; + } + else { + mass += unchargedmz; + } + + // search for a peak in a distance determined by a mass of a brick + left = lastsystemnode + 1; + right = (int)graph.size() - 2; + // binary search + while (left <= right) { + + middle = (left + right) / 2; + if (isInPpmMassErrorTolerance(uncharge(graph[middle].getMZRatio(), z2), mass, parameters->fragmentmasserrortolerance)) { + // found + while ((middle > lastsystemnode + 1) && isInPpmMassErrorTolerance(uncharge(graph[middle - 1].getMZRatio(), z2), mass, parameters->fragmentmasserrortolerance)) { + middle--; + } + while ((middle < (int)graph.size()) && (isInPpmMassErrorTolerance(uncharge(graph[middle].getMZRatio(), z2), mass, parameters->fragmentmasserrortolerance))) { + + // target node cannot be a system node + if (middle <= lastsystemnode) { + middle++; + continue; + } + + // avoid cyclic paths + if (i == middle) { + middle++; + continue; + } + + // mass corresponding to the target node must be <= uncharged precursor mass + if (uncharge(graph[middle].getMZRatio(), z2) > unchargedprecursormass) { + middle++; + continue; + } + + // irrelevant connection with precursor + if ((parameters->fragmentionsfordenovograph[m] == precursor_ion) && (middle != (int)graph.size() - 1) && (i != (int)graph.size() - 1)) { + middle++; + continue; + } + + // create an edge + cEdge e; + + if (i == (int)graph.size() - 1) { + e.targetnode = i; + e.brickid = j; + e.ppmerror = ppmError(uncharge(graph[middle].getMZRatio(), z2), mass); + e.massdifference = abs(unchargedmz - uncharge(graph[middle].getMZRatio(), z2)); + e.sourcecharge = z2; + e.targetcharge = z1; + e.targetintensity = graph[i].getIntensity(); + e.composition = bricksdatabasewithcombinations[j].getComposition(); + e.endmodifID = n; + e.middlemodifID = p; + + // insert the new edge and/or attach the annotation to the source node if the edge exists + graph[middle].insertTempEdge(e); + } + else { + e.targetnode = middle; + e.brickid = j; + e.ppmerror = ppmError(uncharge(graph[middle].getMZRatio(), z2), mass); + e.massdifference = abs(uncharge(graph[middle].getMZRatio(), z2) - unchargedmz); + e.sourcecharge = z1; + e.targetcharge = z2; + e.targetintensity = graph[middle].getIntensity(); + e.composition = bricksdatabasewithcombinations[j].getComposition(); + e.endmodifID = n; + e.middlemodifID = p; + + // insert the new edge and/or attach the annotation to the source node if the edge exists + graph[i].insertTempEdge(e); + + } + + usedbrick = true; + + middle++; + } + break; + } + if (mass < uncharge(graph[middle].getMZRatio(), z2)) { + right = middle - 1; + } + else { + left = middle + 1; + } + + } + + } + + } + + } + + } + + } + + } + + i++; + + } + + if (((int)bricksdatabasewithcombinations.size() > numberofbasicbricks) && (!usedbrick)) { + bricksdatabasewithcombinations.removeLastBrick(); + } + else { + j++; + } + + } + + createVectorsOfEdges(); + + *os << endl << "The de novo graph has been successfully created." << endl; + *os << "Number of bricks combinations used: " << bricksdatabasewithcombinations.size() << endl; + *os << "Number of nodes: " << graph.size() << endl; + *os << "Number of edges: " << getNumberOfEdges() << endl << endl; + + return 0; +} + + +int cDeNovoGraph::removeEdgesFormingPathsNotFinishingInPrecursor(bool& terminatecomputation) { + *os << "Removing edges forming blind paths (not finishing in the precursor)... "; + double unchargedprecursormass = uncharge(parameters->precursormass, parameters->precursorcharge); + bool removed = true; + bool isprecursor; + int edgesremoved = 0; + int j; + while (removed) { + removed = false; + for (int i = startnode; i < (int)graph.size(); i++) { + + if (terminatecomputation) { + return -1; + } + + j = 0; + while (j < (int)graph[i].size()) { + + // Is the target precursor ? + isprecursor = false; + for (int k = 1; k <= parameters->precursorcharge; k++) { + if (isInPpmMassErrorTolerance(graph[graph[i][j].targetnode].getMZRatio(), charge(unchargedprecursormass, k), parameters->precursormasserrortolerance)) { + isprecursor = true; + break; + } + } + + // the target has not any outgoing edge and the target is not the precursor + if ((graph[graph[i][j].targetnode].size() == 0) && !isprecursor) { + graph[i].removeEdge(j); + edgesremoved++; + removed = true; + } + else { + j++; + } + } + } + } + *os << "ok" << endl; + *os << "Edges removed: " << edgesremoved << endl; + *os << "Number of edges: " << getNumberOfEdges() << endl << endl; + + return 0; +} + + +int cDeNovoGraph::removeEdgesFormingPathsNotStartingFromFirstNode(bool& terminatecomputation) { + *os << "Removing edges forming blind paths (not starting from the first node)... "; + bool removed = true; + int edgesremoved = 0; + bool match; + + while (removed) { + removed = false; + for (int i = lastsystemnode + 1; i < (int)graph.size(); i++) { + + if (terminatecomputation) { + return -1; + } + + // Am I a target node ? + match = false; + for (int j = startnode; j < (int)graph.size(); j++) { + for (int k = 0; k < (int)graph[j].size(); k++) { + if (graph[j][k].targetnode == i) { + match = true; + break; + } + } + if (match) { + break; + } + } + + // remove all outgoing edges + if (!match) { + edgesremoved += (int)graph[i].size(); + graph[i].clearEdges(); + } + + } + } + *os << "ok" << endl; + *os << "Edges removed: " << edgesremoved << endl; + *os << "Number of edges: " << getNumberOfEdges() << endl << endl; + + return 0; +} + + +int cDeNovoGraph::connectEdgesFormingPathsNotFinishingInPrecursor(bool& terminatecomputation) { + *os << "Connecting edges with the precursor's node to generate sequence tags... "; + //*os << "Connecting edges forming blind paths (not finishing in the precursor)... "; + int edgescreated = 0; + int precursorposition = (int)graph.size() - 1; + + for (int i = lastsystemnode + 1; i < precursorposition; i++) { + + if (terminatecomputation) { + return -1; + } + + // the target has not any outgoing edge and the target is not the precursor + //if (!finishInPrecursor(i, graph[i].getMZRatio())) { + cEdge e; + e.targetnode = (int)graph.size() - 1; + e.brickid = (int)bricksdatabasewithcombinations.size() + 1; + e.ppmerror = 0; + e.massdifference = abs(graph[precursorposition].getMZRatio() - graph[i].getMZRatio()); + e.sourcecharge = 1; + e.targetcharge = 1; + e.targetintensity = graph[e.targetnode].getIntensity(); + e.composition = to_string(e.brickid); + e.endmodifID = 0; + e.middlemodifID = 0; + graph[i].insertEdge(e); + edgescreated++; + + cBrick b; + b.setName(to_string(e.massdifference)); + b.setAcronyms(to_string(e.massdifference)); + string s = "unknown"; + b.setReferences(s); + b.setSummary(s); + b.setMass(e.massdifference); + b.setComposition(to_string(e.brickid), false); + b.setArtificial(true); + bricksdatabasewithcombinations.push_back(b); + //} + + } + + *os << "ok" << endl; + *os << "Edges created: " << edgescreated << endl; + *os << "Number of edges: " << getNumberOfEdges() << endl << endl; + + return 0; +} + + +int cDeNovoGraph::connectEdgesFormingPathsNotStartingFromFirstNode(bool& terminatecomputation) { + *os << "Connecting edges with the starting node to generate sequence tags... "; + //*os << "Connecting edges forming blind paths (not starting from the first node)... "; + int edgescreated = 0; + //bool match; + + for (int i = lastsystemnode + 1; i < (int)graph.size() - 1; i++) { + + if (terminatecomputation) { + return -1; + } + + // Am I a target node ? + /*match = false; + for (int j = startnode; j < (int)graph.size() - 1; j++) { + for (int k = 0; k < (int)graph[j].size(); k++) { + if (graph[j][k].targetnode == i) { + match = true; + break; + } + } + if (match) { + break; + } + }*/ + + // connect with starting nodes + //if (!match) { + for (int j = startnode; j <= lastsystemnode; j++) { + cEdge e; + e.targetnode = i; + e.brickid = (int)bricksdatabasewithcombinations.size() + 1; + e.ppmerror = 0; + e.massdifference = abs(graph[i].getMZRatio() - graph[j].getMZRatio()); + e.sourcecharge = 1; + e.targetcharge = 1; + e.targetintensity = graph[i].getIntensity(); + e.composition = to_string(e.brickid); + e.endmodifID = 0; + e.middlemodifID = 0; + graph[j].insertEdge(e); + edgescreated++; + + cBrick b; + b.setName(to_string(e.massdifference)); + b.setAcronyms(to_string(e.massdifference)); + string s = "unknown"; + b.setReferences(s); + b.setSummary(s); + b.setMass(e.massdifference); + b.setComposition(to_string(e.brickid), false); + b.setArtificial(true); + bricksdatabasewithcombinations.push_back(b); + } + //} + + } + + *os << "ok" << endl; + *os << "Edges created: " << edgescreated << endl; + *os << "Number of edges: " << getNumberOfEdges() << endl << endl; + + return 0; +} + + +int cDeNovoGraph::removePathsWhichCanBeSubstitutedByLongerPath(bool& terminatecomputation) { + *os << "Removing edges forming paths which can be substituted by longer paths... "; + int edgesremoved = 0; + int j; + + for (int i = startnode; i < (int)graph.size(); i++) { + + if (terminatecomputation) { + return -1; + } + + //*os << i << " "; + j = 0; + 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 << " "; + graph[i].removeEdge(j); + edgesremoved++; + } + else { + j++; + } + } + } + *os << "ok" << endl; + *os << "Edges removed: " << edgesremoved << endl; + *os << "Number of edges: " << getNumberOfEdges() << endl << endl; + + return 0; +} + + +void cDeNovoGraph::startGraphReader(cCandidateSet& candidates, bool& terminatecomputation) { + graphreaderthread = new cGraphReaderThread(); + graphreaderthread->initialize(graph, bricksdatabasewithcombinations, candidates, parameters, os, lastsystemnode, terminatecomputation); + os->connect(graphreaderthread, SIGNAL(finished()), os, SLOT(graphReaderFinished())); + os->setGraphReaderIsWorking(true); + graphreaderthread->start(); +} + + +int cDeNovoGraph::getNumberOfEdges() { + int edges = 0; + for (int i = 0; i < (int)graph.size(); i++) { + edges += (int)graph[i].size(); + } + return edges; +} + + +void cDeNovoGraph::printPaths(cMainThread* os, cDeNovoGraphNode& node, vector& path, vector& composition) { + string s; + + if (node.size() > 0) { + for (int i = 0; i < (int)node.size(); i++) { + if (node.getMZRatio() > 0) { + s = to_string(node.getMZRatio()); + s += " ("; + s += node[i].composition; + s += ")"; + path.push_back(s); + composition.push_back(node[i].composition); + } + printPaths(os, graph[node[i].targetnode], path, composition); + if (node.getMZRatio() > 0) { + path.pop_back(); + composition.pop_back(); + } + } + } + else { + s = to_string(node.getMZRatio()); + path.push_back(s); + + vector tmp; + cCandidate candidate(composition, tmp, 0, 0, 0, -1); + + *os << "bricks: " << getNumberOfBricks(candidate.getComposition()) << " edges: " << composition.size() << " composition: "; + *os << candidate.getComposition(); + *os << " path: "; + for (int i = 0; i < (int)path.size(); i++) { + *os << path[i]; + if (i < (int)path.size() - 1) { + *os << " -> "; + } + } + *os << endl; + + path.pop_back(); + } + +} + + +string cDeNovoGraph::printGraph() { + string s, s2; + string g = ""; + + for (int i = 0; i < (int)graph.size(); i++) { + + s = to_string(graph[i].getMZRatio()); + + if ((int)graph[i].size() > 0) { + g += "The node " + s + " with relative intensity " + to_string(graph[i].getIntensity()) + " has " + to_string(graph[i].size()) + " outgoing edge(s).
"; + } + else { + g += "The node " + s + " with relative intensity " + to_string(graph[i].getIntensity()) + " does not have any outgoing edge.
"; + } + + //g += "Possible annotations: "; + //g += graph[i].printAnnotations(); + //g += "\n"; + + for (int j = 0; j < (int)graph[i].size(); j++) { + s2 = to_string(graph[graph[i][j].targetnode].getMZRatio()); + g += s + "->" + s2 + " using brick(s): "; + if (graph[i][j].composition.compare("0") == 0) { + g += "none"; + } + else { + g += bricksdatabasewithcombinations.getAcronymName(graph[i][j].composition, true); + } + s2 = to_string(graph[i][j].ppmerror); + g += " (mass difference: " + to_string(graph[i][j].massdifference) + ", "; + g += "target intensity: " + to_string(graph[graph[i][j].targetnode].getIntensity()) + ", "; + g += "ppm error: " + s2 + ", "; + g += "source charge: " + to_string(graph[i][j].sourcecharge) + ", "; + g += "target charge: " + to_string(graph[i][j].targetcharge); + if ((parameters->peptidetype == branched) || (parameters->peptidetype == lasso)) { + if (graph[i][j].middlemodifID > 0) { + g += ", branch modification: " + parameters->searchedmodifications[graph[i][j].middlemodifID].name; + } + } + if (graph[i][j].endmodifID > 0) { + g += ", terminal modification: " + parameters->searchedmodifications[graph[i][j].endmodifID].name; + } + //g += graph[i][j].printSourceAnnotation(fragmentdefinitions); + //g += "->"; + //g += graph[i][j].printTargetAnnotation(fragmentdefinitions); + g += ")
"; + } + + g += "
"; + } + + //vector path; + //vector composition; + //printPaths(os,graph[0],path,composition); + + return g; +} + + +cDeNovoGraphNode& cDeNovoGraph::operator[](int position) { + return graph[position]; +} + + +void cDeNovoGraph::sortEdgesByPPMError() { + for (int i = 0; i < (int)graph.size(); i++) { + graph[i].sortEdgesByPPMError(); + } +} + + +void cDeNovoGraph::sortEdgesByTargetNodeIntensity() { + for (int i = 0; i < (int)graph.size(); i++) { + graph[i].sortEdgesByTargetNodeIntensity(); + } +} + + +cBricksDatabase* cDeNovoGraph::getBrickDatabaseWithCombinations() { + return &bricksdatabasewithcombinations; +} + diff --git a/CycloBranch/core/cDeNovoGraph.h b/CycloBranch/core/cDeNovoGraph.h new file mode 100644 index 0000000..92cadcb --- /dev/null +++ b/CycloBranch/core/cDeNovoGraph.h @@ -0,0 +1,185 @@ +/** + \file cDeNovoGraph.h + \brief The implementation of the de novo graph. +*/ + + +#ifndef _CDENOVOGRAPH_H +#define _CDENOVOGRAPH_H + +#include +#include +#include +#include + +#include "core/cParameters.h" +#include "core/cDeNovoGraphNode.h" +#include "core/cPeaksList.h" +#include "core/cBricksDatabase.h" +#include "core/cTheoreticalSpectrumList.h" +#include "parallel/cGraphReaderThread.h" + +class cMainThread; + + +using namespace std; + + +/** + \brief Compare two nodes. + \param node1 reference to the first node + \param node2 reference to the second node + \retval bool true when the mz ratio of the first node is smaller than the mz ratio of the second node +*/ +bool compareNodes(cDeNovoGraphNode& node1, cDeNovoGraphNode& node2); + + +/** + \brief The class implementing the de novo graph. +*/ +class cDeNovoGraph { + + cParameters* parameters; + vector graph; + cPeaksList sortedpeaklist; + cBricksDatabase bricksdatabasewithcombinations; + int lastsystemnode; + cMainThread* os; + int startnode; + + cGraphReaderThread* graphreaderthread; + + bool findPath(int sourcenodeid, int edgeid, int targetnodeid, string& composition, string brickspath, int maximumbricksincombination, int depth); + + // create vectors of edges from temporary unordered_sets + void createVectorsOfEdges(); + + // check whether a path leads to the precursor + bool finishInPrecursor(int currentnode, double cummass); + +public: + + /** + \brief The constructor. + */ + cDeNovoGraph(); + + + /** + \brief Initialize the graph. + \param os reference to the main thread of the application + \param parameters reference to program parameters + */ + void initialize(cMainThread& os, cParameters& parameters); + + + /** + \brief Create the graph. + \param terminatecomputation reference to a variable determining that the computation must be stopped + \retval int 0 = successfully finished, -1 computation terminated + */ + int createGraph(bool& terminatecomputation); + + + /** + \brief Remove edges which do not form a path finishing in the precursor. + \param terminatecomputation reference to a variable determining that the computation must be stopped + \retval int 0 = successfully finished, -1 computation terminated + */ + int removeEdgesFormingPathsNotFinishingInPrecursor(bool& terminatecomputation); + + + /** + \brief Remove edges which do not start from system nodes. + \param terminatecomputation reference to a variable determining that the computation must be stopped + \retval int 0 = successfully finished, -1 computation terminated + */ + int removeEdgesFormingPathsNotStartingFromFirstNode(bool& terminatecomputation); + + + /** + \brief Connect edges which do not form a path finishing in the precursor. + \param terminatecomputation reference to a variable determining that the computation must be stopped + \retval int 0 = successfully finished, -1 computation terminated + */ + int connectEdgesFormingPathsNotFinishingInPrecursor(bool& terminatecomputation); + + + /** + \brief Connect edges which do not start from system nodes. + \param terminatecomputation reference to a variable determining that the computation must be stopped + \retval int 0 = successfully finished, -1 computation terminated + */ + int connectEdgesFormingPathsNotStartingFromFirstNode(bool& terminatecomputation); + + + /** + \brief Remove paths which can be substituted by longer paths. + \param terminatecomputation reference to a variable determining that the computation must be stopped + \retval int 0 = successfully finished, -1 computation terminated + */ + int removePathsWhichCanBeSubstitutedByLongerPath(bool& terminatecomputation); + + + /** + \brief Start the graph reader. + \param candidates output set of candidates + \param terminatecomputation reference to a variable determining that the computation must be stopped + */ + void startGraphReader(cCandidateSet& candidates, bool& terminatecomputation); + + + /** + \brief Get the number of edges. + \retval int number of edges + */ + int getNumberOfEdges(); + + + /** + \brief Print all paths in the graph into a stream. + \param os pointer to the main thread of the application (stream, respectively). + \param node reference to a starting node + \param path reference to an auxiliary empty vector of strings + \param composition reference to an auxiliary empty vector of strings + */ + void printPaths(cMainThread* os, cDeNovoGraphNode& node, vector& path, vector& composition); + + + /** + \brief Print the graph to a string. + \retval string the printed graph + */ + string printGraph(); + + + /** + \brief Overloaded operator []. + \param position position of a node + \retval cDeNovoGraphNode reference to a node + */ + cDeNovoGraphNode& operator[](int position); + + + /** + \brief Sort edges by ppm error. + */ + void sortEdgesByPPMError(); + + + /** + \brief Sort edges by target node intensity. + */ + void sortEdgesByTargetNodeIntensity(); + + + /** + \brief Access to the database of bricks with combinations of bricks. + \retval cBricksDatabase pointer to a database of bricks + */ + cBricksDatabase* getBrickDatabaseWithCombinations(); + +}; + + +#endif \ No newline at end of file diff --git a/CycloBranch/core/cDeNovoGraphNode.cpp b/CycloBranch/core/cDeNovoGraphNode.cpp new file mode 100644 index 0000000..4c3b4d1 --- /dev/null +++ b/CycloBranch/core/cDeNovoGraphNode.cpp @@ -0,0 +1,128 @@ +#include "core/cDeNovoGraphNode.h" + + +void nodeEdge::store(ofstream& os) { + os.write((char *)&nodeid, sizeof(int)); + os.write((char *)&edgeid, sizeof(int)); +} + + +void nodeEdge::load(ifstream& is) { + is.read((char *)&nodeid, sizeof(int)); + is.read((char *)&edgeid, sizeof(int)); +} + + +bool operator == (cEdge const& a, cEdge const& b) { + return (a.targetnode == b.targetnode) && (a.brickid == b.brickid); +} + + +bool compareEdgesByPPMError(cEdge& a, cEdge& b) { + return (a.ppmerror < b.ppmerror); +} + + +bool compareEdgesByTargetNodeIntensityDesc(cEdge& a, cEdge& b) { + return (a.targetintensity > b.targetintensity); +} + + +cDeNovoGraphNode::cDeNovoGraphNode() { + clear(); +} + + +void cDeNovoGraphNode::clear() { + mzratio = 0; + intensity = 0; + ionannotation.clear(); + + for (int i = 0; i < fragmentIonTypeEnd; i++) + { + ionannotation[(fragmentIonType)i] = false; + } + + tempedges.clear(); + edges.clear(); +} + + +double cDeNovoGraphNode::getMZRatio() { + return mzratio; +} + + +void cDeNovoGraphNode::setMZRatio(double mzratio) { + this->mzratio = mzratio; +} + + +double cDeNovoGraphNode::getIntensity() { + return intensity; +} + + +void cDeNovoGraphNode::setIntensity(double intensity) { + this->intensity = intensity; +} + + +void cDeNovoGraphNode::insertTempEdge(cEdge& e) { + tempedges.insert(e); +} + + +void cDeNovoGraphNode::insertEdge(cEdge& e) { + edges.push_back(e); +} + + +void cDeNovoGraphNode::sortEdgesByPPMError() { + sort(edges.begin(), edges.end(), compareEdgesByPPMError); +} + + +void cDeNovoGraphNode::sortEdgesByTargetNodeIntensity() { + sort(edges.begin(), edges.end(), compareEdgesByTargetNodeIntensityDesc); +} + + +void cDeNovoGraphNode::createVectorOfEdges() { + edges.clear(); + while (tempedges.size() > 0) { + edges.push_back(*tempedges.begin()); + tempedges.erase(tempedges.begin()); + } +} + + +int cDeNovoGraphNode::size() { + return (int)edges.size(); +} + + +cEdge& cDeNovoGraphNode::operator[](int position) { + return edges[position]; +} + + +void cDeNovoGraphNode::removeEdge(int position) { + edges.erase(edges.begin() + position); +} + + +void cDeNovoGraphNode::clearEdges() { + edges.clear(); +} + + +void cDeNovoGraphNode::addIonAnnotation(fragmentIonType iontype) { + ionannotation[iontype] = true; +} + + +bool cDeNovoGraphNode::checkIonAnnotation(fragmentIonType iontype) { + return ionannotation[iontype]; +} + diff --git a/CycloBranch/core/cDeNovoGraphNode.h b/CycloBranch/core/cDeNovoGraphNode.h new file mode 100644 index 0000000..8ee33bd --- /dev/null +++ b/CycloBranch/core/cDeNovoGraphNode.h @@ -0,0 +1,321 @@ +/** + \file cDeNovoGraphNode.h + \brief The representation of a node in the de novo graph. +*/ + + +#ifndef _CDENOVOGRAPHNODE_H +#define _CDENOVOGRAPHNODE_H + +#include +#include +#include +#include + +#include "core/cFragmentIons.h" + +using namespace std; + + +/** + \brief An auxiliary structure to store relationship between a node and an edge. +*/ +struct nodeEdge { + + /** + \brief Id of a node. + */ + int nodeid; + + + /** + \brief Id of an edge. + */ + int edgeid; + + + /** + \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 The structure representing an outgoing edge from a node. +*/ +struct cEdge { + + /** + \brief Id of a target node. + */ + int targetnode; + + + /** + \brief Id of a brick. + */ + int brickid; + + + /** + \brief Error in ppm. + */ + double ppmerror; + + + /** + \brief A mass difference. + */ + double massdifference; + + + /** + \brief Charge of the source node. + */ + int sourcecharge; + + + /** + \brief Charge of the target node. + */ + int targetcharge; + + + /** + \brief Intensity of the target node. + */ + double targetintensity; + + + /** + \brief ids of bricks separated by '-'. + */ + string composition; + + + /** + \brief Id of a terminal modification (at the end of a spectrum). + */ + int endmodifID; + + + /** + \brief Id of a terminal modification of a branched peptide (in the middle of a spectrum). + */ + int middlemodifID; + + + /** + \brief The constructor. + */ + cEdge() { + clear(); + } + + + /** + \brief Clear the structure. + */ + void clear() { + targetnode = 0; + brickid = 0; + ppmerror = 0; + massdifference = 0; + sourcecharge = 1; + targetcharge = 1; + targetintensity = 0; + composition = ""; + endmodifID = 0; + middlemodifID = 0; + } + +}; + + +/** + \brief The structure defining a hash function of cEdge. +*/ +struct hash_cEdge { + + /** + \brief Hash an edge. + \param e reference to an edge + \retval size_t hashed edge + */ + size_t operator()(const cEdge& e) const { + return hash()(e.targetnode) ^ hash()(e.brickid); + } + +}; + + +/** + \brief Overloaded operator ==. + \param a first edge + \param b second edge + \retval bool true when edges are equal +*/ +bool operator == (cEdge const& a, cEdge const& b); + + +/** + \brief Compare edges by ppm error. + \param a first edge + \param b second edge + \retval bool true when \a a has smaller ppm error than \a b +*/ +bool compareEdgesByPPMError(cEdge& a, cEdge& b); + + +/** + \brief Compare edges by target node intensity. + \param a first edge + \param b second edge + \retval bool true when the target node of \a a has bigger intensity than the target node of \a b +*/ +bool compareEdgesByTargetNodeIntensityDesc(cEdge& a, cEdge& b); + + +/** + \brief The class representing a node in the de novo graph. +*/ +class cDeNovoGraphNode { + + double mzratio; + double intensity; + + unordered_set tempedges; + vector edges; + map ionannotation; + +public: + + + /** + \brief The constructor. + */ + cDeNovoGraphNode(); + + + /** + \brief Clear the class. + */ + void clear(); + + + /** + \brief Get the mz ratio of the node. + \retval double mz ratio + */ + double getMZRatio(); + + + /** + \brief Set the mz ratio of the node. + \param mzratio mz ratio + */ + void setMZRatio(double mzratio); + + + /** + \brief Get the intensity of the node. + \retval double intensity + */ + double getIntensity(); + + + /** + \brief Set the intensity of the node. + \param intensity intensity + */ + void setIntensity(double intensity); + + + /** + \brief Insert an edge into a temporary unordered set. + \param e reference to an edge + */ + void insertTempEdge(cEdge& e); + + + /** + \brief Insert an edge into a vector of edges. + \param e reference to an edge + */ + void insertEdge(cEdge& e); + + + /** + \brief Sort a vector of edges by ppm error. + */ + void sortEdgesByPPMError(); + + + /** + \brief Sort a vector of edges by target node intensity. + */ + void sortEdgesByTargetNodeIntensity(); + + + /** + \brief Create a vector of edges from an unordered set of temporary edges. + */ + void createVectorOfEdges(); + + + /** + \brief Get the number of edges. + \retval int number of edges + */ + int size(); + + + /** + \brief Overloaded operator []. + \param position position of an edge + \retval edge reference to an edge + */ + cEdge& operator[](int position); + + + /** + \brief Remove an edge + \param position position of removed edge + */ + void removeEdge(int position); + + + /** + \brief Clear edges. + */ + void clearEdges(); + + + /** + \brief Add ion annotation. + \param iontype type of fragment ion + */ + void addIonAnnotation(fragmentIonType iontype); + + + /** + \brief Check ion annotation. + \param iontype type of fragment ion + \retval bool true when the ion type was assigned to the node + */ + bool checkIonAnnotation(fragmentIonType iontype); + +}; + + +#endif \ No newline at end of file diff --git a/CycloBranch/core/cFragmentIons.cpp b/CycloBranch/core/cFragmentIons.cpp new file mode 100644 index 0000000..fe4c28b --- /dev/null +++ b/CycloBranch/core/cFragmentIons.cpp @@ -0,0 +1,514 @@ +#include "core/cFragmentIons.h" + + +cPeriodicTableMap::cPeriodicTableMap() { + table["H"] = H; + table["Li"] = Li; + table["Be"] = Be; + table["B"] = B; + table["C"] = C; + table["N"] = N; + table["O"] = O; + table["F"] = F; + table["Na"] = Na; + table["Mg"] = Mg; + table["Al"] = Al; + table["Si"] = Si; + table["P"] = P; + table["S"] = S; + table["Cl"] = Cl; + table["K"] = K; + table["Ca"] = Ca; + table["Sc"] = Sc; + table["Ti"] = Ti; + table["V"] = V; + table["Cr"] = Cr; + table["Mn"] = Mn; + table["Fe"] = Fe; + table["Co"] = Co; + table["Ni"] = Ni; + table["Cu"] = Cu; + table["Zn"] = Zn; + table["Se"] = Se; + table["Br"] = Br; + table["Mo"] = Mo; + table["I"] = I; +} + + +double &cPeriodicTableMap::operator[](string& element) { + return table[element]; +} + + +int cPeriodicTableMap::count(string& element) { + return (int)table.count(element); +} + + +double getMassFromResidueSummary(string& summary, bool& error, string& errormessage) { + if ((int)summary.size() == 0) { + return 0; + } + + regex rx; + rx = "^([A-Z][a-z]*((-[0-9]+)|([0-9]*))*)+$"; + + try { + if (!regex_search(summary, rx)) { + error = true; + errormessage = "Invalid summary: " + summary + ".\n\n"; + return 0; + } + } + catch (std::regex_error& e) { + error = true; + errormessage = "getMassFromResidueSummary: regex_search failed, error no. " + to_string((int)e.code()) + "\n"; + return 0; + } + + // calculate mass from summary + error = false; + errormessage = ""; + + cPeriodicTableMap map; + double sum = 0; + + string tmps; + tmps = summary[0]; + + int tmpc = 0; + + bool minus = false; + + for (int i = 1; i < (int)summary.size(); i++) { + + if ((summary[i] >= 'A') && (summary[i] <= 'Z')) { + if (map.count(tmps) > 0) { + if (tmpc == 0) { + sum += map[tmps]; + } + else { + sum += minus?-tmpc*map[tmps]:tmpc*map[tmps]; + } + //cout << tmps << " " << (minus?"-":"") << tmpc << endl; + } + else { + error = true; + errormessage = "Undefined atom name: " + tmps + ".\n\n"; + return 0; + } + + tmps = summary[i]; + tmpc = 0; + minus = false; + } + + if ((summary[i] >= 'a') && (summary[i] <= 'z')) { + tmps += summary[i]; + } + + if ((summary[i] >= '0') && (summary[i] <= '9')) { + tmpc *= 10; + tmpc += summary[i] - '0'; + } + + if (summary[i] == '-') { + minus = true; + } + + } + + // last element + if (map.count(tmps) > 0) { + if (tmpc == 0) { + sum += map[tmps]; + } + else { + sum += minus?-tmpc*map[tmps]:tmpc*map[tmps]; + } + //cout << tmps << " " << (minus?"-":"") << tmpc << endl; + } + else { + error = true; + errormessage = "Undefined atom name: " + tmps + ".\n\n"; + return 0; + } + + return sum; +} + + +double charge(double mass, int charge) { + return (mass + ((double)(charge - 1))*Hplus)/(double)charge; +} + + +double uncharge(double mass, int charge) { + return mass*(double)charge - ((double)(charge - 1))*Hplus; +} + + +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()); + + os.write((char *)&massdifference, sizeof(double)); + os.write((char *)&nterminal, sizeof(bool)); + os.write((char *)&cterminal, sizeof(bool)); + os.write((char *)&parent, sizeof(fragmentIonType)); +} + + +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()); + + is.read((char *)&massdifference, sizeof(double)); + is.read((char *)&nterminal, sizeof(bool)); + is.read((char *)&cterminal, sizeof(bool)); + is.read((char *)&parent, sizeof(fragmentIonType)); +} + + +cFragmentIons::cFragmentIons() { + recalculateFragments(false, false); +} + + +cFragmentIons::cFragmentIons(bool cyclicnterminus, bool cycliccterminus) { + recalculateFragments(cyclicnterminus, cycliccterminus); +} + + +fragmentDescription &cFragmentIons::operator[](fragmentIonType iontype) { + return fragmentions[iontype]; +} + + +void cFragmentIons::recalculateFragments(bool cyclicnterminus, bool cycliccterminus) { + + fragmentions.clear(); + + double nterminusshift = cyclicnterminus?-H2O:0; + double cterminusshift = cycliccterminus?-H2O:0; + + // initialize B-ion + fragmentions[b_ion].nterminal = true; + fragmentions[b_ion].cterminal = false; + fragmentions[b_ion].name = "B"; + fragmentions[b_ion].massdifference = B_ION + nterminusshift; + fragmentions[b_ion].parent = b_ion; + + // initialize B-H2O ion + fragmentions[b_ion_water_loss].nterminal = true; + fragmentions[b_ion_water_loss].cterminal = false; + fragmentions[b_ion_water_loss].name = "B*"; + fragmentions[b_ion_water_loss].massdifference = B_ION - H2O + nterminusshift; + fragmentions[b_ion_water_loss].parent = b_ion; + + // initialize B-NH3 ion + fragmentions[b_ion_ammonia_loss].nterminal = true; + fragmentions[b_ion_ammonia_loss].cterminal = false; + fragmentions[b_ion_ammonia_loss].name = "Bx"; + fragmentions[b_ion_ammonia_loss].massdifference = B_ION - NH3 + nterminusshift; + fragmentions[b_ion_ammonia_loss].parent = b_ion; + + // initialize B-H2O-NH3 ion + fragmentions[b_ion_water_and_ammonia_loss].nterminal = true; + fragmentions[b_ion_water_and_ammonia_loss].cterminal = false; + fragmentions[b_ion_water_and_ammonia_loss].name = "B*x"; + fragmentions[b_ion_water_and_ammonia_loss].massdifference = B_ION - H2O - NH3 + nterminusshift; + fragmentions[b_ion_water_and_ammonia_loss].parent = b_ion; + + // initialize A-ion + fragmentions[a_ion].nterminal = true; + fragmentions[a_ion].cterminal = false; + fragmentions[a_ion].name = "A"; + fragmentions[a_ion].massdifference = A_ION + nterminusshift; + fragmentions[a_ion].parent = b_ion; // ok + + // initialize A-H2O ion + fragmentions[a_ion_water_loss].nterminal = true; + fragmentions[a_ion_water_loss].cterminal = false; + fragmentions[a_ion_water_loss].name = "A*"; + fragmentions[a_ion_water_loss].massdifference = A_ION - H2O + nterminusshift; + fragmentions[a_ion_water_loss].parent = a_ion; + + // initialize A-NH3 ion + fragmentions[a_ion_ammonia_loss].nterminal = true; + fragmentions[a_ion_ammonia_loss].cterminal = false; + fragmentions[a_ion_ammonia_loss].name = "Ax"; + fragmentions[a_ion_ammonia_loss].massdifference = A_ION - NH3 + nterminusshift; + fragmentions[a_ion_ammonia_loss].parent = a_ion; + + // initialize A-H2O-NH3 ion + fragmentions[a_ion_water_and_ammonia_loss].nterminal = true; + fragmentions[a_ion_water_and_ammonia_loss].cterminal = false; + fragmentions[a_ion_water_and_ammonia_loss].name = "A*x"; + fragmentions[a_ion_water_and_ammonia_loss].massdifference = A_ION - H2O - NH3 + nterminusshift; + fragmentions[a_ion_water_and_ammonia_loss].parent = a_ion; + + // initialize Y ion + fragmentions[y_ion].nterminal = false; + fragmentions[y_ion].cterminal = true; + fragmentions[y_ion].name = "Y"; + fragmentions[y_ion].massdifference = Y_ION + cterminusshift; + fragmentions[y_ion].parent = y_ion; + + // initialize Y-H2O ion + fragmentions[y_ion_water_loss].nterminal = false; + fragmentions[y_ion_water_loss].cterminal = true; + fragmentions[y_ion_water_loss].name = "Y*"; + fragmentions[y_ion_water_loss].massdifference = Y_ION - H2O + cterminusshift; + fragmentions[y_ion_water_loss].parent = y_ion; + + // initialize Y-NH3 ion + fragmentions[y_ion_ammonia_loss].nterminal = false; + fragmentions[y_ion_ammonia_loss].cterminal = true; + fragmentions[y_ion_ammonia_loss].name = "Yx"; + fragmentions[y_ion_ammonia_loss].massdifference = Y_ION - NH3 + cterminusshift; + fragmentions[y_ion_ammonia_loss].parent = y_ion; + + // initialize Y-H2O-NH3 ion + fragmentions[y_ion_water_and_ammonia_loss].nterminal = false; + fragmentions[y_ion_water_and_ammonia_loss].cterminal = true; + fragmentions[y_ion_water_and_ammonia_loss].name = "Y*x"; + fragmentions[y_ion_water_and_ammonia_loss].massdifference = Y_ION - H2O - NH3 + cterminusshift; + fragmentions[y_ion_water_and_ammonia_loss].parent = y_ion; + + // initialize precursor ion + fragmentions[precursor_ion].nterminal = false; + fragmentions[precursor_ion].cterminal = false; + fragmentions[precursor_ion].name = "M"; + fragmentions[precursor_ion].massdifference = PRECURSOR_ION + nterminusshift + cterminusshift; + fragmentions[precursor_ion].parent = precursor_ion; + + // initialize precursor ion - H2O + fragmentions[precursor_ion_water_loss].nterminal = false; + fragmentions[precursor_ion_water_loss].cterminal = false; + fragmentions[precursor_ion_water_loss].name = "M*"; + fragmentions[precursor_ion_water_loss].massdifference = PRECURSOR_ION - H2O + nterminusshift + cterminusshift; + fragmentions[precursor_ion_water_loss].parent = precursor_ion; + + // initialize precursor ion - NH3 + fragmentions[precursor_ion_ammonia_loss].nterminal = false; + fragmentions[precursor_ion_ammonia_loss].cterminal = false; + fragmentions[precursor_ion_ammonia_loss].name = "Mx"; + fragmentions[precursor_ion_ammonia_loss].massdifference = PRECURSOR_ION - NH3 + nterminusshift + cterminusshift; + fragmentions[precursor_ion_ammonia_loss].parent = precursor_ion; + + // initialize precursor ion - H2O - NH3 + fragmentions[precursor_ion_water_and_ammonia_loss].nterminal = false; + fragmentions[precursor_ion_water_and_ammonia_loss].cterminal = false; + fragmentions[precursor_ion_water_and_ammonia_loss].name = "M*x"; + fragmentions[precursor_ion_water_and_ammonia_loss].massdifference = PRECURSOR_ION - H2O - NH3 + nterminusshift + cterminusshift; + fragmentions[precursor_ion_water_and_ammonia_loss].parent = precursor_ion; + + // initialize precursor ion - CO + fragmentions[precursor_ion_co_loss].nterminal = false; + fragmentions[precursor_ion_co_loss].cterminal = false; + fragmentions[precursor_ion_co_loss].name = "M-CO"; + fragmentions[precursor_ion_co_loss].massdifference = PRECURSOR_ION - CO + nterminusshift + cterminusshift; + fragmentions[precursor_ion_co_loss].parent = precursor_ion; + + // initialize precursor ion - CO - H2O + fragmentions[precursor_ion_co_loss_water_loss].nterminal = false; + fragmentions[precursor_ion_co_loss_water_loss].cterminal = false; + fragmentions[precursor_ion_co_loss_water_loss].name = "M*-CO"; + fragmentions[precursor_ion_co_loss_water_loss].massdifference = PRECURSOR_ION - CO - H2O + nterminusshift + cterminusshift; + fragmentions[precursor_ion_co_loss_water_loss].parent = precursor_ion_co_loss; + + // initialize precursor ion - CO - NH3 + fragmentions[precursor_ion_co_loss_ammonia_loss].nterminal = false; + fragmentions[precursor_ion_co_loss_ammonia_loss].cterminal = false; + fragmentions[precursor_ion_co_loss_ammonia_loss].name = "Mx-CO"; + fragmentions[precursor_ion_co_loss_ammonia_loss].massdifference = PRECURSOR_ION - CO - NH3 + nterminusshift + cterminusshift; + fragmentions[precursor_ion_co_loss_ammonia_loss].parent = precursor_ion_co_loss; + + // initialize precursor ion - CO - H2O - NH3 + fragmentions[precursor_ion_co_loss_water_and_ammonia_loss].nterminal = false; + fragmentions[precursor_ion_co_loss_water_and_ammonia_loss].cterminal = false; + fragmentions[precursor_ion_co_loss_water_and_ammonia_loss].name = "M*x-CO"; + fragmentions[precursor_ion_co_loss_water_and_ammonia_loss].massdifference = PRECURSOR_ION - CO - H2O - NH3 + nterminusshift + cterminusshift; + fragmentions[precursor_ion_co_loss_water_and_ammonia_loss].parent = precursor_ion_co_loss; + + // initialize cyclic precursor ion + fragmentions[cyclic_precursor_ion].nterminal = false; + fragmentions[cyclic_precursor_ion].cterminal = false; + fragmentions[cyclic_precursor_ion].name = "M"; + fragmentions[cyclic_precursor_ion].massdifference = PRECURSOR_ION_CYCLIC; + fragmentions[cyclic_precursor_ion].parent = cyclic_precursor_ion; + + // initialize cyclic precursor ion - H2O + fragmentions[cyclic_precursor_ion_water_loss].nterminal = false; + fragmentions[cyclic_precursor_ion_water_loss].cterminal = false; + fragmentions[cyclic_precursor_ion_water_loss].name = "M*"; + fragmentions[cyclic_precursor_ion_water_loss].massdifference = PRECURSOR_ION_CYCLIC - H2O; + fragmentions[cyclic_precursor_ion_water_loss].parent = cyclic_precursor_ion; + + // initialize cyclic precursor ion - NH3 + fragmentions[cyclic_precursor_ion_ammonia_loss].nterminal = false; + fragmentions[cyclic_precursor_ion_ammonia_loss].cterminal = false; + fragmentions[cyclic_precursor_ion_ammonia_loss].name = "Mx"; + fragmentions[cyclic_precursor_ion_ammonia_loss].massdifference = PRECURSOR_ION_CYCLIC - NH3; + fragmentions[cyclic_precursor_ion_ammonia_loss].parent = cyclic_precursor_ion; + + // initialize cyclic precursor ion - H2O - NH3 + fragmentions[cyclic_precursor_ion_water_and_ammonia_loss].nterminal = false; + fragmentions[cyclic_precursor_ion_water_and_ammonia_loss].cterminal = false; + fragmentions[cyclic_precursor_ion_water_and_ammonia_loss].name = "M*x"; + fragmentions[cyclic_precursor_ion_water_and_ammonia_loss].massdifference = PRECURSOR_ION_CYCLIC - H2O - NH3; + fragmentions[cyclic_precursor_ion_water_and_ammonia_loss].parent = cyclic_precursor_ion; + + // initialize cyclic precursor ion - CO + fragmentions[cyclic_precursor_ion_co_loss].nterminal = false; + fragmentions[cyclic_precursor_ion_co_loss].cterminal = false; + fragmentions[cyclic_precursor_ion_co_loss].name = "M-CO"; + fragmentions[cyclic_precursor_ion_co_loss].massdifference = PRECURSOR_ION_CYCLIC - CO; + fragmentions[cyclic_precursor_ion_co_loss].parent = cyclic_precursor_ion; + + // initialize cyclic precursor ion - CO - H2O + fragmentions[cyclic_precursor_ion_co_loss_water_loss].nterminal = false; + fragmentions[cyclic_precursor_ion_co_loss_water_loss].cterminal = false; + fragmentions[cyclic_precursor_ion_co_loss_water_loss].name = "M*-CO"; + fragmentions[cyclic_precursor_ion_co_loss_water_loss].massdifference = PRECURSOR_ION_CYCLIC - CO - H2O; + fragmentions[cyclic_precursor_ion_co_loss_water_loss].parent = cyclic_precursor_ion_co_loss; + + // initialize cyclic precursor ion - CO - NH3 + fragmentions[cyclic_precursor_ion_co_loss_ammonia_loss].nterminal = false; + fragmentions[cyclic_precursor_ion_co_loss_ammonia_loss].cterminal = false; + fragmentions[cyclic_precursor_ion_co_loss_ammonia_loss].name = "Mx-CO"; + fragmentions[cyclic_precursor_ion_co_loss_ammonia_loss].massdifference = PRECURSOR_ION_CYCLIC - CO - NH3; + fragmentions[cyclic_precursor_ion_co_loss_ammonia_loss].parent = cyclic_precursor_ion_co_loss; + + // initialize cyclic precursor ion - CO - H2O - NH3 + fragmentions[cyclic_precursor_ion_co_loss_water_and_ammonia_loss].nterminal = false; + fragmentions[cyclic_precursor_ion_co_loss_water_and_ammonia_loss].cterminal = false; + fragmentions[cyclic_precursor_ion_co_loss_water_and_ammonia_loss].name = "M*x-CO"; + fragmentions[cyclic_precursor_ion_co_loss_water_and_ammonia_loss].massdifference = PRECURSOR_ION_CYCLIC - CO - H2O - NH3; + fragmentions[cyclic_precursor_ion_co_loss_water_and_ammonia_loss].parent = cyclic_precursor_ion_co_loss; + + // initialize MS N-terminal ion H+ + fragmentions[ms_nterminal_ion_hplus].nterminal = true; + fragmentions[ms_nterminal_ion_hplus].cterminal = false; + fragmentions[ms_nterminal_ion_hplus].name = "N_H+"; + fragmentions[ms_nterminal_ion_hplus].massdifference = H2O + Hplus; + fragmentions[ms_nterminal_ion_hplus].parent = ms_nterminal_ion_hplus; + + // initialize MS N-terminal ion Na+ + fragmentions[ms_nterminal_ion_naplus].nterminal = true; + fragmentions[ms_nterminal_ion_naplus].cterminal = false; + fragmentions[ms_nterminal_ion_naplus].name = "N_Na+"; + fragmentions[ms_nterminal_ion_naplus].massdifference = H2O + Naplus; + fragmentions[ms_nterminal_ion_naplus].parent = ms_nterminal_ion_naplus; + + // initialize MS N-terminal ion K+ + fragmentions[ms_nterminal_ion_kplus].nterminal = true; + fragmentions[ms_nterminal_ion_kplus].cterminal = false; + fragmentions[ms_nterminal_ion_kplus].name = "N_K+"; + fragmentions[ms_nterminal_ion_kplus].massdifference = H2O + Kplus; + fragmentions[ms_nterminal_ion_kplus].parent = ms_nterminal_ion_kplus; + + // initialize MS C-terminal ion H+ + fragmentions[ms_cterminal_ion_hplus].nterminal = false; + fragmentions[ms_cterminal_ion_hplus].cterminal = true; + fragmentions[ms_cterminal_ion_hplus].name = "C_H+"; + fragmentions[ms_cterminal_ion_hplus].massdifference = H2O + Hplus; + fragmentions[ms_cterminal_ion_hplus].parent = ms_cterminal_ion_hplus; + + // initialize MS C-terminal ion Na+ + fragmentions[ms_cterminal_ion_naplus].nterminal = false; + fragmentions[ms_cterminal_ion_naplus].cterminal = true; + fragmentions[ms_cterminal_ion_naplus].name = "C_Na+"; + fragmentions[ms_cterminal_ion_naplus].massdifference = H2O + Naplus; + fragmentions[ms_cterminal_ion_naplus].parent = ms_cterminal_ion_naplus; + + // initialize MS C-terminal ion K+ + fragmentions[ms_cterminal_ion_kplus].nterminal = false; + fragmentions[ms_cterminal_ion_kplus].cterminal = true; + fragmentions[ms_cterminal_ion_kplus].name = "C_K+"; + fragmentions[ms_cterminal_ion_kplus].massdifference = H2O + Kplus; + fragmentions[ms_cterminal_ion_kplus].parent = ms_cterminal_ion_kplus; + + // initialize B-2H ion + //fragmentions[b_ion_2H_loss].nterminal = true; + //fragmentions[b_ion_2H_loss].cterminal = false; + //fragmentions[b_ion_2H_loss].name = "-2HB"; + //fragmentions[b_ion_2H_loss].massdifference = B_ION - 2 * H; + +} + + +void cFragmentIons::store(ofstream& os) { + int size; + + size = (int)fragmentions.size(); + os.write((char *)&size, sizeof(int)); + for (map::iterator it = fragmentions.begin(); it != fragmentions.end(); ++it) { + os.write((char *)&it->first, sizeof(fragmentIonType)); + os.write((char *)&it->second, sizeof(fragmentDescription)); + } +} + + +void cFragmentIons::load(ifstream& is) { + int size; + fragmentIonType iontype; + fragmentDescription description; + + is.read((char *)&size, sizeof(int)); + fragmentions.clear(); + for (int i = 0; i < size; i++) { + is.read((char *)&iontype, sizeof(fragmentIonType)); + is.read((char *)&description, sizeof(fragmentDescription)); + fragmentions[iontype] = description; + } +} + + +void initializeFragmentIonsForDeNovoGraphOfCyclicPeptides(vector& fragmentions) { + fragmentions.push_back(b_ion); +} + + +void initializeFragmentIonsForDeNovoGraphOfLinearPeptides(vector& fragmentions) { + fragmentions.push_back(y_ion); + fragmentions.push_back(b_ion); + fragmentions.push_back(precursor_ion); +} + + +void initializeFragmentIonsForDeNovoGraphOfTPeptides(vector& fragmentions) { + fragmentions.push_back(y_ion); + fragmentions.push_back(b_ion); + fragmentions.push_back(precursor_ion); +} + + +void initializeFragmentIonsForDeNovoGraphOfLassoPeptides(vector& fragmentions) { + fragmentions.push_back(b_ion); + //fragmentions.push_back(y_ion); +} + + +void initializeFragmentIonsForDeNovoGraphOfLinearPolysaccharide(vector& fragmentions) { + fragmentions.push_back(ms_nterminal_ion_hplus); + //fragmentions.push_back(ms_cterminal_ion_hplus); + fragmentions.push_back(precursor_ion); +} + diff --git a/CycloBranch/core/cFragmentIons.h b/CycloBranch/core/cFragmentIons.h new file mode 100644 index 0000000..446d47a --- /dev/null +++ b/CycloBranch/core/cFragmentIons.h @@ -0,0 +1,395 @@ +/** + \file cFragmentIons.h + \brief Basic definitions of fragment ions occurring in the mass spectra. +*/ + + +#ifndef _CFRAGMENTIONS_H +#define _CFRAGMENTIONS_H + +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; + + +// monoisotopic masses +const double Hplus = 1.00727645; +const double Naplus = 22.989222; +const double Kplus = 38.963158; +const double H = 1.0078250321; +const double Li = 7.016004; +const double Be = 9.012182; +const double B = 11.009306; +const double C = 12.0; +const double N = 14.0030740052; +const double O = 15.9949146221; +const double F = 18.998404; +const double Na = 22.989771; +const double Mg = 23.985043; +const double Al = 26.981539; +const double Si = 27.976927; +const double P = 30.97376151; +const double S = 31.97207069; +const double Cl = 34.968853; +const double K = 38.963707; +const double Ca = 39.962589; +const double Sc = 44.95591; +const double Ti = 47.947948; +const double V = 50.943962; +const double Cr = 51.940514; +const double Mn = 54.938049; +const double Fe = 55.93494; +const double Co = 58.933201; +const double Ni = 57.935349; +const double Cu = 62.9296; +const double Zn = 63.929146; +const double Se = 79.916519; +const double Br = 78.918327; +const double Mo = 97.905411; +const double I = 126.904457; + + +/** + \brief The class representing a periodic table. +*/ +class cPeriodicTableMap { + + map table; + +public: + + + /** + \brief The constructor. + */ + cPeriodicTableMap(); + + + /** + \brief Overloaded operator []. + \param element reference to a string with a name of an element + \retval double mass of an element + */ + double &operator[](string& element); + + + /** + \brief Check whether an element occurs in the table. + \param element reference to a string with a name of an element + \retval int 1 when element is presented in the table, 0 otherwise + */ + int count(string& element); + +}; + + +/** + \brief Compute mass from summary molecular formula. + \param summary reference to a string with summary molecular formula + \param error reference to an output boolean value; when the value is true, an error occurred + \param errormessage reference to an output string value; filled when an error occurred + \retval double mass corresponding to the formula +*/ +double getMassFromResidueSummary(string& summary, bool& error, string& errormessage); + + +const double H2O = 2 * H + O; +const double NH3 = 3 * H + N; +const double CO = C + O; + +const double A_ION = Hplus - C - O; +const double B_ION = Hplus; +const double C_ION = Hplus + NH3; +const double X_ION = Hplus + 2 * O + C; +const double Y_ION = Hplus + H2O; +const double Z_ION = Hplus + O - N - H; + +const double PRECURSOR_ION = Hplus + H2O; +const double PRECURSOR_ION_CYCLIC = Hplus; + + +/** + \brief The types of peptides supported by the application. +*/ +enum peptideType { + linear = 0, + cyclic = 1, + branched = 2, + lasso = 3, + linearpolysaccharide = 4 +}; + + +/** + \brief Register peptideType by Qt. +*/ +Q_DECLARE_METATYPE(peptideType); + + +/** + \brief Convert single charged mz ratio to multiple charged mz ratio. + \param mass single charged mz ratio + \param charge new charge + \retval double multiple charged mzratio +*/ +double charge(double mass, int charge); + + +/** + \brief Convert multiple charged mz ratio to single charged mz ratio. + \param mass multiple charged mz ratio + \param charge old charge + \retval double single charged mzratio +*/ +double uncharge(double mass, int charge); + + +/** + \brief The types of supported fragment ions. +*/ +enum fragmentIonType { + b_ion = 0, + b_ion_water_loss = 1, + b_ion_ammonia_loss = 2, + b_ion_water_and_ammonia_loss = 3, + a_ion = 4, + a_ion_water_loss = 5, + a_ion_ammonia_loss = 6, + a_ion_water_and_ammonia_loss = 7, + y_ion = 8, + y_ion_water_loss = 9, + y_ion_ammonia_loss = 10, + y_ion_water_and_ammonia_loss = 11, + precursor_ion = 12, + precursor_ion_water_loss = 13, + precursor_ion_ammonia_loss = 14, + precursor_ion_water_and_ammonia_loss = 15, + precursor_ion_co_loss = 16, + precursor_ion_co_loss_water_loss = 17, + precursor_ion_co_loss_ammonia_loss = 18, + precursor_ion_co_loss_water_and_ammonia_loss = 19, + cyclic_precursor_ion = 20, + cyclic_precursor_ion_water_loss = 21, + cyclic_precursor_ion_ammonia_loss = 22, + cyclic_precursor_ion_water_and_ammonia_loss = 23, + cyclic_precursor_ion_co_loss = 24, + cyclic_precursor_ion_co_loss_water_loss = 25, + cyclic_precursor_ion_co_loss_ammonia_loss = 26, + cyclic_precursor_ion_co_loss_water_and_ammonia_loss = 27, + ms_nterminal_ion_hplus = 28, + ms_nterminal_ion_naplus = 29, + ms_nterminal_ion_kplus = 30, + ms_cterminal_ion_hplus = 31, + ms_cterminal_ion_naplus = 32, + ms_cterminal_ion_kplus = 33, + //b_ion_2H_loss = 34, + fragmentIonTypeEnd +}; + + +/** + \brief Register vector by Qt. +*/ +Q_DECLARE_METATYPE(vector); + + +/** + \brief The structure for a detailed definition of a fragment ion type. +*/ +struct fragmentDescription { + + /** + \brief Name of the fragment. + */ + string name; + + + /** + \brief Summary formula of the fragment. + */ + string summary; + + + /** + \brief Mass difference of the fragment. + */ + double massdifference; + + + /** + \brief True when the fragment is N-terminal. + */ + bool nterminal; + + + /** + \brief True when the fragment is C-terminal. + */ + bool cterminal; + + + /** + \brief Parent fragment type. + */ + fragmentIonType parent; + + + /** + \brief The default constructor. + */ + fragmentDescription() { + name = ""; + summary = ""; + massdifference = 0; + nterminal = false; + cterminal = false; + parent = fragmentIonTypeEnd; + } + + + /** + \brief The constructor. + \param name name of the fragment + \param massdifference mass difference of the fragment + \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 parent parent fragment type + */ + fragmentDescription(string name, double massdifference, string summary, bool nterminal, bool cterminal, fragmentIonType parent = fragmentIonTypeEnd) { + this->name = name; + this->massdifference = massdifference; + this->summary = summary; + this->nterminal = nterminal; + this->cterminal = cterminal; + this->parent = parent; + } + + + /** + \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 Register vector by Qt. +*/ +Q_DECLARE_METATYPE(vector); + + +/** + \brief The detailed definitions of all supported fragment ion types. +*/ +class cFragmentIons { + + map fragmentions; + +public: + + + /** + \brief The constructor. + */ + cFragmentIons(); + + + /** + \brief The constructor. + \param cyclicnterminus true when the N-terminus of a linear peptide is cyclized + \param cycliccterminus true when the C-terminus of a linear peptide is cyclized + */ + cFragmentIons(bool cyclicnterminus, bool cycliccterminus); + + + /** + \brief Overloaded operator []. + \param iontype type of fragment ion + \retval fragmentDescription reference to a structure with detailed information about the fragment ion + */ + fragmentDescription &operator[](fragmentIonType iontype); + + + /** + \brief Recalculate all fragment ion types. + \param cyclicnterminus true when the N-terminus of a linear peptide is cyclized + \param cycliccterminus true when the C-terminus of a linear peptide is cyclized + */ + void recalculateFragments(bool cyclicnterminus, bool cycliccterminus); + + + /** + \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 Register cFragmentIons by Qt. +*/ +Q_DECLARE_METATYPE(cFragmentIons); + + +/** + \brief Initialize fragment ion types for the de novo graph of cyclic peptides. + \param fragmentions reference to a vector of fragment ion types +*/ +void initializeFragmentIonsForDeNovoGraphOfCyclicPeptides(vector& fragmentions); + + +/** + \brief Initialize fragment ion types for the de novo graph of linear peptides. + \param fragmentions reference to a vector of fragment ion types +*/ +void initializeFragmentIonsForDeNovoGraphOfLinearPeptides(vector& fragmentions); + + +/** + \brief Initialize fragment ion types for the de novo graph of branched peptides. + \param fragmentions reference to a vector of fragment ion types +*/ +void initializeFragmentIonsForDeNovoGraphOfTPeptides(vector& fragmentions); + + +/** + \brief Initialize fragment ion types for the de novo graph of lasso peptides. + \param fragmentions reference to a vector of fragment ion types +*/ +void initializeFragmentIonsForDeNovoGraphOfLassoPeptides(vector& fragmentions); + + +/** + \brief Initialize fragment ion types for the de novo graph of a custom linear type. + \param fragmentions reference to a vector of fragment ion types +*/ +void initializeFragmentIonsForDeNovoGraphOfLinearPolysaccharide(vector& fragmentions); + + +#endif \ No newline at end of file diff --git a/CycloBranch/core/cParameters.cpp b/CycloBranch/core/cParameters.cpp new file mode 100644 index 0000000..3898c81 --- /dev/null +++ b/CycloBranch/core/cParameters.cpp @@ -0,0 +1,645 @@ +#include "core/cParameters.h" + +#include "gui/cMainThread.h" + + +cParameters::cParameters() { + clear(); +} + + +void cParameters::clear() { + os = 0; + fragmentdefinitions.recalculateFragments(false, false); + peptidetype = linear; + peaklistfilename = ""; + peaklist.clear(); + precursormass = 0; + precursormasserrortolerance = 5; + precursorcharge = 1; + fragmentmasserrortolerance = 5; + masserrortolerancefordeisotoping = 5; + minimumrelativeintensitythreshold = 0; + minimummz = 150; + bricksdatabasefilename = ""; + bricksdatabase.clear(); + maximumbricksincombinationbegin = 3; + maximumbricksincombinationmiddle = 2; + maximumbricksincombinationend = 3; + maximumbricksincombination = max(max(maximumbricksincombinationbegin, maximumbricksincombinationmiddle), maximumbricksincombinationend); + maximumcumulativemass = 0; + generatebrickspermutations = true; + maximumnumberofthreads = 1; + mode = 0; + scoretype = b_ions; + clearhitswithoutparent = false; + cyclicnterminus = false; + cycliccterminus = false; + enablescrambling = false; + hitsreported = 1000; + sequencetag = ""; + originalsequencetag = ""; + searchedsequence = ""; + originalsearchedsequence = ""; + searchedsequenceNtermmodif = ""; + searchedsequenceCtermmodif = ""; + searchedsequenceTmodif = ""; + maximumnumberofcandidates = 50000; + blindedges = 2; + + searchedmodifications.clear(); + searchedmodifications.push_back(fragmentDescription("", 0, "", true, true)); + + fragmentionsfordenovograph.clear(); + fragmentionsfortheoreticalspectra.clear(); +} + + +int cParameters::checkAndPrepare() { + + bool error = false; + string errormessage = ""; + ifstream peakliststream; + ifstream bricksdatabasestream; + regex rx; + ePeakListFileFormat peaklistfileformat; + string s; + + + // peaklist check + if (!error) { + if (peaklistfilename == "") { + error = true; + errormessage = "A peaklist is not specified."; + } + else { + peaklistfileformat = txt; + + try { + + 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][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; + } + + } + 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"; + } + + 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) { + 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; + } + } + peakliststream.close(); + } + } + } + + + // bricksdatabase check + if (!error) { + if (bricksdatabasefilename == "") { + error = true; + errormessage = "A database of bricks is not specified."; + } + else { + bricksdatabasestream.open(bricksdatabasefilename); + if (!bricksdatabasestream.good()) { + 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; + } + } + } + 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++) { + + 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"; + } + } + } + } + } + + } + } + + + // initialize fragment ions for de novo graph + fragmentionsfordenovograph.clear(); + if (!error) { + switch (peptidetype) + { + case linear: + initializeFragmentIonsForDeNovoGraphOfLinearPeptides(fragmentionsfordenovograph); + break; + case cyclic: + initializeFragmentIonsForDeNovoGraphOfCyclicPeptides(fragmentionsfordenovograph); + break; + case branched: + initializeFragmentIonsForDeNovoGraphOfTPeptides(fragmentionsfordenovograph); + break; + case lasso: + initializeFragmentIonsForDeNovoGraphOfLassoPeptides(fragmentionsfordenovograph); + break; + case linearpolysaccharide: + initializeFragmentIonsForDeNovoGraphOfLinearPolysaccharide(fragmentionsfordenovograph); + break; + default: + error = true; + errormessage = "Undefined peptide type.\n\n"; + break; + } + } + + + // report errors and return + if (error) { + if (os) { + *os << endl << endl; + *os << "Error: " << errormessage.c_str() << endl; + *os << endl; + *os << endl; + } + return -1; + } + + + return 0; +} + + +string cParameters::printToString() { + string s = ""; + s += "Peptide Type: "; + switch (peptidetype) { + case linear: + s += "Linear\n"; + break; + case cyclic: + s += "Cyclic\n"; + break; + case branched: + s += "Branched\n"; + break; + case lasso: + s += "Lasso\n"; + break; + case linearpolysaccharide: + s += "Linear polysaccharide (beta version)\n"; + break; + default: + break; + } + s += "Peaklist File: " + peaklistfilename + "\n"; + s += "Precursor Mass: " + to_string(precursormass) + "\n"; + s += "Precursor Charge: " + to_string(precursorcharge) + "\n"; + s += "Precursor Mass Error Tolerance: " + to_string(precursormasserrortolerance) + "\n"; + s += "Fragment Mass Error Tolerance: " + to_string(fragmentmasserrortolerance) + "\n"; + s += "Fragment Mass Error Tolerance for Deisotoping: " + to_string(masserrortolerancefordeisotoping) + "\n"; + s += "Minimum Threshold of Relative Intensity: " + to_string(minimumrelativeintensitythreshold) + "\n"; + s += "Minimum m/z Ratio: " + to_string(minimummz) + "\n"; + s += "Brick Database File: " + bricksdatabasefilename + "\n"; + s += "Maximum Number of Combined Blocks (start, middle, end): " + to_string(maximumbricksincombinationbegin) + ", " + to_string(maximumbricksincombinationmiddle) + ", " + to_string(maximumbricksincombinationend) + "\n"; + s += "Maximum Cumulative Mass of Blocks: " + to_string(maximumcumulativemass) + "\n"; + + s += "Generate Permutations of Combined Bricks: "; + s += generatebrickspermutations ? "on" : "off"; + s += "\n"; + + s += "N-terminal and C-terminal Modifications:\n"; + for (int i = 1; i < (int)searchedmodifications.size(); i++) { + s += searchedmodifications[i].name + ", " + to_string(searchedmodifications[i].massdifference) + ", "; + s += searchedmodifications[i].nterminal ? "N-terminal, " : "-, "; + s += searchedmodifications[i].cterminal ? "C-terminal" : "-"; + s += "\n"; + } + + s += "Mode: "; + switch (mode) { + case 0: + s += "De Novo Search Engine"; + break; + case 1: + s += "Compare Spectrum of Searched Sequence with Peaklist"; + break; + default: + break; + } + s += "\n"; + + s += "Maximum Number of Threads: " + to_string(maximumnumberofthreads) + "\n"; + + s += "Score Type: "; + switch (scoretype) { + case b_ions: + s += "Number of b-ions"; + break; + case b_ions_and_b_water_loss_ions: + s += "Number of b-ions + water loss b-ions"; + break; + case b_ions_and_b_ammonia_loss_ions: + s += "Number of b-ions + ammonia loss b-ions"; + break; + case y_ions_and_b_ions: + s += "Number of y-ions + b-ions (not for cyclic peptides)"; + break; + case y_ions: + s += "Number of y-ions (not for cyclic peptides)"; + break; + case weighted_intensity: + s += "Sum of relative intensities of matched peaks"; + break; + case matched_peaks: + s += "Number of matched peaks"; + break; + case matched_bricks: + s += "Number of matched bricks (cyclic peptides)"; + break; + default: + s += "undefined"; + break; + } + s += "\n"; + + s += "Maximum Number of Candidate Peptides Reported: " + to_string(hitsreported) + "\n"; + s += "Peptide Sequence Tag: " + originalsequencetag + "\n"; + + s += "Fragment Ion Types in Theoretical Spectra: "; + for (int i = 0; i < (int)fragmentionsfortheoreticalspectra.size(); i++) { + s += fragmentdefinitions[fragmentionsfortheoreticalspectra[i]].name; + if (i < (int)fragmentionsfortheoreticalspectra.size() - 1) { + s += ", "; + } + } + s += "\n"; + + s += "Remove Hits of Fragments without Hits of Parent Fragments: "; + s += clearhitswithoutparent ? "on" : "off"; + s += "\n"; + + s += "Cyclic N-terminus: "; + s += cyclicnterminus ? "on" : "off"; + s += "\n"; + + s += "Cyclic C-terminus: "; + s += cycliccterminus ? "on" : "off"; + s += "\n"; + + s += "Enable Scrambling: "; + s += enablescrambling ? "on" : "off"; + s += "\n"; + + s += "Action with Edges Forming Blind Paths: "; + switch (blindedges) { + case 0: + s += "none (you can see a complete de novo graph)"; + break; + case 1: + s += "remove (speed up the search)"; + break; + case 2: + s += "connect (allow detection of sequence tags)"; + break; + default: + break; + } + s += "\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"; + s += "T-Modification of Searched Peptide Sequence: " + searchedsequenceTmodif + "\n"; + + s += "\n"; + + return s; +} + + +void cParameters::setOutputStream(cMainThread& os) { + this->os = &os; +} + + +void cParameters::updateFragmentDefinitions() { + if (peptidetype == linear) { + fragmentdefinitions.recalculateFragments(cyclicnterminus, cycliccterminus); + } + else { + fragmentdefinitions.recalculateFragments(false, false); + } +} + + +void cParameters::store(ofstream& os) { + int size; + + fragmentdefinitions.store(os); + + os.write((char *)&peptidetype, sizeof(peptideType)); + + size = (int)peaklistfilename.size(); + os.write((char *)&size, sizeof(int)); + os.write(peaklistfilename.c_str(), peaklistfilename.size()); + + peaklist.store(os); + + os.write((char *)&precursormass, sizeof(double)); + os.write((char *)&precursormasserrortolerance, sizeof(double)); + os.write((char *)&precursorcharge, sizeof(int)); + os.write((char *)&fragmentmasserrortolerance, sizeof(double)); + os.write((char *)&masserrortolerancefordeisotoping, sizeof(double)); + 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()); + + bricksdatabase.store(os); + + os.write((char *)&maximumbricksincombinationbegin, sizeof(int)); + os.write((char *)&maximumbricksincombinationmiddle, sizeof(int)); + os.write((char *)&maximumbricksincombinationend, sizeof(int)); + os.write((char *)&maximumbricksincombination, sizeof(int)); + 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 *)&scoretype, sizeof(scoreType)); + os.write((char *)&clearhitswithoutparent, sizeof(bool)); + os.write((char *)&cyclicnterminus, sizeof(bool)); + os.write((char *)&cycliccterminus, sizeof(bool)); + 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()); + + os.write((char *)&maximumnumberofcandidates, sizeof(int)); + os.write((char *)&blindedges, sizeof(int)); + + size = (int)searchedmodifications.size(); + os.write((char *)&size, sizeof(int)); + for (int i = 0; i < (int)searchedmodifications.size(); i++) { + searchedmodifications[i].store(os); + } + + size = (int)fragmentionsfordenovograph.size(); + os.write((char *)&size, sizeof(int)); + for (int i = 0; i < (int)fragmentionsfordenovograph.size(); i++) { + os.write((char *)&fragmentionsfordenovograph[i], sizeof(fragmentIonType)); + } + + size = (int)fragmentionsfortheoreticalspectra.size(); + os.write((char *)&size, sizeof(int)); + for (int i = 0; i < (int)fragmentionsfortheoreticalspectra.size(); i++) { + os.write((char *)&fragmentionsfortheoreticalspectra[i], sizeof(fragmentIonType)); + } +} + + +void cParameters::load(ifstream& is) { + int size; + + os = 0; + + fragmentdefinitions.load(is); + + is.read((char *)&peptidetype, sizeof(peptideType)); + + is.read((char *)&size, sizeof(int)); + peaklistfilename.resize(size); + is.read(&peaklistfilename[0], peaklistfilename.size()); + + peaklist.load(is); + + is.read((char *)&precursormass, sizeof(double)); + is.read((char *)&precursormasserrortolerance, sizeof(double)); + is.read((char *)&precursorcharge, sizeof(int)); + is.read((char *)&fragmentmasserrortolerance, sizeof(double)); + is.read((char *)&masserrortolerancefordeisotoping, sizeof(double)); + 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()); + + bricksdatabase.load(is); + + is.read((char *)&maximumbricksincombinationbegin, sizeof(int)); + is.read((char *)&maximumbricksincombinationmiddle, sizeof(int)); + is.read((char *)&maximumbricksincombinationend, sizeof(int)); + is.read((char *)&maximumbricksincombination, sizeof(int)); + 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 *)&scoretype, sizeof(scoreType)); + is.read((char *)&clearhitswithoutparent, sizeof(bool)); + is.read((char *)&cyclicnterminus, sizeof(bool)); + is.read((char *)&cycliccterminus, sizeof(bool)); + 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()); + + is.read((char *)&maximumnumberofcandidates, sizeof(int)); + is.read((char *)&blindedges, sizeof(int)); + + is.read((char *)&size, sizeof(int)); + searchedmodifications.resize(size); + for (int i = 0; i < (int)searchedmodifications.size(); i++) { + searchedmodifications[i].load(is); + } + + is.read((char *)&size, sizeof(int)); + fragmentionsfordenovograph.resize(size); + for (int i = 0; i < (int)fragmentionsfordenovograph.size(); i++) { + is.read((char *)&fragmentionsfordenovograph[i], sizeof(fragmentIonType)); + } + + is.read((char *)&size, sizeof(int)); + fragmentionsfortheoreticalspectra.resize(size); + for (int i = 0; i < (int)fragmentionsfortheoreticalspectra.size(); i++) { + is.read((char *)&fragmentionsfortheoreticalspectra[i], sizeof(fragmentIonType)); + } +} + diff --git a/CycloBranch/core/cParameters.h b/CycloBranch/core/cParameters.h new file mode 100644 index 0000000..2680a99 --- /dev/null +++ b/CycloBranch/core/cParameters.h @@ -0,0 +1,337 @@ +/** + \file cParameters.h + \brief Definitions of program parameters. +*/ + + +#ifndef _CPARAMETERS_H +#define _CPARAMETERS_H + +#include +#include +#include "core/cPeaksList.h" +#include "core/cBricksDatabase.h" + +class cMainThread; + +using namespace std; + + +/** + \brief Peak list file formats supported by the application. +*/ +enum ePeakListFileFormat { + txt = 0, + mgf = 1, + mzML = 2, + mzXML = 3, + baf = 4 +}; + + +/** + \brief The class storing parameters of the application. +*/ +class cParameters { + + cMainThread* os; + +public: + + + /** + \brief Definitions of fragment ion types. + */ + cFragmentIons fragmentdefinitions; + + + /** + \brief The type of analyzed peptide. + */ + peptideType peptidetype; + + + /** + \brief A filename with a peak list. + */ + string peaklistfilename; + + + /** + \brief An internal structure representing a peak list. + */ + cPeaksList peaklist; + + + /** + \brief Precursor mass of the peptide. + */ + double precursormass; + + + /** + \brief Precursor mass error tolerance (ppm). + */ + double precursormasserrortolerance; + + + /** + \brief The charge of the precursor ion. + */ + int precursorcharge; + + + /** + \brief Fragment mass error tolerance (ppm). + */ + double fragmentmasserrortolerance; + + + /** + \brief Mass error tolerance for deisotoping. + */ + double masserrortolerancefordeisotoping; + + + /** + \brief Minimum relative intensity threshold. + */ + double minimumrelativeintensitythreshold; + + + /** + \brief Minimum mz. + */ + double minimummz; + + + /** + \brief A file name of a bricks database. + */ + string bricksdatabasefilename; + + + /** + \brief An internal structure representing a database of bricks. + */ + cBricksDatabase bricksdatabase; + + + /** + \brief The maximum number of bricks in combination (at the beginning of a spectrum). + */ + int maximumbricksincombinationbegin; + + + /** + \brief The maximum number of bricks in combination (in the middle of a spectrum). + */ + int maximumbricksincombinationmiddle; + + + /** + \brief The maximum number of bricks in combination (at the end of a spectrum). + */ + int maximumbricksincombinationend; + + + /** + \brief The global maximum number of bricks in combination (maximum from \a maximumbricksincombinationbegin, \a maximumbricksincombinationmiddle and \a maximumbricksincombinationend). + */ + int maximumbricksincombination; + + + /** + \brief The maximum cummulative mass of bricks. + */ + double maximumcumulativemass; + + + /** + \brief True when permutations of bricks are generated. + */ + bool generatebrickspermutations; + + + /** + \brief Maximum number of threads. + */ + int maximumnumberofthreads; + + + /** + \brief Program mode. + */ + int mode; + + + /** + \brief A type of score. + */ + scoreType scoretype; + + + /** + \brief True when matches of peaks which do not have parent peaks are removed. + */ + bool clearhitswithoutparent; + + + /** + \brief True when the N-terminus of a linear peptide is cyclized. + */ + bool cyclicnterminus; + + + /** + \brief True when the C-terminus of a linear peptide is cyclized. + */ + bool cycliccterminus; + + + /** + \brief True when the detection of scrambled ions is enabled. + */ + bool enablescrambling; + + + /** + \brief Maximum number of reported hits. + */ + int hitsreported; + + + /** + \brief A sequence tag. + */ + string sequencetag; + + + /** + \brief A copy of sequence tag. + */ + string originalsequencetag; + + + /** + \brief A searched sequence. + */ + string searchedsequence; + + + /** + \brief A copy of searched sequence. + */ + string originalsearchedsequence; + + + /** + \brief N-terminal modification of a searched peptide. + */ + string searchedsequenceNtermmodif; + + + /** + \brief C-terminal modification of a searched peptide. + */ + string searchedsequenceCtermmodif; + + + /** + \brief Terminal modification of a branch of searched branched peptide. + */ + string searchedsequenceTmodif; + + + /** + \brief Maximum number of peptide sequence candidates. + */ + int maximumnumberofcandidates; + + + /** + \brief The identifier of an action with edges forming blind paths. + */ + int blindedges; + + + /** + \brief A vector of searched N-terminal and C-terminal modifications. + */ + vector searchedmodifications; + + + /** + \brief A vector of fragment ion types generated in the de novo graph. + */ + vector fragmentionsfordenovograph; + + + /** + \brief A vector of fragment ion types generated in theoretical spectra. + */ + vector fragmentionsfortheoreticalspectra; + + + /** + \brief The constructor. + */ + cParameters(); + + + /** + \brief Clear the structure. + */ + void clear(); + + + /** + \brief Test restrictions of parameters and prepare some internal parameters. + \retval int -1 when an error occurred, 0 otherwise + */ + int checkAndPrepare(); + + + /** + \brief Print parameters to a string. + \retval string string with parameters + */ + string printToString(); + + + /** + \brief Set the ouput stream. + \param os reference to the main thread of the application (output stream) + */ + void setOutputStream(cMainThread& os); + + + /** + \brief Update definitions of fragment ions when \a cyclicnterminus or \a cycliccterminus have been changed. + */ + void updateFragmentDefinitions(); + + + /** + \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 Register cParameters by Qt. +*/ +Q_DECLARE_METATYPE(cParameters); + + +#endif \ No newline at end of file diff --git a/CycloBranch/core/cPeak.cpp b/CycloBranch/core/cPeak.cpp new file mode 100644 index 0000000..cf44ede --- /dev/null +++ b/CycloBranch/core/cPeak.cpp @@ -0,0 +1,108 @@ +#include "core/cPeak.h" + + +cPeak::cPeak() { + clear(); +} + + +void cPeak::clear() { + mzratio = 0; + intensity = 0; + description = ""; + matchdescription = ""; + iontype = fragmentIonTypeEnd; + matched = 0; + matchedid = -1; + charge = 1; + isotope = false; + removeme = false; + scrambled = false; + + rotationid = -1; + matchedrotations.clear(); + seriesid = -1; +} + + +bool cPeak::empty() { + if ((mzratio == 0) && (intensity == 0)) return true; + return false; +} + + +bool cPeak::hasMatchedRotation(int rotationid) { + for (int i = 0; i < (int)matchedrotations.size(); i++) { + if (rotationid == matchedrotations[i]) { + return true; + } + } + return false; +} + + +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()); + + os.write((char *)&iontype, sizeof(fragmentIonType)); + os.write((char *)&matched, sizeof(int)); + os.write((char *)&matchedid, sizeof(int)); + os.write((char *)&charge, sizeof(int)); + os.write((char *)&rotationid, sizeof(int)); + + size = (int)matchedrotations.size(); + os.write((char *)&size, sizeof(int)); + for (int i = 0; i < (int)matchedrotations.size(); i++) { + os.write((char *)&matchedrotations[i], sizeof(int)); + } + + os.write((char *)&seriesid, sizeof(int)); + os.write((char *)&isotope, sizeof(bool)); + os.write((char *)&removeme, sizeof(bool)); + os.write((char *)&scrambled, sizeof(bool)); +} + + +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()); + + is.read((char *)&iontype, sizeof(fragmentIonType)); + is.read((char *)&matched, sizeof(int)); + is.read((char *)&matchedid, sizeof(int)); + is.read((char *)&charge, sizeof(int)); + is.read((char *)&rotationid, sizeof(int)); + + is.read((char *)&size, sizeof(int)); + matchedrotations.resize(size); + for (int i = 0; i < (int)matchedrotations.size(); i++) { + is.read((char *)&matchedrotations[i], sizeof(int)); + } + + is.read((char *)&seriesid, sizeof(int)); + is.read((char *)&isotope, sizeof(bool)); + is.read((char *)&removeme, sizeof(bool)); + is.read((char *)&scrambled, sizeof(bool)); +} + diff --git a/CycloBranch/core/cPeak.h b/CycloBranch/core/cPeak.h new file mode 100644 index 0000000..b3e7be4 --- /dev/null +++ b/CycloBranch/core/cPeak.h @@ -0,0 +1,165 @@ +/** + \file cPeak.h + \brief The representation of a peak in a mass spectrum. +*/ + + +#ifndef _CPEAK_H +#define _CPEAK_H + +#include +#include +#include "core/cFragmentIons.h" + + +using namespace std; + + +/** + \brief The types of scores between an experimental and a theoretical spectrum. +*/ +enum scoreType { + b_ions = 0, + b_ions_and_b_water_loss_ions = 1, + b_ions_and_b_ammonia_loss_ions = 2, + y_ions_and_b_ions = 3, + y_ions = 4, + weighted_intensity = 5, + matched_peaks = 6, + matched_bricks = 7 +}; + + +/** + \brief A structure representing a peak in a mass spectrum. +*/ +struct cPeak { + + /** + \brief MZ ratio. + */ + double mzratio; + + + /** + \brief Intensity. + */ + double intensity; + + + /** + \brief Description of a peak. + */ + string description; + + + /** + \brief An extended description when the peak is matched. + */ + string matchdescription; + + + /** + \brief The type of a fragment ion corresponding to the peak. + */ + fragmentIonType iontype; + + + /** + \brief Number of matches of an experimental peak (when the peak is compared to a theoretical spectrum). + */ + int matched; + + + /** + \brief An order of an experimental peak which has been matched with a theoretical peak. + */ + int matchedid; + + + /** + \brief A charge of the peak. + */ + int charge; + + + /** + \brief Id of a rotation of a cyclic peptide or a permutation of a branched peptide which has been matched. + */ + int rotationid; + + + /** + \brief Vector of ids of rotations matched by an experimental peak. + */ + vector matchedrotations; + + + /** + \brief An order of a peak in a series (e.g., B_5 in a B series). + */ + int seriesid; + + + /** + \brief True when the peak is an isotope peak. + */ + bool isotope; + + + /** + \brief True when the peak should be removed. + */ + bool removeme; + + + /** + \brief True when the peak corresponds to a scrambled fragment ion. + */ + bool scrambled; + + + /** + \brief The constructor. + */ + cPeak(); + + + /** + \brief Clear the structure. + */ + void clear(); + + + /** + \brief Test whether the structure is empty. + \retval bool true when the structure is empty + */ + bool empty(); + + + /** + \brief Test whether the peak matches a rotation of a cyclic peptide. + \param rotationid id of a rotation of a cyclic peptide + \retval bool true when the peak matches the rotation + */ + bool hasMatchedRotation(int rotationid); + + + /** + \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/cPeaksList.cpp b/CycloBranch/core/cPeaksList.cpp new file mode 100644 index 0000000..55431ef --- /dev/null +++ b/CycloBranch/core/cPeaksList.cpp @@ -0,0 +1,537 @@ +#include "core/cPeaksList.h" +#include "gui/cMainThread.h" + + +bool comparePeakMasses(cPeak& a, cPeak& b) { + return (a.mzratio < b.mzratio); +} + + +bool comparePeakIntensitiesDesc(cPeak& a, cPeak& b) { + return (a.intensity > b.intensity); +} + + +bool isInPpmMassErrorTolerance(double experimentalmass, double theoreticalmass, double tolerance) { + double errortolerance = experimentalmass*tolerance*0.000001f; + return abs(experimentalmass - theoreticalmass) <= errortolerance; +} + + +double ppmError(double experimentalmass, double theoreticalmass) { + return abs(experimentalmass - theoreticalmass)/experimentalmass*1000000.0f; +} + + +cPeaksList::cPeaksList() { + clear(); +} + + +void cPeaksList::clear() { + peaks.clear(); +} + + +void cPeaksList::attach(cPeaksList& peaklist) { + peaks.insert(peaks.end(), peaklist.peaks.begin(), peaklist.peaks.end()); + /* + for (int i = 0; i < (int)peaklist.peaks.size(); i++) { + peaks.push_back(peaklist.peaks[i]); + } + */ +} + + +void cPeaksList::add(cPeak& peak) { + peaks.push_back(peak); +} + + +void cPeaksList::loadFromPlainTextStream(ifstream &stream) { + string s; + cPeak p; + size_t pos; + + while (stream.good()) { + getline(stream,s); + + // replaces commas with dots + pos = s.find(','); + while (pos != string::npos) { + s.replace(pos, 1, "."); + pos = s.find(','); + } + + // load a row + p.clear(); + sscanf_s(s.c_str(), "%lf\t%lf", &p.mzratio, &p.intensity); + if (!p.empty()) { + peaks.push_back(p); + } + } +} + + +void cPeaksList::loadFromBAFStream(ifstream &stream) { + string s; + cPeak p; + size_t pos; + + getline(stream,s); + + while (stream.good()) { + getline(stream,s); + + // replaces commas with dots + pos = s.find(','); + while (pos != string::npos) { + s.replace(pos, 1, "."); + pos = s.find(','); + } + + pos = s.find(':'); + if (pos != string::npos) { + s.replace(pos, 1, "\t"); + } + + // load a row + p.clear(); + sscanf_s(s.c_str(), "%lf\t%lf", &p.mzratio, &p.intensity); + if (!p.empty()) { + peaks.push_back(p); + } + } +} + + +void cPeaksList::loadFromMGFStream(ifstream &stream) { + string s; + cPeak p; + size_t pos; + + while (stream.good()) { + getline(stream,s); + if (strstr(s.c_str(),"BEGIN IONS")) { + break; + } + } + + while (stream.good()) { + getline(stream,s); + if (!strstr(s.c_str(),"=")) { + break; + } + } + + while (stream.good()) { + getline(stream,s); + if (s.size() > 0) { + break; + } + } + + while ((stream.good()) && !(strstr(s.c_str(),"END IONS"))) { + + // replaces commas with dots + pos = s.find(','); + while (pos != string::npos) { + s.replace(pos, 1, "."); + pos = s.find(','); + } + + // load a row + p.clear(); + sscanf_s(s.c_str(), "%lf %lf", &p.mzratio, &p.intensity); + if (!p.empty()) { + peaks.push_back(p); + } + + getline(stream,s); + } +} + + +int cPeaksList::size() { + return (int)peaks.size(); +} + + +string cPeaksList::print(bool htmlterminatelines) { + string s = ""; + + for (int i = 0; i < size(); i++) { + + if (peaks[i].description.compare("") != 0) { + s += peaks[i].description + " "; + } + + s += to_string(peaks[i].mzratio); + + if (peaks[i].intensity > 0) { + s += " "; + s += to_string(peaks[i].intensity); + } + + if (peaks[i].matchdescription.compare("") != 0) { + s += peaks[i].matchdescription + " "; + } + + if (htmlterminatelines) { + s += "
"; + } + else { + s += "\n"; + } + + } + + s += "Total peaks: " + to_string((int)peaks.size()) + "\n\n"; + return s; +} + + +void cPeaksList::sortbyMass(int limit) { + if (limit == -1) { + sort(peaks.begin(), peaks.end(), comparePeakMasses); + } + else { + sort(peaks.begin(), peaks.begin() + limit, comparePeakMasses); + } +} + + +int cPeaksList::normalizeIntenzity() { + double maximum = 0.0f; + for (int i = 0; i < (int)peaks.size(); i++) { + if (peaks[i].intensity > maximum) { + maximum = peaks[i].intensity; + } + } + if (maximum > 0) { + for (int i = 0; i < (int)peaks.size(); i++) { + peaks[i].intensity /= maximum; + peaks[i].intensity *= 100.0f; + } + } + else { + return -1; + } + return 0; +} + + +void cPeaksList::cropIntenzity(double minimumrelativeintensitythreshold) { + int i = 0; + while (i < (int)peaks.size()) { + if (peaks[i].intensity < minimumrelativeintensitythreshold) { + peaks.erase(peaks.begin()+i); + } + else { + i++; + } + } +} + + +void cPeaksList::cropMinimumMZRatio(double minimummz) { + while ((int)peaks.size() > 0) { + if (peaks[0].mzratio < minimummz) { + peaks.erase(peaks.begin()); + } + else { + break; + } + } +} + + +void cPeaksList::cropMaximumMZRatio(double maximummz) { + while ((int)peaks.size() > 0) { + if (peaks.back().mzratio > maximummz) { + peaks.erase(peaks.begin() + peaks.size() - 1); + } + else { + break; + } + } +} + + +cPeak& cPeaksList::operator[](int position) { + return peaks[position]; +} + + +void cPeaksList::resize(int size) { + peaks.resize(size); +} + + +double cPeaksList::getMinimumMZRatio() { + double minimum = DBL_MAX; + for (int i = 0; i < (int)peaks.size(); i++) { + if (peaks[i].mzratio < minimum) { + minimum = peaks[i].mzratio; + } + } + return minimum; +} + + +double cPeaksList::getMaximumMZRatio() { + double maximum = 0; + for (int i = 0; i < (int)peaks.size(); i++) { + if (peaks[i].mzratio > maximum) { + maximum = peaks[i].mzratio; + } + } + return maximum; +} + + +void cPeaksList::removeIsotopes(int maximumcharge, double fragmentmasserrortolerance, cMainThread* os) { + + if (os) { + *os << "Removed isotopes:" << endl; + } + + int pos, i; + for (i = 0; i < (int)peaks.size(); i++) { + peaks[i].isotope = false; + } + for (i = 0; i < (int)peaks.size(); i++) { + for (int j = 1; j <= maximumcharge; j++) { + pos = find(charge(peaks[i].mzratio + Hplus, j), fragmentmasserrortolerance); + if (pos != -1) { + if (peaks[pos].intensity < peaks[i].intensity) { + peaks[pos].isotope = true; + } + else { + peaks[i].isotope = true; + } + } + } + } + i = 0; + while (i < (int)peaks.size()) { + if (peaks[i].isotope) { + if (os) { + *os << peaks[i].mzratio << endl; + } + peaks.erase(peaks.begin()+i); + } + else { + i++; + } + } + + if (os) { + *os << endl; + } + +} + + +int cPeaksList::find(double mzratio, double fragmentmasserrortolerance) { + int left, right, middle; + for (int i = 0; i < (int)peaks.size(); i++) { + left = 0; + right = (int)peaks.size() - 1; + while (left <= right) { + middle = (left + right) / 2; + if (isInPpmMassErrorTolerance(mzratio, peaks[middle].mzratio, fragmentmasserrortolerance)) { + return middle; + } + if (mzratio < peaks[middle].mzratio) { + right = middle - 1; + } + else { + left = middle + 1; + } + } + } + return -1; +} + + +void cPeaksList::eraseAll(double mzratio) { + int left, right, middle; + for (int i = 0; i < (int)peaks.size(); i++) { + left = 0; + right = (int)peaks.size() - 1; + while (left <= right) { + middle = (left + right) / 2; + if (abs(mzratio - peaks[middle].mzratio) < 0.00000001) { + while ((middle > 0) && (abs(mzratio - peaks[middle - 1].mzratio) < 0.00000001)) { + middle--; + } + while ((peaks.size() > 0) && (middle < (int)peaks.size()) && (abs(mzratio - peaks[middle].mzratio) < 0.00000001)) { + peaks.erase(peaks.begin()+middle); + } + return; + } + if (mzratio < peaks[middle].mzratio) { + right = middle - 1; + } + else { + left = middle + 1; + } + } + } + return; +} + + +void cPeaksList::remove(int position) { + if (position < (int)peaks.size()) { + peaks.erase(peaks.begin() + position); + } +} + + +void cPeaksList::removeChargeVariants(int maximumcharge, double fragmentmasserrortolerance) { + if (maximumcharge == 1) { + return; + } + + sortbyMass(); + + double uncharged, charged; + for (int i = maximumcharge; i > 1; i--) { + for (int j = i - 1; j >= 1; j--) { + for (int k = 0; k < (int)peaks.size(); k++) { + if (peaks[k].removeme) { + continue; + } + + uncharged = uncharge(peaks[k].mzratio, i); + charged = charge(uncharged, j); + + for (int m = k + 1; m < (int)peaks.size(); m++) { + if (peaks[m].removeme) { + continue; + } + + if (isInPpmMassErrorTolerance(charged, peaks[m].mzratio, fragmentmasserrortolerance)) { + peaks[k].removeme = true; + break; + } + } + } + } + } + + removeObsolete(); + +} + + +void cPeaksList::removeNeutralLoss(double loss, int maximumcharge, double fragmentmasserrortolerance) { + + sortbyMass(); + + int found = -1; + for (int i = 1; i <= maximumcharge; i++) { + for (int j = 0; j < (int)peaks.size(); j++) { + found = find(peaks[j].mzratio + loss, fragmentmasserrortolerance); + if ((found != -1) && (peaks[found].intensity < peaks[j].intensity)) { + peaks[found].removeme = true; + } + } + } + + removeObsolete(); + +} + + +void cPeaksList::removeObsolete() { + + int i = 0; + while (i < (int)peaks.size()) { + if (peaks[i].removeme) { + //cout << peaks[i].mzratio << endl; + peaks.erase(peaks.begin()+i); + } + else { + i++; + } + } + +} + + +void cPeaksList::maxHighestPeaksInWindow(int maximumnumberofpeaksinwindow, double windowsize) { + + if ((peaks.size() == 0) || (maximumnumberofpeaksinwindow == 0) || (windowsize <= 0)) { + return; + } + + sortbyMass(); + + int wincount = (int)(peaks.back().mzratio/windowsize) + 1; + vector > windows; + windows.resize(wincount); + + // create windows of peaks + for (int i = 0; i < (int)peaks.size(); i++) { + windows[int(peaks[i].mzratio/windowsize)].push_back(peaks[i]); + } + + // crop windows + int peaksinwindow; + for (int i = 0; i < wincount; i++) { + sort(windows[i].begin(), windows[i].end(), comparePeakIntensitiesDesc); + peaksinwindow = min(maximumnumberofpeaksinwindow, (int)windows[i].size()); + windows[i].resize(peaksinwindow); + } + + // merge windows + peaks.clear(); + for (int i = 0; i < wincount; i++) { + peaks.insert(peaks.end(), windows[i].begin(), windows[i].end()); + } + + sortbyMass(); + +} + + +double cPeaksList::getMaximumIntensityFromMZInterval(double minmz, double maxmz) { + double intensity = 0; + for (int i = 0; i < (int)peaks.size(); i++) { + if ((peaks[i].mzratio < minmz) || (peaks[i].mzratio > maxmz)) { + continue; + } + if (peaks[i].intensity > intensity) { + intensity = peaks[i].intensity; + } + } + return intensity; +} + + +void cPeaksList::store(ofstream& os) { + int size; + + size = (int)peaks.size(); + os.write((char *)&size, sizeof(int)); + + for (int i = 0; i < (int)peaks.size(); i++) { + peaks[i].store(os); + } +} + + +void cPeaksList::load(ifstream& is) { + int size; + + is.read((char *)&size, sizeof(int)); + peaks.resize(size); + + for (int i = 0; i < (int)peaks.size(); i++) { + peaks[i].load(is); + } +} + diff --git a/CycloBranch/core/cPeaksList.h b/CycloBranch/core/cPeaksList.h new file mode 100644 index 0000000..1726347 --- /dev/null +++ b/CycloBranch/core/cPeaksList.h @@ -0,0 +1,285 @@ +/** + \file cPeaksList.h + \brief The representation of a peak list. +*/ + + +#ifndef _CPEAKSLIST_H +#define _CPEAKSLIST_H + +#include +#include +#include +#include +#include +#include "core/cPeak.h" + + +using namespace std; + + +class cMainThread; + + +/** + \brief Compare two peaks by mz ratio. + \param a first peak + \param b second peak + \retval bool true when the mz ratio of the peak \a a is lower than the mz ratio of the peak \a b +*/ +bool comparePeakMasses(cPeak& a, cPeak& b); + + +/** + \brief Compare two peaks by intensities. + \param a first peak + \param b second peak + \retval bool true when the intensity of the peak \a a is bigger than the intensity of the peak \a b +*/ +bool comparePeakIntensitiesDesc(cPeak& a, cPeak& b); + + +/** + \brief Check whether two masses are inside a ppm mass error tolerance. + \param experimentalmass first mass + \param theoreticalmass second mass + \param tolerance fragment mass error tolerance + \retval bool true when masses are inside a mass tolerance +*/ +bool isInPpmMassErrorTolerance(double experimentalmass, double theoreticalmass, double tolerance); + + +/** + \brief Compute a ppm error between two masses. + \param experimentalmass first mass + \param theoreticalmass second mass + \retval double ppm error +*/ +double ppmError(double experimentalmass, double theoreticalmass); + + +/** + \brief The class representing a peak list. +*/ +class cPeaksList { + + vector peaks; + +public: + + + /** + \brief The constructor. + */ + cPeaksList(); + + + /** + \brief Clear the peak list. + */ + void clear(); + + + /** + \brief Attach a peak list. + \param peaklist peaklist which will be attached + */ + void attach(cPeaksList& peaklist); + + + /** + \brief Add a peak. + \param peak peak which will be added + */ + void add(cPeak& peak); + + + /** + \brief Load the spectrum from a plain text stream (tab separated values m/z ratio and intensity). + \param stream source stream + */ + void loadFromPlainTextStream(ifstream &stream); + + + /** + \brief Load the spectrum from a .csv file converted from a .baf file by CompassXport. + \param stream source stream + */ + void loadFromBAFStream(ifstream &stream); + + + /** + \brief Load the spectrum from a .mgf file. + \param stream source stream + */ + void loadFromMGFStream(ifstream &stream); + + + /** + \brief The number of peaks. + \retval int number of peaks + */ + int size(); + + + /** + \brief Print the spectrum. + \param htmlterminatelines true when html line endings must used + \retval string string with a printed spectrum + */ + string print(bool htmlterminatelines = false); + + + /** + \brief Sort the peaks by mass. + \param limit sort first \a limit peaks only; if \a limit == -1 then all peaks are sorted + */ + void sortbyMass(int limit = -1); + + + /** + \brief Normalize intensities of peaks. + \retval int 0 == success, -1 == maximum intensity <= 0 + */ + int normalizeIntenzity(); + + + /** + \brief Crop relative intensities lower than a threshold. + \param minimumrelativeintensitythreshold minimum threshold of relative intensity + */ + void cropIntenzity(double minimumrelativeintensitythreshold); + + + /** + \brief Crop mz ratio lower than a threshold. + \param minimummz minimum threshold of mz ratio + */ + void cropMinimumMZRatio(double minimummz); + + + /** + \brief Crop mz ratio bigger than a threshold. + \param maximummz maximum threshold of mz ratio + */ + void cropMaximumMZRatio(double maximummz); + + + /** + \brief Overloaded operator []. + \param position position of a peak in the peak list + \retval cPeak reference to the peak + */ + cPeak& operator[](int position); + + + /** + \brief Resize the peak list. + \param size number of peaks + */ + void resize(int size); + + + /** + \brief Get the minimum mz ratio. + \retval double minimum mz ratio + */ + double getMinimumMZRatio(); + + + /** + \brief Get the maximum mz ratio. + \retval double maximum mz ratio + */ + double getMaximumMZRatio(); + + + /** + \brief Remove isotopic peaks. + \param maximumcharge charge of the precursor + \param fragmentmasserrortolerance mz error tolerance + \param os reference to a main thread of the application (stream, respectively) + */ + void removeIsotopes(int maximumcharge, double fragmentmasserrortolerance, cMainThread* os = 0); + + + /** + \brief Get a position of a peak with specified mzratio. + \param mzratio of searched peak + \param fragmentmasserrortolerance mz error tolerance + \retval int position; -1 when the peak is not found + */ + int find(double mzratio, double fragmentmasserrortolerance); + + + /** + \brief Erase all peaks having specified m/z ratio. + \param mzratio mz ratio of peaks which will be erased + */ + void eraseAll(double mzratio); + + + /** + \brief Remove a peak. + \param position position of a peak + */ + void remove(int position); + + + /** + \brief Perform a deconvolution. + \param maximumcharge charge of the precursor + \param fragmentmasserrortolerance mz error tolerance + */ + void removeChargeVariants(int maximumcharge, double fragmentmasserrortolerance); + + + /** + \brief Remove neutral losses. + \param loss mass change + \param maximumcharge charge of the precursor + \param fragmentmasserrortolerance mz error tolerance + */ + void removeNeutralLoss(double loss, int maximumcharge, double fragmentmasserrortolerance); + + + /** + \brief Remove peaks having set up the flag \a removeme == true. + */ + void removeObsolete(); + + + /** + \brief Keep only n highest peaks in a window of a specified size. + \param maximumnumberofpeaksinwindow maximum number of peaks in a window + \param windowsize size of a window + */ + void maxHighestPeaksInWindow(int maximumnumberofpeaksinwindow, double windowsize); + + + /** + \brief Get a maximum intensity of a peak in an interval of mz ratios. + \param minmz minimum mz ratio + \param maxmz maximum mz ratio + \retval double intensity + */ + double getMaximumIntensityFromMZInterval(double minmz, double maxmz); + + + /** + \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/cTheoreticalSpectrum.cpp b/CycloBranch/core/cTheoreticalSpectrum.cpp new file mode 100644 index 0000000..ecefbdd --- /dev/null +++ b/CycloBranch/core/cTheoreticalSpectrum.cpp @@ -0,0 +1,2321 @@ +#include "core/cTheoreticalSpectrum.h" +#include "core/cDeNovoGraph.h" + +#include "gui/cMainThread.h" + + +void visualSeries::store(ofstream& os) { + int size; + + size = (int)series.size(); + os.write((char *)&size, sizeof(int)); + for (int i = 0; i < (int)series.size(); i++) { + os.write((char *)&series[i], sizeof(int)); + } + + size = (int)name.size(); + os.write((char *)&size, sizeof(int)); + os.write(name.c_str(), name.size()); +} + + +void visualSeries::load(ifstream& is) { + int size; + + is.read((char *)&size, sizeof(int)); + series.resize(size); + for (int i = 0; i < (int)series.size(); i++) { + is.read((char *)&series[i], sizeof(int)); + } + + is.read((char *)&size, sizeof(int)); + name.resize(size); + is.read(&name[0], name.size()); +} + + +void cTheoreticalSpectrum::clearFalseHits(map >& series, vector& fragmentions) { + for (int i = 0; i < (int)fragmentions.size(); i++) { + for (int j = 0; j < (int)series[fragmentions[i]].size(); j++) { + + // parent fragment ion type is not defined in fragmentions or parent of a specific ion does not exist + if ((series.count(parameters->fragmentdefinitions[fragmentions[i]].parent) == 0) || (series[parameters->fragmentdefinitions[fragmentions[i]].parent][j] == 0)) { + series[fragmentions[i]][j] = 0; + } + + } + } +} + + +void cTheoreticalSpectrum::searchForPeakPairs(cPeaksList& theoreticalpeaks, int theoreticalpeaksrealsize, cPeaksList& experimentalpeaks, vector >& experimentalpeakmatches, double fragmentmasserrortolerance) { + experimentalpeakmatches.resize(experimentalpeaks.size()); + int left, right, middle; + for (int i = 0; i < theoreticalpeaksrealsize; i++) { + left = 0; + right = experimentalpeaks.size() - 1; + while (left <= right) { + middle = (left + right) / 2; + if (isInPpmMassErrorTolerance(experimentalpeaks[middle].mzratio, theoreticalpeaks[i].mzratio, fragmentmasserrortolerance)) { + experimentalpeakmatches[middle].insert(i); + experimentalpeaks[middle].matched++; + + theoreticalpeaks[i].matched++; + theoreticalpeaks[i].matchedid = middle; + break; + } + if (theoreticalpeaks[i].mzratio < experimentalpeaks[middle].mzratio) { + right = middle - 1; + } + else { + left = middle + 1; + } + } + } +} + + +void cTheoreticalSpectrum::computeSomeStatistics(bool writedescription) { + experimentalpeaksmatched = 0; + if (writedescription) { + unmatchedpeaks = ""; + } + intensityweightedscore = 0; + for (int i = 0; i < (int)experimentalpeaks.size(); i++) { + if (experimentalpeaks[i].matched > 0) { + experimentalpeaksmatched++; + intensityweightedscore += experimentalpeaks[i].intensity; + matchedions[experimentalpeaks[i].iontype]++; + } + else { + if (writedescription) { + unmatchedpeaks += to_string((long double)experimentalpeaks[i].mzratio) + " "; + } + } + } + peakstested = experimentalpeaks.size(); + experimentalpeaksmatchedratio = ((double)experimentalpeaksmatched) / ((double)experimentalpeaks.size()); +} + + +void cTheoreticalSpectrum::generateScrambledIons(cBricksDatabase& bricksdatabase, bool writedescription, int& theoreticalpeaksrealsize) { + unordered_set scrambledsequences, commonsequences; + vector intcomposition; + scrambledsequences.clear(); + int minimumsizeofscrambledsequences = 2; + cBrick b; + + b.setComposition(candidate.getComposition(), false); + vector stringcomposition; + b.explodeToStringComposition(stringcomposition); + + if (stringcomposition.size() > 32) { + // max 2^32 subsequences is tested + return; + } + + int numberofbricks = (int)stringcomposition.size(); + string subseq; + bool single; + // generate scrambled sequences + for (int i = 1; i < (int)pow(2, numberofbricks) - 1; i++) { + subseq = ""; + single = true; + for (int j = 0; j < numberofbricks; j++) { + if ((i >> j) % 2 == 1) { + if ((int)subseq.size() > 0) { + subseq += "-"; + single = false; + } + subseq += stringcomposition[j]; + } + } + if (!single) { + scrambledsequences.insert(subseq); + } + } + + // normalize scrambled sequences + normalizeScrambledSequences(scrambledsequences); + + cPeaksList scrambledpeaks; + scrambledpeaks.resize(5000); + int scrambledspeaksrealsize = 0; + + // generate scrambled peaks + for (int i = 0; i < (int)parameters->fragmentionsfortheoreticalspectra.size(); i++) { + for (unordered_set::iterator it = scrambledsequences.begin(); it != scrambledsequences.end(); ++it) { + b.setComposition((string &)*it, false); + intcomposition.clear(); + b.explodeToIntComposition(intcomposition); + cPeak peak; + peak.iontype = (fragmentIonType)parameters->fragmentionsfortheoreticalspectra[i]; + peak.mzratio = parameters->fragmentdefinitions[peak.iontype].massdifference; + peak.removeme = false; + peak.scrambled = true; + for (int i = 0; i < (int)intcomposition.size(); i++) { + peak.mzratio += bricksdatabase[intcomposition[i] - 1].getMass(); + } + + if (writedescription) { + peak.description = "scrambled "; + peak.description += parameters->fragmentdefinitions[peak.iontype].name.substr(0, 1) + to_string((int)intcomposition.size()); + if (parameters->fragmentdefinitions[peak.iontype].name.size() > 1) { + peak.description += parameters->fragmentdefinitions[peak.iontype].name.substr(1, parameters->fragmentdefinitions[peak.iontype].name.length() - 1); + } + peak.description += ": "; + for (int i = 0; i < (int)intcomposition.size(); i++) { + peak.description += "[" + bricksdatabase[intcomposition[i] - 1].getAcronymsAsString() + "]"; + if (i < (int)intcomposition.size() - 1) { + peak.description += '-'; + } + } + } + + if (scrambledpeaks.size() > scrambledspeaksrealsize) { + scrambledpeaks[scrambledspeaksrealsize] = peak; + } + else { + scrambledpeaks.add(peak); + } + 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); + // } + + // attach scrambled peaks to common peaks + for (int i = 0; i < (int)scrambledpeaks.size(); i++) { + if (theoreticalpeaks.size() > theoreticalpeaksrealsize) { + theoreticalpeaks[theoreticalpeaksrealsize] = scrambledpeaks[i]; + } + else { + theoreticalpeaks.add(scrambledpeaks[i]); + } + theoreticalpeaksrealsize++; + } + +} + + +void cTheoreticalSpectrum::normalizeScrambledSequences(unordered_set& scrambledsequences) { + unordered_set temp = scrambledsequences; + scrambledsequences.clear(); + + string twocompositions = candidate.getComposition() + "-" + candidate.getComposition(); + cBrick b; + b.setComposition(twocompositions, false); + string reversedtwocompositions = b.getReverseComposition(); + + for (unordered_set::iterator it = temp.begin(); it != temp.end(); ++it) { + if ((twocompositions.find((string& )*it) == string::npos) && (reversedtwocompositions.find((string& )*it) == string::npos)) { + b.setComposition((string& )*it, true); + if (scrambledsequences.count(b.getReverseComposition()) == 0) { + scrambledsequences.insert(b.getComposition()); + } + } + } +} + + +fragmentIonType cTheoreticalSpectrum::selectHigherPriorityIonType(fragmentIonType experimentalpeakiontype, fragmentIonType theoreticalpeakiontype) { + if (experimentalpeakiontype != fragmentIonTypeEnd) { + + switch (experimentalpeakiontype) + { + case b_ion: + break; + case b_ion_water_loss: + case b_ion_ammonia_loss: + if (theoreticalpeakiontype == b_ion) { + experimentalpeakiontype = theoreticalpeakiontype; + } + break; + case b_ion_water_and_ammonia_loss: + if ((theoreticalpeakiontype == b_ion) || (theoreticalpeakiontype == b_ion_water_loss) || (theoreticalpeakiontype == b_ion_ammonia_loss)) { + experimentalpeakiontype = theoreticalpeakiontype; + } + break; + case a_ion: + if (theoreticalpeakiontype == b_ion) { + experimentalpeakiontype = theoreticalpeakiontype; + } + break; + case a_ion_water_loss: + case a_ion_ammonia_loss: + if ((theoreticalpeakiontype == b_ion) || (theoreticalpeakiontype == b_ion_water_loss) || (theoreticalpeakiontype == b_ion_ammonia_loss) || (theoreticalpeakiontype == a_ion)) { + experimentalpeakiontype = theoreticalpeakiontype; + } + break; + case a_ion_water_and_ammonia_loss: + if ((theoreticalpeakiontype == b_ion) || (theoreticalpeakiontype == b_ion_water_loss) || (theoreticalpeakiontype == b_ion_ammonia_loss) || (theoreticalpeakiontype == a_ion) || (theoreticalpeakiontype == a_ion_water_loss) || (theoreticalpeakiontype == a_ion_ammonia_loss)) { + experimentalpeakiontype = theoreticalpeakiontype; + } + break; + case y_ion: + if ((theoreticalpeakiontype == b_ion) || (theoreticalpeakiontype == a_ion)) { + experimentalpeakiontype = theoreticalpeakiontype; + } + break; + case y_ion_water_loss: + case y_ion_ammonia_loss: + if ((theoreticalpeakiontype == y_ion) || (theoreticalpeakiontype == b_ion) || (theoreticalpeakiontype == b_ion_water_loss) || (theoreticalpeakiontype == b_ion_ammonia_loss) || (theoreticalpeakiontype == a_ion) || (theoreticalpeakiontype == a_ion_water_loss) || (theoreticalpeakiontype == a_ion_ammonia_loss)) { + experimentalpeakiontype = theoreticalpeakiontype; + } + break; + case y_ion_water_and_ammonia_loss: + experimentalpeakiontype = theoreticalpeakiontype; + default: + break; + } + + } + else { + experimentalpeakiontype = theoreticalpeakiontype; + } + + return experimentalpeakiontype; +} + + +cTheoreticalSpectrum::cTheoreticalSpectrum() { + clear(); +} + + +cTheoreticalSpectrum::cTheoreticalSpectrum(cParameters* parameters, cCandidate& candidate) { + clear(); + this->parameters = parameters; + this->candidate = candidate; +} + + +void cTheoreticalSpectrum::clear(bool clearpeaklist) { + parameters = 0; + + if (clearpeaklist) { + theoreticalpeaks.clear(); + } + + experimentalpeaks.clear(); + matchedions.clear(); + for (int i = 0; i < fragmentIonTypeEnd; i++) { + matchedions[(fragmentIonType)i] = 0; + } + + candidate.clear(); + experimentalpeaksmatched = 0; + peakstested = 0; + experimentalpeaksmatchedratio = 0; + unmatchedpeaks = ""; + coveragebyseries = ""; + valid = false; + maskscore = 0; + intensityweightedscore = 0; + visualcoverage.clear(); + validposition = -1; + reversevalidposition = -1; + + realpeptidename = ""; + acronympeptidename = ""; + acronyms.clear(); + path = ""; + seriescompleted = 1; +} + + +cCandidate& cTheoreticalSpectrum::getCandidate() { + return candidate; +} + + +void cTheoreticalSpectrum::setCandidate(cCandidate& candidate) { + this->candidate = candidate; +} + + +int cTheoreticalSpectrum::compareBranched(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence) { + + cBrick brick; + vector stringcomposition; + vector splittingsites; + int theoreticalpeaksrealsize = 0; + + vector trotations; + candidate.getPermutationsOfBranches(trotations); + + try { + bool stop = true; + for (int i = 0; i < (int)trotations.size(); i++) { + if (regex_search(trotations[i].tcomposition, sequencetag)) { + stop = false; + break; + } + } + if (stop) { + return -2; + } + + if (writedescription) { + valid = false; + if (parameters->searchedsequence.size() > 0) { + for (int i = 0; i < (int)trotations.size(); i++) { + if (regex_search(trotations[i].tcomposition, searchedsequence) && + (parameters->searchedmodifications[trotations[i].startmodifID].name.compare(parameters->searchedsequenceNtermmodif) == 0) && + (parameters->searchedmodifications[trotations[i].middlemodifID].name.compare(parameters->searchedsequenceTmodif) == 0) && + (parameters->searchedmodifications[trotations[i].endmodifID].name.compare(parameters->searchedsequenceCtermmodif) == 0)) { + valid = true; + break; + } + } + } + } + } + catch (std::regex_error& e) { + e; + return -2; + } + + for (int i = 0; i < (int)parameters->fragmentionsfortheoreticalspectra.size(); i++) { + for (int j = 0; j < (int)trotations.size(); j++) { + + if (writedescription) { + stringcomposition.clear(); + for (int k = 0; k < (int)trotations[j].bricks.size(); k++) { + stringcomposition.push_back(to_string(trotations[j].bricks[k])); + } + } + + // we do not know whether the middle branch is n-terminal or c-terminal for an unmodified middle branch + // in this case the modifID is 0, and both n-terminal (*) and c-terminal (**) fragments are generated + + // j == 2 and j == 5 have invalid n-terms + if ((parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].nterminal) && (j != 2) && (j != 5)) { + // if the start modification for j == 1 or j == 4 is nterminal, generate n-terminal ions (*) + if (!(((j == 1) || (j == 4)) && (!parameters->searchedmodifications[trotations[j].startmodifID].nterminal))) { + generateNTerminalFragmentIons(parameters->precursorcharge, theoreticalpeaksrealsize, stringcomposition, trotations[j].bricks, parameters->fragmentionsfortheoreticalspectra[i], bricksdatabasewithcombinations, writedescription, 0, splittingsites, parameters->searchedmodifications, branched, &trotations[j]); + } + } + + // j == 2 and j == 4 have invalid c-terms + if ((parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].cterminal) && (j != 2) && (j != 4)) { + // if the end modification for j == 3 or j == 5 is cterminal, generate c-terminal ions (**) + if (!(((j == 3) || (j == 5)) && (!parameters->searchedmodifications[trotations[j].endmodifID].cterminal))) { + generateCTerminalFragmentIons(parameters->precursorcharge, theoreticalpeaksrealsize, stringcomposition, trotations[j].bricks, parameters->fragmentionsfortheoreticalspectra[i], bricksdatabasewithcombinations, writedescription, 0, splittingsites, parameters->searchedmodifications, branched, &trotations[j]); + } + } + + } + } + + + // generate the precursor ion + cPeak peak; + peak.mzratio = parameters->searchedmodifications[candidate.getStartModifID()].massdifference + parameters->searchedmodifications[candidate.getEndModifID()].massdifference + parameters->searchedmodifications[candidate.getMiddleModifID()].massdifference; + for (int i = 0; i < (int)trotations[0].bricks.size(); i++) { + peak.mzratio += bricksdatabasewithcombinations[trotations[0].bricks[i] - 1].getMass(); + } + peak.seriesid = 0; + + double tempratio = peak.mzratio; + for (int i = (int)precursor_ion; i <= (int)precursor_ion_co_loss_water_and_ammonia_loss; i++) { + for (int j = 1; j <= parameters->precursorcharge; j++) { + peak.mzratio = tempratio + parameters->fragmentdefinitions[(fragmentIonType)i].massdifference; + peak.iontype = (fragmentIonType)i; + + if (writedescription) { + peak.description = to_string(j) + "+ " + parameters->fragmentdefinitions[(fragmentIonType)i].name + ":"; + } + + peak.mzratio = charge(peak.mzratio, j); + peak.charge = j; + + if (theoreticalpeaks.size() > theoreticalpeaksrealsize) { + theoreticalpeaks[theoreticalpeaksrealsize] = peak; + } + else { + theoreticalpeaks.add(peak); + } + theoreticalpeaksrealsize++; + + } + } + + + // search the theoretical peaks in the experimental peak list + experimentalpeaks = sortedpeaklist; + vector > experimentalpeakmatches; + searchForPeakPairs(theoreticalpeaks, theoreticalpeaksrealsize, experimentalpeaks, experimentalpeakmatches, parameters->fragmentmasserrortolerance); + + + // coverage of series + vector > > series; + series.resize(trotations.size()); + for (int i = 0; i < (int)series.size(); i++) { + for (int j = 0; j < parameters->fragmentionsfortheoreticalspectra.size(); j++) { + series[i][parameters->fragmentionsfortheoreticalspectra[j]].resize(trotations[0].bricks.size()); + } + } + + for (int i = 0; i < theoreticalpeaksrealsize; i++) { + if ((theoreticalpeaks[i].matched > 0) && (theoreticalpeaks[i].rotationid >= 0) && (series[theoreticalpeaks[i].rotationid].count(theoreticalpeaks[i].iontype) == 1)) { + series[theoreticalpeaks[i].rotationid][theoreticalpeaks[i].iontype][theoreticalpeaks[i].seriesid]++; + } + } + + + // peak hits without parents are removed + if (parameters->clearhitswithoutparent) { + for (int i = 0; i < (int)trotations.size(); i++) { + clearFalseHits(series[i], parameters->fragmentionsfortheoreticalspectra); + } + + for (int i = 0; i < theoreticalpeaksrealsize; i++) { + if ((theoreticalpeaks[i].matched > 0) && (theoreticalpeaks[i].rotationid >= 0) && ((series[theoreticalpeaks[i].rotationid].count(parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent) == 0) || (series[theoreticalpeaks[i].rotationid][parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent][theoreticalpeaks[i].seriesid] == 0))) { + experimentalpeakmatches[theoreticalpeaks[i].matchedid].erase(experimentalpeakmatches[theoreticalpeaks[i].matchedid].find(i)); + experimentalpeaks[theoreticalpeaks[i].matchedid].matched--; + + theoreticalpeaks[i].matched--; + theoreticalpeaks[i].matchedid = -1; + } + } + } + + + // 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 (writedescription) { + if (experimentalpeaks[i].description.compare("") != 0) { + experimentalpeaks[i].description += ", "; + } + experimentalpeaks[i].description += theoreticalpeaks[*it].description.substr(0,theoreticalpeaks[*it].description.find(':')); + experimentalpeaks[i].matchedrotations.push_back(theoreticalpeaks[*it].rotationid); + 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"; + } + + experimentalpeaks[i].iontype = selectHigherPriorityIonType(experimentalpeaks[i].iontype,theoreticalpeaks[*it].iontype); + } + } + + + if (writedescription) { + + visualcoverage.clear(); + visualSeries tempseries; + + coveragebyseries = "T-Permutations:
\n"; + for (int i = 0; i < (int)trotations.size(); i++) { + coveragebyseries += to_string(i + 1) + " ~ " + bricksdatabasewithcombinations.getAcronymNameOfTPeptide(trotations[i].tcomposition, false) + "
\n"; + } + coveragebyseries += "
\n"; + + coveragebyseries += "Series of matched peaks:
\n"; + for (int i = 0; i < (int)series.size(); i++) { + for (int j = 0; j < (int)parameters->fragmentionsfortheoreticalspectra.size(); j++) { + tempseries.name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name; + coveragebyseries += tempseries.name + " "; + tempseries.series.clear(); + for (int k = 0; k < series[i][parameters->fragmentionsfortheoreticalspectra[j]].size() - 1; k++) { + coveragebyseries += to_string(series[i][parameters->fragmentionsfortheoreticalspectra[j]][k]); + tempseries.series.push_back(series[i][parameters->fragmentionsfortheoreticalspectra[j]][k]); + if (k < series[i][parameters->fragmentionsfortheoreticalspectra[j]].size() - 2) { + coveragebyseries += " "; + } + } + coveragebyseries += "
\n"; + visualcoverage.push_back(tempseries); + } + } + + } + + computeSomeStatistics(writedescription); + + return theoreticalpeaksrealsize; +} + + +int cTheoreticalSpectrum::compareLinear(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence) { + cBrick brick; + vector intcomposition; + vector stringcomposition; + vector splittingsites; + int theoreticalpeaksrealsize = 0; + + try { + if (!regex_search(candidate.getComposition(), sequencetag)) { + return -2; + } + + if (writedescription) { + valid = false; + if ((parameters->searchedsequence.size() > 0) && regex_search(candidate.getComposition(), searchedsequence) && + (parameters->searchedmodifications[candidate.getStartModifID()].name.compare(parameters->searchedsequenceNtermmodif) == 0) && + (parameters->searchedmodifications[candidate.getEndModifID()].name.compare(parameters->searchedsequenceCtermmodif) == 0)) { + valid = true; + } + } + } + catch (std::regex_error& e) { + e; + return -2; + } + + intcomposition.clear(); + brick.clear(); + brick.setComposition(candidate.getComposition(), false); + brick.explodeToIntComposition(intcomposition); + + if (writedescription) { + stringcomposition.clear(); + brick.explodeToStringComposition(stringcomposition); + } + + for (int i = 0; i < (int)parameters->fragmentionsfortheoreticalspectra.size(); i++) { + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].nterminal) { + generateNTerminalFragmentIons(parameters->precursorcharge, theoreticalpeaksrealsize, stringcomposition, intcomposition, parameters->fragmentionsfortheoreticalspectra[i], bricksdatabasewithcombinations, writedescription, 0, splittingsites, parameters->searchedmodifications, linear); + } + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].cterminal) { + generateCTerminalFragmentIons(parameters->precursorcharge, theoreticalpeaksrealsize, stringcomposition, intcomposition, parameters->fragmentionsfortheoreticalspectra[i], bricksdatabasewithcombinations, writedescription, 0, splittingsites, parameters->searchedmodifications, linear); + } + } + + + // generate the precursor ion + cPeak peak; + peak.mzratio = parameters->searchedmodifications[candidate.getStartModifID()].massdifference + parameters->searchedmodifications[candidate.getEndModifID()].massdifference; + for (int i = 0; i < (int)intcomposition.size(); i++) { + peak.mzratio += bricksdatabasewithcombinations[intcomposition[i] - 1].getMass(); + } + peak.seriesid = 0; + + double tempratio = peak.mzratio; + for (int i = (int)precursor_ion; i <= (int)precursor_ion_co_loss_water_and_ammonia_loss; i++) { + for (int j = 1; j <= parameters->precursorcharge; j++) { + peak.mzratio = tempratio + parameters->fragmentdefinitions[(fragmentIonType)i].massdifference; + peak.iontype = (fragmentIonType)i; + + if (writedescription) { + peak.description = to_string(j) + "+ " + parameters->fragmentdefinitions[(fragmentIonType)i].name + ":"; + } + + peak.mzratio = charge(peak.mzratio, j); + peak.charge = j; + + if (theoreticalpeaks.size() > theoreticalpeaksrealsize) { + theoreticalpeaks[theoreticalpeaksrealsize] = peak; + } + else { + theoreticalpeaks.add(peak); + } + theoreticalpeaksrealsize++; + + } + } + + + // search the theoretical peaks in the experimental peak list + experimentalpeaks = sortedpeaklist; + vector > experimentalpeakmatches; + searchForPeakPairs(theoreticalpeaks, theoreticalpeaksrealsize, experimentalpeaks, experimentalpeakmatches, parameters->fragmentmasserrortolerance); + + + // coverage of series + map > series; + for (int i = 0; i < parameters->fragmentionsfortheoreticalspectra.size(); i++) { + series[parameters->fragmentionsfortheoreticalspectra[i]].resize(intcomposition.size()); + } + + for (int i = 0; i < theoreticalpeaksrealsize; i++) { + if ((theoreticalpeaks[i].matched > 0) && (series.count(theoreticalpeaks[i].iontype) == 1)) { + series[theoreticalpeaks[i].iontype][theoreticalpeaks[i].seriesid]++; + } + } + + + // peak hits without parents are removed + if (parameters->clearhitswithoutparent) { + clearFalseHits(series, parameters->fragmentionsfortheoreticalspectra); + + for (int i = 0; i < theoreticalpeaksrealsize; i++) { + if ((theoreticalpeaks[i].matched > 0) && ((series.count(parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent) == 0) || (series[parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent][theoreticalpeaks[i].seriesid] == 0))) { + experimentalpeakmatches[theoreticalpeaks[i].matchedid].erase(experimentalpeakmatches[theoreticalpeaks[i].matchedid].find(i)); + experimentalpeaks[theoreticalpeaks[i].matchedid].matched--; + + theoreticalpeaks[i].matched--; + theoreticalpeaks[i].matchedid = -1; + } + } + } + + + // 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 (writedescription) { + if (experimentalpeaks[i].description.compare("") != 0) { + experimentalpeaks[i].description += ", "; + } + experimentalpeaks[i].description += theoreticalpeaks[*it].description.substr(0,theoreticalpeaks[*it].description.find(':')); + experimentalpeaks[i].matchedrotations.push_back(theoreticalpeaks[*it].rotationid); + 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"; + } + + experimentalpeaks[i].iontype = selectHigherPriorityIonType(experimentalpeaks[i].iontype,theoreticalpeaks[*it].iontype); + } + } + + + if (writedescription) { + + visualcoverage.clear(); + visualSeries tempseries; + + coveragebyseries = "Series of matched peaks:
\n"; + for (int i = 0; i < (int)parameters->fragmentionsfortheoreticalspectra.size(); i++) { + tempseries.name = parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].name; + coveragebyseries += tempseries.name + " "; + tempseries.series.clear(); + for (int j = 0; j < series[parameters->fragmentionsfortheoreticalspectra[i]].size() - 1; j++) { + coveragebyseries += to_string(series[parameters->fragmentionsfortheoreticalspectra[i]][j]); + tempseries.series.push_back(series[parameters->fragmentionsfortheoreticalspectra[i]][j]); + if (j < series[parameters->fragmentionsfortheoreticalspectra[i]].size() - 2) { + coveragebyseries += " "; + } + } + coveragebyseries += "
\n"; + visualcoverage.push_back(tempseries); + } + + } + + computeSomeStatistics(writedescription); + + return theoreticalpeaksrealsize; +} + + +int cTheoreticalSpectrum::compareCyclic(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence) { + + cBrick brick; + vector intcomposition; + vector stringcomposition; + vector splittingsites; + int theoreticalpeaksrealsize = 0; + + vector rotations; + candidate.getRotations(rotations, true); + + int r = (int)rotations.size() / 2; + validposition = -1; + reversevalidposition = -1; + + + try { + bool stop = true; + for (int i = 0; i < (int)rotations.size(); i++) { + if (regex_search(rotations[i], sequencetag)) { + stop = false; + break; + } + } + if (stop) { + return -2; + } + + if (writedescription) { + + valid = false; + + if (parameters->searchedsequence.size() > 0) { + for (int i = 0; i < (int)rotations.size(); i++) { + if (regex_search(rotations[i], searchedsequence)) { + validposition = i; + + if (validposition == 0) { + reversevalidposition = r; + } + else if (validposition == r) { + reversevalidposition = 0; + } + else { + reversevalidposition = 2*r - validposition; + } + + break; + } + } + + if (validposition != -1) { + valid = true; + } + } + + bool enableshiftoflabels = false; + if (!enableshiftoflabels || (validposition == -1)) { + validposition = 0; + reversevalidposition = r; + } + + if (validposition != -1) { + + splittingsites.resize(rotations.size()); + splittingsites[validposition].first = 0; + splittingsites[validposition].second = r - 1; + splittingsites[reversevalidposition].first = r - 1; + splittingsites[reversevalidposition].second = 0; + + if (validposition < r) { + for (int i = 1; i < r; i++) { + splittingsites[(validposition + i) % r].first = (splittingsites[(validposition + i + r - 1) % r].first + 1) % r; + splittingsites[(validposition + i) % r].second = (splittingsites[(validposition + i + r - 1) % r].second + 1) % r; + splittingsites[((reversevalidposition + i) % r) + r].first = (splittingsites[((reversevalidposition + i + r - 1) % r) + r].first + r - 1) % r; + splittingsites[((reversevalidposition + i) % r) + r].second = (splittingsites[((reversevalidposition + i + r - 1) % r) + r].second + r - 1) % r; + } + } + else { + for (int i = 1; i < r; i++) { + splittingsites[((validposition + i) % r) + r].first = (splittingsites[((validposition + i + r - 1) % r) + r].first + 1) % r; + splittingsites[((validposition + i) % r) + r].second = (splittingsites[((validposition + i + r - 1) % r) + r].second + 1) % r; + splittingsites[(reversevalidposition + i) % r].first = (splittingsites[(reversevalidposition + i + r - 1) % r].first + r - 1) % r; + splittingsites[(reversevalidposition + i) % r].second = (splittingsites[(reversevalidposition + i + r - 1) % r].second + r - 1) % r; + } + } + + } + + } + } + catch (std::regex_error& e) { + e; + return -2; + } + + + for (int i = 0; i < 2*r; i++) { + + intcomposition.clear(); + brick.clear(); + brick.setComposition(rotations[i], false); + brick.explodeToIntComposition(intcomposition); + + if (writedescription) { + stringcomposition.clear(); + brick.explodeToStringComposition(stringcomposition); + } + + for (int j = 0; j < (int)parameters->fragmentionsfortheoreticalspectra.size(); j++) { + generateNTerminalFragmentIons(parameters->precursorcharge, theoreticalpeaksrealsize, stringcomposition, intcomposition, parameters->fragmentionsfortheoreticalspectra[j], bricksdatabasewithcombinations, writedescription, i, splittingsites, parameters->searchedmodifications, cyclic); + } + + } + + if (parameters->enablescrambling) { + generateScrambledIons(bricksdatabasewithcombinations, writedescription, theoreticalpeaksrealsize); + } + + + // generate the precursor ion + cPeak peak; + peak.mzratio = 0; + for (int i = 0; i < (int)intcomposition.size(); i++) { + peak.mzratio += bricksdatabasewithcombinations[intcomposition[i] - 1].getMass(); + } + peak.seriesid = (int)intcomposition.size() - 1; + + double tempratio = peak.mzratio; + for (int i = (int)cyclic_precursor_ion; i <= (int)cyclic_precursor_ion_co_loss_water_and_ammonia_loss; i++) { + for (int j = 1; j <= parameters->precursorcharge; j++) { + peak.mzratio = tempratio + parameters->fragmentdefinitions[(fragmentIonType)i].massdifference; + peak.iontype = (fragmentIonType)i; + + if (writedescription) { + peak.description = to_string(j) + "+ " + parameters->fragmentdefinitions[(fragmentIonType)i].name + ":"; + } + + peak.mzratio = charge(peak.mzratio, j); + peak.charge = j; + + if (theoreticalpeaks.size() > theoreticalpeaksrealsize) { + theoreticalpeaks[theoreticalpeaksrealsize] = peak; + } + else { + theoreticalpeaks.add(peak); + } + theoreticalpeaksrealsize++; + + } + } + + + // search the theoretical peaks in the experimental peak list + experimentalpeaks = sortedpeaklist; + vector > experimentalpeakmatches; + searchForPeakPairs(theoreticalpeaks, theoreticalpeaksrealsize, experimentalpeaks, experimentalpeakmatches, parameters->fragmentmasserrortolerance); + + + // coverage of series + vector > > series; + series.resize(rotations.size()); + for (int i = 0; i < (int)series.size(); i++) { + for (int j = 0; j < parameters->fragmentionsfortheoreticalspectra.size(); j++) { + series[i][parameters->fragmentionsfortheoreticalspectra[j]].resize(r); + } + } + + for (int i = 0; i < theoreticalpeaksrealsize; i++) { + if ((theoreticalpeaks[i].matched > 0) && (theoreticalpeaks[i].rotationid >= 0) && (series[theoreticalpeaks[i].rotationid].count(theoreticalpeaks[i].iontype) == 1)) { + series[theoreticalpeaks[i].rotationid][theoreticalpeaks[i].iontype][theoreticalpeaks[i].seriesid]++; + } + } + + + // peak hits without parents are removed + if (parameters->clearhitswithoutparent) { + for (int i = 0; i < (int)rotations.size(); i++) { + clearFalseHits(series[i], parameters->fragmentionsfortheoreticalspectra); + } + + for (int i = 0; i < theoreticalpeaksrealsize; i++) { + if ((theoreticalpeaks[i].matched > 0) && (theoreticalpeaks[i].rotationid >= 0) && ((series[theoreticalpeaks[i].rotationid].count(parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent) == 0) || (series[theoreticalpeaks[i].rotationid][parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent][theoreticalpeaks[i].seriesid] == 0))) { + experimentalpeakmatches[theoreticalpeaks[i].matchedid].erase(experimentalpeakmatches[theoreticalpeaks[i].matchedid].find(i)); + experimentalpeaks[theoreticalpeaks[i].matchedid].matched--; + + theoreticalpeaks[i].matched--; + theoreticalpeaks[i].matchedid = -1; + } + } + + // remove scrambled peaks without parents + if (parameters->enablescrambling) { + int res; + bool matchesscrambled; + for (int i = 0; i < (int)parameters->fragmentionsfortheoreticalspectra.size(); i++) { + if (parameters->fragmentionsfortheoreticalspectra[i] == parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].parent) { + continue; + } + + int j = 0; + while (j < theoreticalpeaksrealsize) { + // current peak is scrambled, matched and currently tested ion type matches the ion type of the scrambled peak + if (theoreticalpeaks[j].scrambled && (theoreticalpeaks[j].matched > 0) && (parameters->fragmentionsfortheoreticalspectra[i] == theoreticalpeaks[j].iontype)) { + + // parent not found + res = experimentalpeaks.find(theoreticalpeaks[j].mzratio - parameters->fragmentdefinitions[theoreticalpeaks[j].iontype].massdifference + parameters->fragmentdefinitions[parameters->fragmentdefinitions[theoreticalpeaks[j].iontype].parent].massdifference, parameters->fragmentmasserrortolerance); + if (res == -1) { + experimentalpeakmatches[theoreticalpeaks[j].matchedid].erase(experimentalpeakmatches[theoreticalpeaks[j].matchedid].find(j)); + experimentalpeaks[theoreticalpeaks[j].matchedid].matched--; + + theoreticalpeaks[j].matched--; + theoreticalpeaks[j].matchedid = -1; + + } + else { + + matchesscrambled = false; + for (set::iterator it = experimentalpeakmatches[res].begin(); it != experimentalpeakmatches[res].end(); ++it) { + if ((theoreticalpeaks[*it].matched > 0) && theoreticalpeaks[*it].scrambled) { + matchesscrambled = true; + break; + } + } + + // a scrambled peak is not matched by parent + if (!matchesscrambled) { + experimentalpeakmatches[theoreticalpeaks[j].matchedid].erase(experimentalpeakmatches[theoreticalpeaks[j].matchedid].find(j)); + experimentalpeaks[theoreticalpeaks[j].matchedid].matched--; + + theoreticalpeaks[j].matched--; + theoreticalpeaks[j].matchedid = -1; + } + else { + j++; + } + } + } + else { + j++; + } + } + } + } + } + + + // fill annotations of peaks + for (int i = 0; i < (int)experimentalpeakmatches.size(); i++) { + for (set::iterator it = experimentalpeakmatches[i].begin(); it != experimentalpeakmatches[i].end(); ++it) { + if (writedescription) { + if (experimentalpeaks[i].description.compare("") != 0) { + experimentalpeaks[i].description += ", "; + } + experimentalpeaks[i].description += theoreticalpeaks[*it].description.substr(0,theoreticalpeaks[*it].description.find(':')); + experimentalpeaks[i].matchedrotations.push_back(theoreticalpeaks[*it].rotationid); + 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"; + } + + if (experimentalpeaks[i].iontype != fragmentIonTypeEnd) { + + if (theoreticalpeaks[*it].scrambled == experimentalpeaks[i].scrambled) { + + switch (experimentalpeaks[i].iontype) + { + case b_ion: + break; + case b_ion_water_loss: + case b_ion_ammonia_loss: + if (theoreticalpeaks[*it].iontype == b_ion) { + experimentalpeaks[i].iontype = theoreticalpeaks[*it].iontype; + } + break; + case b_ion_water_and_ammonia_loss: + if ((theoreticalpeaks[*it].iontype == b_ion) || (theoreticalpeaks[*it].iontype == b_ion_water_loss) || (theoreticalpeaks[*it].iontype == b_ion_ammonia_loss)) { + experimentalpeaks[i].iontype = theoreticalpeaks[*it].iontype; + } + break; + case a_ion: + if (theoreticalpeaks[*it].iontype == b_ion) { + experimentalpeaks[i].iontype = theoreticalpeaks[*it].iontype; + } + break; + case a_ion_water_loss: + case a_ion_ammonia_loss: + if ((theoreticalpeaks[*it].iontype == b_ion) || (theoreticalpeaks[*it].iontype == b_ion_water_loss) || (theoreticalpeaks[*it].iontype == b_ion_ammonia_loss) || (theoreticalpeaks[*it].iontype == a_ion)) { + experimentalpeaks[i].iontype = theoreticalpeaks[*it].iontype; + } + break; + case a_ion_water_and_ammonia_loss: + experimentalpeaks[i].iontype = theoreticalpeaks[*it].iontype; + break; + default: + break; + } + + } + else { + + if (experimentalpeaks[i].scrambled && !theoreticalpeaks[*it].scrambled) { + experimentalpeaks[i].iontype = theoreticalpeaks[*it].iontype; + experimentalpeaks[i].scrambled = theoreticalpeaks[*it].scrambled; + } + + } + + } + else { + experimentalpeaks[i].iontype = theoreticalpeaks[*it].iontype; + experimentalpeaks[i].scrambled = theoreticalpeaks[*it].scrambled; + } + } + } + + + if (writedescription) { + + visualSeries tempseries; + visualcoverage.clear(); + + coveragebyseries = "Rotations:
\n"; + for (int i = 0; i < (int)rotations.size(); i++) { + /* + if (i == 0) { + coveragebyseries += ">>>
\n"; + } + if (i == r) { + coveragebyseries += "
\n<<<
\n"; + } + */ + if (i == r) { + coveragebyseries += "
\n"; + } + coveragebyseries += to_string(splittingsites[i].first + 1) + "-" + to_string(splittingsites[i].second + 1) + " " + bricksdatabasewithcombinations.getAcronymName(rotations[i], false) + "
\n"; + } + coveragebyseries += "
\n"; + + coveragebyseries += "Series of matched peaks:
\n"; + for (int i = 0; i < (int)series.size(); i++) { + if (i == r) { + coveragebyseries += "
\n"; + } + for (int j = 0; j < (int)parameters->fragmentionsfortheoreticalspectra.size(); j++) { + tempseries.name = to_string(splittingsites[i].first + 1) + "-" + to_string(splittingsites[i].second + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name; + coveragebyseries += tempseries.name + " "; + tempseries.series.clear(); + for (int k = 0; k < series[i][parameters->fragmentionsfortheoreticalspectra[j]].size() - 1; k++) { + coveragebyseries += to_string(series[i][parameters->fragmentionsfortheoreticalspectra[j]][k]); + tempseries.series.push_back(series[i][parameters->fragmentionsfortheoreticalspectra[j]][k]); + if (k < series[i][parameters->fragmentionsfortheoreticalspectra[j]].size() - 2) { + coveragebyseries += " "; + } + } + coveragebyseries += "
\n"; + visualcoverage.push_back(tempseries); // comment + } + } + + } + + + vector mask; // peaks converted to letters + vector tempvector; + visualSeries visualtempseries; + for (int k = 0; k < r; k++) { + mask.push_back(0); + tempvector.push_back(0); + if (writedescription) { + visualtempseries.series.push_back(0); + } + } + + if (writedescription) { + //visualcoverage.clear(); // uncomment + } + + for (int i = 0; i < (int)series.size(); i++) { + + for (int j = 0; j < (int)parameters->fragmentionsfortheoreticalspectra.size(); j++) { + + for (int k = 0; k < r; k++) { + tempvector[k] = 0; + } + + for (int k = 0; k < r; k++) { + // the first peak determines the first letter + if ((k == 0) && (series[i][parameters->fragmentionsfortheoreticalspectra[j]][k] > 0)) { + tempvector[0] = 1; + } + + // the pre-last peak and the precursor determine the last letter + if ((k == r - 2) && (series[i][parameters->fragmentionsfortheoreticalspectra[j]][k] > 0)) { + tempvector[r - 1] = 1; + } + + if ((k >= 0) && (k < r - 2) && (series[i][parameters->fragmentionsfortheoreticalspectra[j]][k] > 0) && (series[i][parameters->fragmentionsfortheoreticalspectra[j]][k + 1] > 0)) { + tempvector[k + 1] = 1; + } + } + + if (writedescription) { + visualtempseries.name = to_string(splittingsites[i].first + 1) + "-" + to_string(splittingsites[i].second + 1) + "_"; + visualtempseries.name += parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name; + } + + if (i < r) { + for (int k = 0; k < r; k++) { + mask[k] += tempvector[(k + r - i) % r]; + + if (writedescription) { + visualtempseries.series[k] = tempvector[(k + r - i) % r]; + } + } + } + else { + reverse(tempvector.begin(),tempvector.end()); + + for (int k = 0; k < r; k++) { + mask[k] += tempvector[(k + i) % r]; + + if (writedescription) { + visualtempseries.series[k] = tempvector[(k + i) % r]; + } + } + } + + if (writedescription) { + //visualcoverage.push_back(visualtempseries); // uncomment + } + + } + + } + + maskscore = 0; + for (int k = 0; k < (int)mask.size(); k++) { + maskscore += mask[k]; + } + + computeSomeStatistics(writedescription); + + return theoreticalpeaksrealsize; +} + + +int cTheoreticalSpectrum::compareLasso(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence) { + + vector splittingsites; + int theoreticalpeaksrealsize = 0; + vector stringcomposition; + + + vector lassorotations; + candidate.getLassoRotations(lassorotations, true); + + + int r = (int)lassorotations.size() / 2; + validposition = -1; + reversevalidposition = -1; + + + vector > trotationsoflassorotations; + trotationsoflassorotations.resize(lassorotations.size()); + for (int i = 0; i < (int)lassorotations.size(); i++) { + lassorotations[i].getPermutationsOfBranches(trotationsoflassorotations[i]); + } + + + try { + bool stop = true; + for (int i = 0; i < (int)lassorotations.size(); i++) { + for (int j = 0; j < (int)trotationsoflassorotations[i].size(); j++) { + if (regex_search(trotationsoflassorotations[i][j].tcomposition, sequencetag)) { + stop = false; + break; + } + } + } + if (stop) { + return -2; + } + + if (writedescription) { + valid = false; + if (parameters->searchedsequence.size() > 0) { + for (int i = 0; i < (int)lassorotations.size(); i++) { + if (regex_search(lassorotations[i].getComposition(), searchedsequence)) { + validposition = i; + + if (validposition == 0) { + reversevalidposition = r; + } + else if (validposition == r) { + reversevalidposition = 0; + } + else { + reversevalidposition = 2*r - validposition; + } + } + + for (int j = 0; j < (int)trotationsoflassorotations[i].size(); j++) { + if (regex_search(trotationsoflassorotations[i][j].tcomposition, searchedsequence) && + (parameters->searchedmodifications[trotationsoflassorotations[i][j].middlemodifID].name.compare(parameters->searchedsequenceTmodif) == 0)) { + valid = true; + break; + } + } + } + } + + bool enableshiftoflabels = true; + if (!enableshiftoflabels || (validposition == -1)) { + validposition = 0; + reversevalidposition = r; + } + + if (validposition != -1) { + + splittingsites.resize(lassorotations.size()); + splittingsites[validposition].first = 0; + splittingsites[validposition].second = r - 1; + splittingsites[reversevalidposition].first = r - 1; + splittingsites[reversevalidposition].second = 0; + + if (validposition < r) { + for (int i = 1; i < r; i++) { + splittingsites[(validposition + i) % r].first = (splittingsites[(validposition + i + r - 1) % r].first + 1) % r; + splittingsites[(validposition + i) % r].second = (splittingsites[(validposition + i + r - 1) % r].second + 1) % r; + splittingsites[((reversevalidposition + i) % r) + r].first = (splittingsites[((reversevalidposition + i + r - 1) % r) + r].first + r - 1) % r; + splittingsites[((reversevalidposition + i) % r) + r].second = (splittingsites[((reversevalidposition + i + r - 1) % r) + r].second + r - 1) % r; + } + } + else { + for (int i = 1; i < r; i++) { + splittingsites[((validposition + i) % r) + r].first = (splittingsites[((validposition + i + r - 1) % r) + r].first + 1) % r; + splittingsites[((validposition + i) % r) + r].second = (splittingsites[((validposition + i + r - 1) % r) + r].second + 1) % r; + splittingsites[(reversevalidposition + i) % r].first = (splittingsites[(reversevalidposition + i + r - 1) % r].first + r - 1) % r; + splittingsites[(reversevalidposition + i) % r].second = (splittingsites[(reversevalidposition + i + r - 1) % r].second + r - 1) % r; + } + } + + } + + } + } + catch (std::regex_error& e) { + e; + return -2; + } + + + for (int i = 0; i < (int)parameters->fragmentionsfortheoreticalspectra.size(); i++) { + + for (int j = 0; j < (int)lassorotations.size(); j++) { + + for (int k = 0; k < (int)trotationsoflassorotations[j].size(); k++) { + + if (writedescription) { + // to do - performace issue, generated repeatedly + stringcomposition.clear(); + for (int m = 0; m < (int)trotationsoflassorotations[j][k].bricks.size(); m++) { + stringcomposition.push_back(to_string(trotationsoflassorotations[j][k].bricks[m])); + } + } + + // we do not know whether the middle branch is n-terminal or c-terminal for an unmodified middle branch + // in this case the modifID is 0, and both n-terminal (*) and c-terminal (**) fragments are generated + + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].nterminal) { + // if the start modification for k == 1 or k == 4 is nterminal, generate n-terminal ions (*) + if (!(((k == 1) || (k == 4)) && (!parameters->searchedmodifications[trotationsoflassorotations[j][k].startmodifID].nterminal))) { + generateNTerminalFragmentIons(parameters->precursorcharge, theoreticalpeaksrealsize, stringcomposition, trotationsoflassorotations[j][k].bricks, parameters->fragmentionsfortheoreticalspectra[i], bricksdatabasewithcombinations, writedescription, j, splittingsites, parameters->searchedmodifications, lasso, &trotationsoflassorotations[j][k]); + } + } + + // 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 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]); + } + } + + } + + } + + } + + + // generate the precursor ion + // to do - performance + cBrick b; + b.setComposition(candidate.getComposition(), false); + vector intcomposition; + b.explodeToIntComposition(intcomposition); + + cPeak peak; + peak.mzratio = parameters->searchedmodifications[candidate.getMiddleModifID()].massdifference; + for (int i = 0; i < (int)intcomposition.size(); i++) { + peak.mzratio += bricksdatabasewithcombinations[intcomposition[i] - 1].getMass(); + } + peak.seriesid = 0; + + double tempratio = peak.mzratio; + for (int i = (int)cyclic_precursor_ion; i <= (int)cyclic_precursor_ion_co_loss_water_and_ammonia_loss; i++) { + for (int j = 1; j <= parameters->precursorcharge; j++) { + peak.mzratio = tempratio + parameters->fragmentdefinitions[(fragmentIonType)i].massdifference; + peak.iontype = (fragmentIonType)i; + + if (writedescription) { + peak.description = to_string(j) + "+ " + parameters->fragmentdefinitions[(fragmentIonType)i].name + ":"; + } + + peak.mzratio = charge(peak.mzratio, j); + peak.charge = j; + + if (theoreticalpeaks.size() > theoreticalpeaksrealsize) { + theoreticalpeaks[theoreticalpeaksrealsize] = peak; + } + else { + theoreticalpeaks.add(peak); + } + theoreticalpeaksrealsize++; + + } + } + + + // search the theoretical peaks in the experimental peak list + experimentalpeaks = sortedpeaklist; + vector > experimentalpeakmatches; + searchForPeakPairs(theoreticalpeaks, theoreticalpeaksrealsize, experimentalpeaks, experimentalpeakmatches, parameters->fragmentmasserrortolerance); + + + // coverage of series + vector > > > series; + series.resize(lassorotations.size()); + for (int i = 0; i < (int)lassorotations.size(); i++) { + series[i].resize(6); + //series[i].resize(trotationsoflassorotations[i].size()); // to do - potential bug + + for (int j = 0; j < (int)series[i].size(); j++) { + for (int k = 0; k < parameters->fragmentionsfortheoreticalspectra.size(); k++) { + series[i][j][parameters->fragmentionsfortheoreticalspectra[k]].resize(trotationsoflassorotations[i][0].bricks.size()); + } + } + + for (int j = 0; j < theoreticalpeaksrealsize; j++) { + if ((theoreticalpeaks[j].matched > 0) && (theoreticalpeaks[j].rotationid >= 0) && (series[i][theoreticalpeaks[j].rotationid % 6].count(theoreticalpeaks[j].iontype) == 1)) { + if (i == theoreticalpeaks[j].rotationid / 6) { + series[i][theoreticalpeaks[j].rotationid % 6][theoreticalpeaks[j].iontype][theoreticalpeaks[j].seriesid]++; + } + } + } + } + + + // peak hits without parents are removed + if (parameters->clearhitswithoutparent) { + for (int i = 0; i < (int)lassorotations.size(); i++) { + for (int j = 0; j < (int)trotationsoflassorotations[i].size(); j++) { + clearFalseHits(series[i][j], parameters->fragmentionsfortheoreticalspectra); + } + + for (int j = 0; j < theoreticalpeaksrealsize; j++) { + if ((theoreticalpeaks[j].matched > 0) && (theoreticalpeaks[j].rotationid >= 0) && (i == theoreticalpeaks[j].rotationid / 6) && ((series[i][theoreticalpeaks[j].rotationid % 6].count(parameters->fragmentdefinitions[theoreticalpeaks[j].iontype].parent) == 0) || (series[i][theoreticalpeaks[j].rotationid % 6][parameters->fragmentdefinitions[theoreticalpeaks[j].iontype].parent][theoreticalpeaks[j].seriesid] == 0))) { + experimentalpeakmatches[theoreticalpeaks[j].matchedid].erase(experimentalpeakmatches[theoreticalpeaks[j].matchedid].find(j)); + experimentalpeaks[theoreticalpeaks[j].matchedid].matched--; + + theoreticalpeaks[j].matched--; + theoreticalpeaks[j].matchedid = -1; + } + } + } + } + + + // 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 (writedescription) { + if (experimentalpeaks[i].description.compare("") != 0) { + experimentalpeaks[i].description += ", "; + } + experimentalpeaks[i].description += theoreticalpeaks[*it].description.substr(0,theoreticalpeaks[*it].description.find(':')); + experimentalpeaks[i].matchedrotations.push_back(theoreticalpeaks[*it].rotationid); + 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"; + } + + experimentalpeaks[i].iontype = selectHigherPriorityIonType(experimentalpeaks[i].iontype,theoreticalpeaks[*it].iontype); + } + } + + + if (writedescription) { + + coveragebyseries = "T-Permutations of lasso rotations:
\n"; + for (int i = 0; i < (int)lassorotations.size(); i++) { + if (i == 0) { + coveragebyseries += ">>>
\n"; + } + if (i == r) { + coveragebyseries += "<<<
\n"; + } + for (int j = 0; j < (int)trotationsoflassorotations[i].size(); j++) { + coveragebyseries += to_string(splittingsites[i].first + 1) + "-" + to_string(splittingsites[i].second + 1) + "_"; + coveragebyseries += to_string(j + 1) + " ~ "; + coveragebyseries += bricksdatabasewithcombinations.getAcronymNameOfTPeptide(trotationsoflassorotations[i][j].tcomposition, false); + coveragebyseries += "
\n"; + } + coveragebyseries += "
\n"; + } + + coveragebyseries += "Series of matched peaks:
\n"; + for (int i = 0; i < (int)lassorotations.size(); i++) { + for (int j = 0; j < (int)series[i].size(); j++) { + for (int k = 0; k < (int)parameters->fragmentionsfortheoreticalspectra.size(); k++) { + coveragebyseries += to_string(splittingsites[i].first + 1) + "-" + to_string(splittingsites[i].second + 1) + "_"; + coveragebyseries += to_string(j + 1) + "_"; + coveragebyseries += parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[k]].name + " "; + for (int m = 0; m < series[i][j][parameters->fragmentionsfortheoreticalspectra[k]].size() - 1; m++) { + coveragebyseries += to_string(series[i][j][parameters->fragmentionsfortheoreticalspectra[k]][m]); + if (m < series[i][j][parameters->fragmentionsfortheoreticalspectra[k]].size() - 2) { + coveragebyseries += " "; + } + } + coveragebyseries += "
\n"; + } + } + } + + } + + + computeSomeStatistics(writedescription); + + return theoreticalpeaksrealsize; +} + + +int cTheoreticalSpectrum::compareLinearPolysaccharide(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence) { + cBrick brick; + vector intcomposition; + vector stringcomposition; + vector splittingsites; + int theoreticalpeaksrealsize = 0; + + try { + if (!regex_search(candidate.getComposition(), sequencetag)) { + return -2; + } + + if (writedescription) { + valid = false; + if ((parameters->searchedsequence.size() > 0) && regex_search(candidate.getComposition(), searchedsequence) && + (parameters->searchedmodifications[candidate.getStartModifID()].name.compare(parameters->searchedsequenceNtermmodif) == 0) && + (parameters->searchedmodifications[candidate.getEndModifID()].name.compare(parameters->searchedsequenceCtermmodif) == 0)) { + valid = true; + } + } + } + catch (std::regex_error& e) { + e; + return -2; + } + + intcomposition.clear(); + brick.clear(); + brick.setComposition(candidate.getComposition(), false); + brick.explodeToIntComposition(intcomposition); + + if (writedescription) { + stringcomposition.clear(); + brick.explodeToStringComposition(stringcomposition); + } + + for (int i = 0; i < (int)parameters->fragmentionsfortheoreticalspectra.size(); i++) { + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].nterminal) { + generateNTerminalFragmentIons(parameters->precursorcharge, theoreticalpeaksrealsize, stringcomposition, intcomposition, parameters->fragmentionsfortheoreticalspectra[i], bricksdatabasewithcombinations, writedescription, 0, splittingsites, parameters->searchedmodifications, linearpolysaccharide); + } + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].cterminal) { + generateCTerminalFragmentIons(parameters->precursorcharge, theoreticalpeaksrealsize, stringcomposition, intcomposition, parameters->fragmentionsfortheoreticalspectra[i], bricksdatabasewithcombinations, writedescription, 0, splittingsites, parameters->searchedmodifications, linearpolysaccharide); + } + } + + + // generate the precursor ion + cPeak peak; + peak.mzratio = parameters->searchedmodifications[candidate.getStartModifID()].massdifference + parameters->searchedmodifications[candidate.getEndModifID()].massdifference; + for (int i = 0; i < (int)intcomposition.size(); i++) { + peak.mzratio += bricksdatabasewithcombinations[intcomposition[i] - 1].getMass(); + } + peak.seriesid = 0; + + double tempratio = peak.mzratio; + for (int i = (int)precursor_ion; i <= (int)precursor_ion_co_loss_water_and_ammonia_loss; i++) { + for (int j = 1; j <= parameters->precursorcharge; j++) { + peak.mzratio = tempratio + parameters->fragmentdefinitions[(fragmentIonType)i].massdifference; + peak.iontype = (fragmentIonType)i; + + if (writedescription) { + peak.description = to_string(j) + "+ " + parameters->fragmentdefinitions[(fragmentIonType)i].name + ":"; + } + + peak.mzratio = charge(peak.mzratio, j); + peak.charge = j; + + if (theoreticalpeaks.size() > theoreticalpeaksrealsize) { + theoreticalpeaks[theoreticalpeaksrealsize] = peak; + } + else { + theoreticalpeaks.add(peak); + } + theoreticalpeaksrealsize++; + + } + } + + + // search the theoretical peaks in the experimental peak list + experimentalpeaks = sortedpeaklist; + vector > experimentalpeakmatches; + searchForPeakPairs(theoreticalpeaks, theoreticalpeaksrealsize, experimentalpeaks, experimentalpeakmatches, parameters->fragmentmasserrortolerance); + + + // coverage of series + map > series; + for (int i = 0; i < parameters->fragmentionsfortheoreticalspectra.size(); i++) { + series[parameters->fragmentionsfortheoreticalspectra[i]].resize(intcomposition.size()); + } + + for (int i = 0; i < theoreticalpeaksrealsize; i++) { + if ((theoreticalpeaks[i].matched > 0) && (series.count(theoreticalpeaks[i].iontype) == 1)) { + series[theoreticalpeaks[i].iontype][theoreticalpeaks[i].seriesid]++; + } + } + + + // peak hits without parents are removed + if (parameters->clearhitswithoutparent) { + clearFalseHits(series, parameters->fragmentionsfortheoreticalspectra); + + for (int i = 0; i < theoreticalpeaksrealsize; i++) { + if ((theoreticalpeaks[i].matched > 0) && ((series.count(parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent) == 0) || (series[parameters->fragmentdefinitions[theoreticalpeaks[i].iontype].parent][theoreticalpeaks[i].seriesid] == 0))) { + experimentalpeakmatches[theoreticalpeaks[i].matchedid].erase(experimentalpeakmatches[theoreticalpeaks[i].matchedid].find(i)); + experimentalpeaks[theoreticalpeaks[i].matchedid].matched--; + + theoreticalpeaks[i].matched--; + theoreticalpeaks[i].matchedid = -1; + } + } + } + + + // 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 (writedescription) { + if (experimentalpeaks[i].description.compare("") != 0) { + experimentalpeaks[i].description += ", "; + } + experimentalpeaks[i].description += theoreticalpeaks[*it].description.substr(0,theoreticalpeaks[*it].description.find(':')); + experimentalpeaks[i].matchedrotations.push_back(theoreticalpeaks[*it].rotationid); + 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"; + } + + // to do + if (experimentalpeaks[i].iontype != fragmentIonTypeEnd) { + if ((experimentalpeaks[i].iontype != y_ion) && (theoreticalpeaks[*it].iontype == y_ion)) { + experimentalpeaks[i].iontype = y_ion; + } + } + else { + experimentalpeaks[i].iontype = theoreticalpeaks[*it].iontype; + } + } + } + + + if (writedescription) { + + coveragebyseries = "Series of matched peaks:
\n"; + for (int i = 0; i < (int)parameters->fragmentionsfortheoreticalspectra.size(); i++) { + coveragebyseries += parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].name + " "; + for (int j = 0; j < series[parameters->fragmentionsfortheoreticalspectra[i]].size() - 1; j++) { + coveragebyseries += to_string(series[parameters->fragmentionsfortheoreticalspectra[i]][j]); + if (j < series[parameters->fragmentionsfortheoreticalspectra[i]].size() - 2) { + coveragebyseries += " "; + } + } + coveragebyseries += "
\n"; + } + + } + + computeSomeStatistics(writedescription); + + return theoreticalpeaksrealsize; +} + + +int cTheoreticalSpectrum::getNumberOfPeaks() { + return theoreticalpeaks.size(); +} + + +int cTheoreticalSpectrum::getNumberOfMatchedPeaks() { + return experimentalpeaksmatched; +} + + +int cTheoreticalSpectrum::getNumberOfMatchedPeaks(fragmentIonType iontype) { + return matchedions[iontype]; +} + + +double cTheoreticalSpectrum::getRatioOfMatchedPeaks() { + return experimentalpeaksmatchedratio; +} + + +int cTheoreticalSpectrum::getNumberOfMatchedPeaksYB() { + return matchedions[y_ion]+matchedions[b_ion]; +} + + +void cTheoreticalSpectrum::printMatch(ofstream& os, peptideType peptidetype) { + vector rotations; + + os << endl << "Peptide: " << realpeptidename << endl; + + switch (peptidetype) + { + case linear: + case cyclic: + case linearpolysaccharide: + os << "Composition: " << candidate.getComposition(); + break; + case branched: + case lasso: + os << "Composition: " << candidate.getTComposition(); + break; + default: + break; + } + + if (valid) { + os << " (valid)"; + } + os << endl; + + os << "Number of bricks: " << getNumberOfBricks(candidate.getComposition()) << endl << endl; + + if ((peptidetype == linear) || (peptidetype == linearpolysaccharide)) { + os << "Modifications: "; + os << candidate.getStartModifID() << " " << candidate.getEndModifID() << endl; + } + + if (peptidetype == branched) { + os << "Modifications: "; + os << candidate.getStartModifID() << " " << candidate.getMiddleModifID() << " " << candidate.getEndModifID() << endl; + } + + if (peptidetype == lasso) { + os << "Modifications: "; + os << candidate.getMiddleModifID() << endl; + } + + os << "Coverage by series:" << endl; + os << coveragebyseries << endl; + + switch (peptidetype) + { + case linear: + os << "Matched y-ions and b-ions: " << matchedions[y_ion] + matchedions[b_ion] << endl; + os << "Matched y-ions: " << matchedions[y_ion] << endl; + os << "Matched b-ions: " << matchedions[b_ion] << endl; + os << "Matched a-ions: " << matchedions[a_ion] << endl; + os << "Matched y*-ions: " << matchedions[y_ion_water_loss] << endl; + os << "Matched b*-ions: " << matchedions[b_ion_water_loss] << endl; + os << "Matched a*-ions: " << matchedions[a_ion_water_loss] << endl; + os << "Matched yx-ions: " << matchedions[y_ion_ammonia_loss] << endl; + os << "Matched bx-ions: " << matchedions[b_ion_ammonia_loss] << endl; + os << "Matched ax-ions: " << matchedions[a_ion_ammonia_loss] << endl; + break; + case cyclic: + os << "Matched b-ions: " << matchedions[b_ion] << endl; + os << "Matched a-ions: " << matchedions[a_ion] << endl; + os << "Matched b*-ions: " << matchedions[b_ion_water_loss] << endl; + os << "Matched a*-ions: " << matchedions[a_ion_water_loss] << endl; + os << "Matched bx-ions: " << matchedions[b_ion_ammonia_loss] << endl; + os << "Matched ax-ions: " << matchedions[a_ion_ammonia_loss] << endl; + os << "Matched b*x-ions: " << matchedions[b_ion_water_and_ammonia_loss] << endl; + os << "Matched a*x-ions: " << matchedions[a_ion_water_and_ammonia_loss] << endl; + os << "Matched b-ions and b*-ions: " << matchedions[b_ion] + matchedions[b_ion_water_loss] << endl; + os << "Matched b-ions and bx-ions: " << matchedions[b_ion] + matchedions[b_ion_ammonia_loss] << endl << endl; + break; + case branched: + os << "Matched y-ions and b-ions: " << matchedions[y_ion] + matchedions[b_ion] << endl; + os << "Matched y-ions: " << matchedions[y_ion] << endl; + os << "Matched b-ions: " << matchedions[b_ion] << endl; + os << "Matched a-ions: " << matchedions[a_ion] << endl; + os << "Matched y*-ions: " << matchedions[y_ion_water_loss] << endl; + os << "Matched b*-ions: " << matchedions[b_ion_water_loss] << endl; + os << "Matched a*-ions: " << matchedions[a_ion_water_loss] << endl; + os << "Matched yx-ions: " << matchedions[y_ion_ammonia_loss] << endl; + os << "Matched bx-ions: " << matchedions[b_ion_ammonia_loss] << endl; + os << "Matched ax-ions: " << matchedions[a_ion_ammonia_loss] << endl; + break; + case lasso: + os << "Matched y-ions and b-ions: " << matchedions[y_ion] + matchedions[b_ion] << endl; + os << "Matched y-ions: " << matchedions[y_ion] << endl; + os << "Matched b-ions: " << matchedions[b_ion] << endl; + os << "Matched a-ions: " << matchedions[a_ion] << endl; + os << "Matched y*-ions: " << matchedions[y_ion_water_loss] << endl; + os << "Matched b*-ions: " << matchedions[b_ion_water_loss] << endl; + os << "Matched a*-ions: " << matchedions[a_ion_water_loss] << endl; + os << "Matched yx-ions: " << matchedions[y_ion_ammonia_loss] << endl; + os << "Matched bx-ions: " << matchedions[b_ion_ammonia_loss] << endl; + os << "Matched ax-ions: " << matchedions[a_ion_ammonia_loss] << endl; + break; + case linearpolysaccharide: + break; + default: + break; + } + + os << "Matched peaks: " << experimentalpeaksmatched << endl; + os << "Total peaks: " << peakstested << endl; + os << "Sum of Relative Intensities: " << intensityweightedscore << endl; + os << "Ratio of matched peaks: " << experimentalpeaksmatchedratio*100.0f << "%" << endl << endl; + os << "Unmatched measured peaks:" << endl << unmatchedpeaks << endl << endl; + os << "Theoretical peaks:" << endl << theoreticalpeaks.print(); +} + + +void cTheoreticalSpectrum::generateNTerminalFragmentIons(int maxcharge, int& peaklistrealsize, vector& stringcomposition, vector& intcomposition, fragmentIonType fragmentiontype, cBricksDatabase& bricksdatabase, bool writedescription, int rotationid, vector& splittingsites, vector& searchedmodifications, peptideType peptidetype, TRotationInfo* trotation) { + cPeak peak; + double tempratio; + string tempdescription; + + peak.mzratio = parameters->fragmentdefinitions[fragmentiontype].massdifference; + if ((peptidetype == linear) || (peptidetype == linearpolysaccharide)) { + peak.mzratio += searchedmodifications[candidate.getStartModifID()].massdifference; + } + if ((peptidetype == branched) || (peptidetype == lasso)) { + peak.mzratio += searchedmodifications[trotation->startmodifID].massdifference; + } + + peak.iontype = fragmentiontype; + peak.scrambled = false; + + switch (peptidetype) + { + case linear: + peak.rotationid = rotationid; + break; + case cyclic: + peak.rotationid = rotationid; + break; + case branched: + peak.rotationid = trotation->id; + break; + case lasso: + peak.rotationid = rotationid*6 + trotation->id; // to do - potential bug + break; + case linearpolysaccharide: + peak.rotationid = rotationid; + break; + default: + break; + } + + for (int i = 0; i < (int)intcomposition.size() - 1; i++) { + peak.mzratio += bricksdatabase[intcomposition[i] - 1].getMass(); + + + if ((peptidetype == branched) || (peptidetype == lasso)) { + if (i == trotation->middlebranchstart) { + peak.mzratio += searchedmodifications[trotation->middlemodifID].massdifference; + } + + if ((i >= trotation->middlebranchstart) && (i < trotation->middlebranchend)) { + continue; + } + + // redundant short n-term fragments are not generated + //if (((trotation->id == 3) || ((trotation->id == 4))) && (i < trotation->middlebranchstart)) { + // continue; + //} + + // redundant long n-term fragments are not generated + //if ((trotation->id == 1) && (i >= trotation->middlebranchend)) { + // continue; + //} + } + + peak.seriesid = i; + + if (writedescription) { + + peak.description = ""; + if (peptidetype == cyclic) { + peak.description += to_string(splittingsites[rotationid].first + 1) + "-" + to_string(splittingsites[rotationid].second + 1) + "_"; + } + if (peptidetype == branched) { + peak.description += to_string(peak.rotationid + 1) + "_"; + } + if (peptidetype == lasso) { + peak.description += to_string(splittingsites[rotationid].first + 1) + "-" + to_string(splittingsites[rotationid].second + 1) + "_"; + peak.description += to_string(trotation->id + 1) + "_"; + } + peak.description += parameters->fragmentdefinitions[fragmentiontype].name.substr(0, 1) + to_string(i + 1); + if (parameters->fragmentdefinitions[fragmentiontype].name.size() > 1) { + peak.description += parameters->fragmentdefinitions[fragmentiontype].name.substr(1, parameters->fragmentdefinitions[fragmentiontype].name.length() - 1); + } + peak.description += ": "; + for (int j = 0; j <= i; j++) { + peak.description += "[" + bricksdatabase[intcomposition[j] - 1].getAcronymsAsString() + "]"; + if (j < i) { + peak.description += '-'; + } + } + + } + + if (peak.mzratio > 0) { + + tempratio = peak.mzratio; + if (writedescription) { + tempdescription = peak.description; + } + for (int j = 1; j <= maxcharge; j++) { + + peak.mzratio = charge(tempratio, j); + peak.charge = j; + if (writedescription) { + peak.description = to_string(j) + "+ " + tempdescription; + } + + if (theoreticalpeaks.size() > peaklistrealsize) { + theoreticalpeaks[peaklistrealsize] = peak; + } + else { + theoreticalpeaks.add(peak); + } + peaklistrealsize++; + + } + peak.mzratio = tempratio; + if (writedescription) { + peak.description = tempdescription; + } + + } + + } + +} + + +void cTheoreticalSpectrum::generateCTerminalFragmentIons(int maxcharge, int& peaklistrealsize, vector& stringcomposition, vector& intcomposition, fragmentIonType fragmentiontype, cBricksDatabase& bricksdatabase, bool writedescription, int rotationid, vector& splittingsites, vector& searchedmodifications, peptideType peptidetype, TRotationInfo* trotation) { + cPeak peak; + double tempratio; + string tempdescription; + + peak.mzratio = parameters->fragmentdefinitions[fragmentiontype].massdifference; + if ((peptidetype == linear) || (peptidetype == linearpolysaccharide)) { + peak.mzratio += searchedmodifications[candidate.getEndModifID()].massdifference; + } + if ((peptidetype == branched) || (peptidetype == lasso)) { + peak.mzratio += searchedmodifications[trotation->endmodifID].massdifference; + } + + peak.iontype = fragmentiontype; + peak.scrambled = false; + + switch (peptidetype) + { + case linear: + peak.rotationid = rotationid; + break; + case cyclic: + peak.rotationid = rotationid; + break; + case branched: + peak.rotationid = trotation->id; + break; + case lasso: + peak.rotationid = rotationid*6 + trotation->id; // to do - potential bug + break; + case linearpolysaccharide: + peak.rotationid = rotationid; + break; + default: + break; + } + + for (int i = (int)intcomposition.size() - 1; i > 0; i--) { + peak.mzratio += bricksdatabase[intcomposition[i] - 1].getMass(); + + if ((peptidetype == branched) || (peptidetype == lasso)) { + if (i == trotation->middlebranchend) { + peak.mzratio += searchedmodifications[trotation->middlemodifID].massdifference; + } + + if ((i > trotation->middlebranchstart) && (i <= trotation->middlebranchend)) { + continue; + } + + // redundant short c-term fragments are not generated + //if (((trotation->id == 1) || (trotation->id == 5)) && (i > trotation->middlebranchend)) { + // continue; + //} + + // redundant long c-term fragments are not generated + //if ((trotation->id == 3) && (i <= trotation->middlebranchstart)) { + // continue; + //} + } + + peak.seriesid = (int)intcomposition.size() - i - 1; + + if (writedescription) { + + peak.description = ""; + //if (peptidetype == cyclic) { + // peak.description += to_string(splittingsites[rotationid].first + 1) + "-" + to_string(splittingsites[rotationid].second + 1); // +"_"; + //} + if (peptidetype == branched) { + peak.description += to_string(peak.rotationid + 1) + "_"; + } + if (peptidetype == lasso) { + peak.description += to_string(splittingsites[rotationid].first + 1) + "-" + to_string(splittingsites[rotationid].second + 1) + "_"; + peak.description += to_string(trotation->id + 1) + "_"; + } + peak.description += parameters->fragmentdefinitions[fragmentiontype].name.substr(0, 1) + to_string((int)intcomposition.size() - i); + + if (parameters->fragmentdefinitions[fragmentiontype].name.size() > 1) { + peak.description += parameters->fragmentdefinitions[fragmentiontype].name.substr(1, parameters->fragmentdefinitions[fragmentiontype].name.length() - 1); + } + peak.description += ": "; + for (int j = (int)intcomposition.size() - 1; j >= i; j--) { + peak.description += "[" + bricksdatabase[intcomposition[j] - 1].getAcronymsAsString() + "]"; + if (j > i) { + peak.description += '-'; + } + } + + } + + if (peak.mzratio > 0) { + + tempratio = peak.mzratio; + if (writedescription) { + tempdescription = peak.description; + } + for (int j = 1; j <= maxcharge; j++) { + + peak.mzratio = charge(tempratio, j); + peak.charge = j; + if (writedescription) { + peak.description = to_string(j) + "+ " + tempdescription; + } + + if (theoreticalpeaks.size() > peaklistrealsize) { + theoreticalpeaks[peaklistrealsize] = peak; + } + else { + theoreticalpeaks.add(peak); + } + peaklistrealsize++; + + } + peak.mzratio = tempratio; + if (writedescription) { + peak.description = tempdescription; + } + + } + + } + +} + + +void cTheoreticalSpectrum::sortByMass(int limit) { + theoreticalpeaks.sortbyMass(limit); +} + + +void cTheoreticalSpectrum::resizePeakList(int size) { + theoreticalpeaks.resize(size); +} + + +double cTheoreticalSpectrum::getPrecursorMass(cBricksDatabase& brickdatabasewithcombinations) { + return candidate.getPrecursorMass(brickdatabasewithcombinations, parameters); +} + + +double cTheoreticalSpectrum::getWeightedIntensityScore() { + return intensityweightedscore; +} + + +void cTheoreticalSpectrum::setRealPeptideName(cBricksDatabase& bricksdatabase, peptideType peptidetype) { + switch (peptidetype) + { + case linear: + case cyclic: + case linearpolysaccharide: + realpeptidename = bricksdatabase.getRealName(candidate.getComposition()); + break; + case branched: + case lasso: + realpeptidename = candidate.getRealNameTComposition(bricksdatabase); + break; + default: + realpeptidename = ""; + break; + } +} + + +void cTheoreticalSpectrum::setAcronymPeptideNameWithHTMLReferences(cBricksDatabase& bricksdatabase, peptideType peptidetype) { + switch (peptidetype) + { + case linear: + case cyclic: + case linearpolysaccharide: + acronympeptidename = bricksdatabase.getAcronymName(candidate.getComposition(), true); + break; + case branched: + case lasso: + acronympeptidename = candidate.getAcronymsTComposition(bricksdatabase); + break; + default: + acronympeptidename = ""; + break; + } +} + + +string& cTheoreticalSpectrum::getRealPeptideName() { + return realpeptidename; +} + + +string& cTheoreticalSpectrum::getAcronymPeptideNameWithHTMLReferences() { + return acronympeptidename; +} + + +cPeak& cTheoreticalSpectrum::operator[](int position) { + return theoreticalpeaks[position]; +} + + +cPeaksList& cTheoreticalSpectrum::getExperimentalSpectrum() { + return experimentalpeaks; +} + + +string cTheoreticalSpectrum::getCoverageBySeries() { + return coveragebyseries; +} + + +string cTheoreticalSpectrum::getUnmatchedPeaks() { + return unmatchedpeaks; +} + + +cPeaksList* cTheoreticalSpectrum::getTheoreticalPeaks() { + return &theoreticalpeaks; +} + + +bool cTheoreticalSpectrum::isValid() { + return valid; +} + + +int cTheoreticalSpectrum::getValidPosition() { + return validposition; +} + + +int cTheoreticalSpectrum::getReverseValidPosition() { + return reversevalidposition; +} + + +int cTheoreticalSpectrum::getNumberOfMatchedBricks() { + return maskscore; +} + + +vector& cTheoreticalSpectrum::getVisualCoverage() { + return visualcoverage; +} + + +void cTheoreticalSpectrum::setAcronyms(cBricksDatabase& bricksdatabase) { + vector bricks; + cBrick b; + b.clear(); + b.setComposition(candidate.getComposition(), false); + b.explodeToIntComposition(bricks); + + acronyms.clear(); + for (int i = 0; i < (int)bricks.size(); i++) { + acronyms.push_back(bricksdatabase[bricks[i] - 1].getAcronymsAsString()); + } +} + + +vector& cTheoreticalSpectrum::getAcronyms() { + return acronyms; +} + + +void cTheoreticalSpectrum::setPath(cDeNovoGraph& graph) { + cDeNovoGraphNode* currentnode; + cDeNovoGraphNode* targetnode; + cEdge* currentedge; + path = ""; + for (int i = 0; i < (int)candidate.getPath().size(); i++) { + currentnode = &graph[candidate.getPath()[i].nodeid]; + currentedge = &((*currentnode)[candidate.getPath()[i].edgeid]); + targetnode = &graph[currentedge->targetnode]; + + path += to_string(currentnode->getMZRatio()); + path += " -> "; + path += to_string(targetnode->getMZRatio()); + path += " using brick(s): "; + if (currentedge->composition.compare("0") == 0) { + path += "none"; + } + else { + path += graph.getBrickDatabaseWithCombinations()->getAcronymName(currentedge->composition, true); + } + + path += " (mass difference: " + to_string(currentedge->massdifference) + ", "; + path += "source intensity: " + to_string(currentnode->getIntensity()) + ", "; + path += "target intensity: " + to_string(targetnode->getIntensity()) + ", "; + path += "ppm error: " + to_string(currentedge->ppmerror) + ", "; + path += "source charge: " + to_string(currentedge->sourcecharge) + ", "; + path += "target charge: " + to_string(currentedge->targetcharge); + if ((parameters->peptidetype == branched) || (parameters->peptidetype == lasso)) { + if (currentedge->middlemodifID > 0) { + path += ", branch modification: " + parameters->searchedmodifications[currentedge->middlemodifID].name; + } + } + if (currentedge->endmodifID > 0) { + path += ", terminal modification: " + parameters->searchedmodifications[currentedge->endmodifID].name; + } + //path += currentedge->printSourceAnnotation(fragmentdefinitions); + //path += "->"; + //path += currentedge->printTargetAnnotation(fragmentdefinitions); + path += ")
"; + } +} + + +string& cTheoreticalSpectrum::getPath() { + return path; +} + + +int cTheoreticalSpectrum::getNumberOfCompletedSeries() { + return seriescompleted; +} + + +void cTheoreticalSpectrum::setNumberOfCompletedSeries(int numberofcompletedseries) { + seriescompleted = numberofcompletedseries; +} + + +void cTheoreticalSpectrum::setParameters(cParameters* parameters) { + this->parameters = parameters; +} + + +void cTheoreticalSpectrum::store(ofstream& os) { + int size; + + theoreticalpeaks.store(os); + experimentalpeaks.store(os); + candidate.store(os); + + os.write((char *)&experimentalpeaksmatched, sizeof(int)); + + size = (int)matchedions.size(); + os.write((char *)&size, sizeof(int)); + for (map::iterator it = matchedions.begin(); it != matchedions.end(); ++it) { + os.write((char *)&it->first, sizeof(fragmentIonType)); + os.write((char *)&it->second, sizeof(int)); + } + + 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()); + + os.write((char *)&valid, sizeof(bool)); + os.write((char *)&intensityweightedscore, sizeof(double)); + os.write((char *)&maskscore, sizeof(int)); + + size = (int)visualcoverage.size(); + os.write((char *)&size, sizeof(int)); + for (int i = 0; i < (int)visualcoverage.size(); i++) { + visualcoverage[i].store(os); + } + + os.write((char *)&validposition, sizeof(int)); + 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)path.size(); + os.write((char *)&size, sizeof(int)); + os.write(path.c_str(), path.size()); +} + + +void cTheoreticalSpectrum::load(ifstream& is) { + int size; + fragmentIonType iontype; + int number; + + parameters = 0; + + theoreticalpeaks.load(is); + experimentalpeaks.load(is); + candidate.load(is); + + is.read((char *)&experimentalpeaksmatched, sizeof(int)); + + is.read((char *)&size, sizeof(int)); + matchedions.clear(); + for (int i = 0; i < size; i++) { + is.read((char *)&iontype, sizeof(fragmentIonType)); + is.read((char *)&number, sizeof(int)); + matchedions[iontype] = number; + } + + 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()); + + is.read((char *)&valid, sizeof(bool)); + is.read((char *)&intensityweightedscore, sizeof(double)); + is.read((char *)&maskscore, sizeof(int)); + + is.read((char *)&size, sizeof(int)); + visualcoverage.resize(size); + for (int i = 0; i < (int)visualcoverage.size(); i++) { + visualcoverage[i].load(is); + } + + is.read((char *)&validposition, sizeof(int)); + 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)); + path.resize(size); + is.read(&path[0], path.size()); +} + diff --git a/CycloBranch/core/cTheoreticalSpectrum.h b/CycloBranch/core/cTheoreticalSpectrum.h new file mode 100644 index 0000000..5eb62c2 --- /dev/null +++ b/CycloBranch/core/cTheoreticalSpectrum.h @@ -0,0 +1,518 @@ +/** + \file cTheoreticalSpectrum.h + \brief The representation of a theoretical mass spectrum. +*/ + + +#ifndef _CTHEORETICALSPECTRUM_H +#define _CTHEORETICALSPECTRUM_H + +#include +#include +#include +#include +#include +#include + +#include "core/cParameters.h" +#include "core/cPeaksList.h" +#include "core/cCandidateSet.h" + +class cMainThread; +class cDeNovoGraph; + + +using namespace std; + + +/** + \brief The structure representing a splitting site of a cyclic peptide. +*/ +struct splitSite { + + /** + \brief Order of the first amino acid where a cyclic peptide is split. + */ + int first; + + /** + \brief Order of the second amino acid where a cyclic peptide is split. + */ + int second; + + splitSite() { + first = 0; + second = 0; + } +}; + + +/** + \brief An auxiliary structure for visualisation of matched series of a cyclic peptide. +*/ +struct visualSeries { + + /** + \brief A vector of matched peaks in a series. + */ + vector series; + + + /** + \brief A name of a series of fragment ions. + */ + string name; + + + /** + \brief The constructor. + */ + visualSeries() { + series.clear(); + name = ""; + } + + + /** + \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 The class representing a theoretical mass spectrum. +*/ +class cTheoreticalSpectrum { + + cParameters* parameters; + cPeaksList theoreticalpeaks; + cPeaksList experimentalpeaks; + cCandidate candidate; + int experimentalpeaksmatched; + map matchedions; + int peakstested; + double experimentalpeaksmatchedratio; + string unmatchedpeaks; + string coveragebyseries; + bool valid; + double intensityweightedscore; + int maskscore; + vector visualcoverage; + int validposition; + int reversevalidposition; + int seriescompleted; + + string realpeptidename; + string acronympeptidename; + vector acronyms; + string path; + + // remove false hits, i.e., b-H2O without existing b-ion + void clearFalseHits(map >& series, vector& fragmentions); + + // search for matches of experimental and theoretical peaks + void searchForPeakPairs(cPeaksList& theoreticalpeaks, int theoreticalpeaksrealsize, cPeaksList& experimentalpeaks, vector >& experimentalpeakmatches, double fragmentmasserrortolerance); + + // compute some scores, etc. + void computeSomeStatistics(bool writedescription); + + // generate scrambled sequences + void generateScrambledIons(cBricksDatabase& bricksdatabase, bool writedescription, int& theoreticalpeaksrealsize); + + // normalize scrambled sequences + void normalizeScrambledSequences(unordered_set& scrambledsequences); + + // select a proper fragment ion type for an experimental peak when masses of more theoretical fragment ions collide + fragmentIonType selectHigherPriorityIonType(fragmentIonType experimentalpeakiontype, fragmentIonType theoreticalpeakiontype); + +public: + + + /** + \brief The constructor. + */ + cTheoreticalSpectrum(); + + + /** + \brief The constructor. + \param parameters a pointer to the parameters of the application + \param candidate reference to a peptide sequence candidate + */ + cTheoreticalSpectrum(cParameters* parameters, cCandidate& candidate); + + + /** + \brief Clear the spectrum. + \param clearpeaklist if true then all variables including the list of theoretical peaks are cleared else the list of theoretical peaks is not cleared + */ + void clear(bool clearpeaklist = true); + + + /** + \brief Get the peptide spectrum candidate. + \retval cCandidate reference to the peptide sequence candidate + */ + cCandidate& cTheoreticalSpectrum::getCandidate(); + + + /** + \brief Set a peptide spectrum candidate. + \param candidate reference to the peptide sequence candidate + */ + void cTheoreticalSpectrum::setCandidate(cCandidate& candidate); + + + /** + \brief Get the number of peaks in the spectrum. + \retval int the number of peaks + */ + int getNumberOfPeaks(); + + + /** + \brief Compare the theoretical spectrum of a branched peptide with an experimental spectrum. + \param sortedpeaklist reference to a peak list of an experimental spectrum + \param bricksdatabasewithcombinations reference to a database of bricks with combinations of bricks + \param writedescription if true then string descriptions of peaks are filled + \param sequencetag reference to a regex of a sequence tag + \param searchedsequence reference to a regex of a searched sequence + \retval int number theoretical peaks generated; -2 when the sequence tag does not match the peptide sequence candidate + */ + int compareBranched(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence); + + + /** + \brief Compare the theoretical spectrum of a linear peptide with an experimental spectrum. + \param sortedpeaklist reference to a peak list of an experimental spectrum + \param bricksdatabasewithcombinations reference to a database of bricks with combinations of bricks + \param writedescription if true then string descriptions of peaks are filled + \param sequencetag reference to a regex of a sequence tag + \param searchedsequence reference to a regex of a searched sequence + \retval int number theoretical peaks generated; -2 when the sequence tag does not match the peptide sequence candidate + */ + int compareLinear(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence); + + + /** + \brief Compare the theoretical spectrum of a cyclic peptide with an experimental spectrum. + \param sortedpeaklist reference to a peak list of an experimental spectrum + \param bricksdatabasewithcombinations reference to a database of bricks with combinations of bricks + \param writedescription if true then string descriptions of peaks are filled + \param sequencetag reference to a regex of a sequence tag + \param searchedsequence reference to a regex of a searched sequence + \retval int number theoretical peaks generated; -2 when the sequence tag does not match the peptide sequence candidate + */ + int compareCyclic(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence); + + + /** + \brief Compare the theoretical spectrum of a lasso peptide with an experimental spectrum. + \param sortedpeaklist reference to a peak list of an experimental spectrum + \param bricksdatabasewithcombinations reference to a database of bricks with combinations of bricks + \param writedescription if true then string descriptions of peaks are filled + \param sequencetag reference to a regex of a sequence tag + \param searchedsequence reference to a regex of a searched sequence + \retval int number theoretical peaks generated; -2 when the sequence tag does not match the peptide sequence candidate + */ + int compareLasso(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence); + + + /** + \brief Compare the theoretical spectrum of a linear polysaccharide with an experimental spectrum. + \param sortedpeaklist reference to a peak list of an experimental spectrum + \param bricksdatabasewithcombinations reference to a database of bricks with combinations of bricks + \param writedescription if true then string descriptions of peaks are filled + \param sequencetag reference to a regex of a sequence tag + \param searchedsequence reference to a regex of a searched sequence + \retval int number theoretical peaks generated; -2 when the sequence tag does not match the peptide sequence candidate + */ + int compareLinearPolysaccharide(cPeaksList& sortedpeaklist, cBricksDatabase& bricksdatabasewithcombinations, bool writedescription, regex& sequencetag, regex& searchedsequence); + + + /** + \brief Get the number of matched peaks between an experimental and a theoretical spectrum. + \retval int number of matched peaks + */ + int getNumberOfMatchedPeaks(); + + + /** + \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 + \retval int number of matched peaks + */ + int getNumberOfMatchedPeaks(fragmentIonType iontype); + + + /** + \brief Get the number of matched Y and B ions between an experimental and a theoretical spectrum. + \retval int number of matched peaks + */ + int getNumberOfMatchedPeaksYB(); + + + /** + \brief Get a ratio of matched peaks. + \retval double ratio of matched peaks + */ + double getRatioOfMatchedPeaks(); + + + /** + \brief Print a peptide-spectrum match into a stream. + \param os reference to an ouput stream + \param peptidetype the type of peptide corresponding to the experimental spectrum + */ + void printMatch(ofstream& os, peptideType peptidetype); + + + /** + \brief Generate a N-terminal fragment ion series. + \param maxcharge a charge of precursor ion + \param peaklistrealsize real size of the peak list + \param stringcomposition reference to a vector of ids of bricks as strings + \param intcomposition reference to a vector of ids of bricks as integers + \param fragmentiontype fragment ion type which will be generated + \param bricksdatabase reference to a database of building blocks + \param writedescription if true then string descriptions of fragment ions are generated + \param rotationid id of a cyclic peptide + \param splittingsites reference to a vector of splitting sites of a cyclic peptide + \param searchedmodifications reference to a vector of searched modifications + \param peptidetype the type of searched peptide + \param trotation a pointer to a T-permutation of a branched peptide + */ + void generateNTerminalFragmentIons(int maxcharge, int& peaklistrealsize, vector& stringcomposition, vector& intcomposition, fragmentIonType fragmentiontype, cBricksDatabase& bricksdatabase, bool writedescription, int rotationid, vector& splittingsites, vector& searchedmodifications, peptideType peptidetype, TRotationInfo* trotation = 0); + + + /** + \brief Generate a C-terminal fragment ion series. + \param maxcharge a charge of precursor ion + \param peaklistrealsize real size of the peak list + \param stringcomposition reference to a vector of ids of bricks as strings + \param intcomposition reference to a vector of ids of bricks as integers + \param fragmentiontype fragment ion type which will be generated + \param bricksdatabase reference to a database of building blocks + \param writedescription if true then string descriptions of fragment ions are generated + \param rotationid id of a cyclic peptide + \param splittingsites reference to a vector of splitting sites of a cyclic peptide + \param searchedmodifications reference to a vector of searched modifications + \param peptidetype the type of searched peptide + \param trotation a pointer to a T-permutation of a branched peptide + */ + void generateCTerminalFragmentIons(int maxcharge, int& peaklistrealsize, vector& stringcomposition, vector& intcomposition, fragmentIonType fragmentiontype, cBricksDatabase& bricksdatabase, bool writedescription, int rotationid, vector& splittingsites, vector& searchedmodifications, peptideType peptidetype, TRotationInfo* trotation = 0); + + + /** + \brief Sort peaks by mass. + \param limit sort first \a limit peaks only; if \a limit == -1 then all peaks are sorted + */ + void sortByMass(int limit = -1); + + + /** + \brief Resize the list of peaks. + \param size the number of peaks + */ + void resizePeakList(int size); + + + /** + \brief Get the precursor mass of the peptide sequence candidate. + \param brickdatabasewithcombinations reference to an input database of bricks with combinations of bricks + \retval double precursor mass of the candidate + */ + double getPrecursorMass(cBricksDatabase& brickdatabasewithcombinations); + + + /** + \brief Get the sum of relative intensities of matched peaks. + \retval double sum of relative intensities of matched peaks + */ + double getWeightedIntensityScore(); + + + /** + \brief Set a real peptide name. + \param bricksdatabase the database of building blocks + \param peptidetype the type of peptide + */ + void setRealPeptideName(cBricksDatabase& bricksdatabase, peptideType peptidetype); + + + /** + \brief Set an acronym peptide name. + \param bricksdatabase the database of building blocks + \param peptidetype the type of peptide + */ + void setAcronymPeptideNameWithHTMLReferences(cBricksDatabase& bricksdatabase, peptideType peptidetype); + + + /** + \brief Get a real peptide name. + \retval string reference to the real peptide name + */ + string& getRealPeptideName(); + + + /** + \brief Get an acronym peptide name. + \retval string reference to the acronym peptide name + */ + string& getAcronymPeptideNameWithHTMLReferences(); + + + /** + \brief Overloaded operator []. + \param position position of a peak in the peak list + \retval cPeak reference to the peak + */ + cPeak& operator[](int position); + + + /** + \brief Get an experimental spectrum which has been compared with the theoretical spectrum. + \retval cPeaksList reference to an experimental spectrum + */ + cPeaksList& getExperimentalSpectrum(); + + + /** + \brief Get coverage of series of fragment ions. + \retval string coverage of the series of fragment ions + */ + string getCoverageBySeries(); + + + /** + \brief Get list of unmatched peaks. + \retval string list of unmatched peaks + */ + string getUnmatchedPeaks(); + + + /** + \brief Access to the list of theoretical peaks. + \retval cPeaksList pointer to a list of theoretical peaks + */ + cPeaksList* getTheoreticalPeaks(); + + + /** + \brief Check whether the theoretical spectrum corresponds to a searched sequence. + \retval bool if true then the theoretical spectrum corresponds to a searched sequence + */ + bool isValid(); + + + /** + \brief Get a position of a rotation of a cyclic peptide sequence corresponding to searched sequence. + \retval int position of sequence + */ + int getValidPosition(); + + + /** + \brief Get a reverted position of a rotation of a cyclic peptide sequence corresponding to searched sequence. + \retval int reverted position of sequence + */ + int getReverseValidPosition(); + + + /** + \brief Get the number of matched bricks. + \retval int number of matched bricks + */ + int getNumberOfMatchedBricks(); + + + /** + \brief Get a vector of fragment ion series for visualization. + \retval vector vector of fragment ion series for visualisation + */ + vector& getVisualCoverage(); + + + /** + \brief Set a vector of acronyms corresponding to a peptide sequence candidate. + \param bricksdatabase a database of building blocks + */ + void setAcronyms(cBricksDatabase& bricksdatabase); + + + /** + \brief Get a vector of acronyms corresponding to a peptide sequence candidate. + \retval vector a vector of acronyms + */ + vector& getAcronyms(); + + + /** + \brief Set a path in the de novo graph corresponding to the spectrum. + \param graph reference to the de novo graph + */ + void setPath(cDeNovoGraph& graph); + + + /** + \brief Get a path in the de novo graph corresponding to the spectrum. + \retval string reference to a path corresponding to the spectrum + */ + string& getPath(); + + + /** + \brief Get a number of series which identify the peptide. + \retval int number of completed series + */ + int getNumberOfCompletedSeries(); + + + /** + \brief Set a number of series which identify the peptide. + \param numberofcompletedseries number of completed series + */ + void setNumberOfCompletedSeries(int numberofcompletedseries); + + + /** + \brief Set a pointer to the parameters of the application. + \param parameters the pointer to the parameters of the application + */ + void setParameters(cParameters* parameters); + + + /** + \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 Register cTheoreticalSpectrum by Qt. +*/ +Q_DECLARE_METATYPE(cTheoreticalSpectrum); + + +#endif + diff --git a/CycloBranch/core/cTheoreticalSpectrumList.cpp b/CycloBranch/core/cTheoreticalSpectrumList.cpp new file mode 100644 index 0000000..c55fc44 --- /dev/null +++ b/CycloBranch/core/cTheoreticalSpectrumList.cpp @@ -0,0 +1,469 @@ +#include "core/cTheoreticalSpectrumList.h" + +#include "gui/cMainThread.h" + + +double cTheoreticalSpectrumList::getCurrentWorstScore() { + QMutexLocker ml(&mutex); + return worstScore; +} + + +void cTheoreticalSpectrumList::computeNumbersOfCompletedSeries() { + for (int i = 0; i < (int)theoreticalspectra.size(); i++) { + for (int j = i + 1; j < (int)theoreticalspectra.size(); j++) {\ + if (theoreticalspectra[i].getCandidate().hasEqualTPermutations(theoreticalspectra[j].getCandidate())) { + theoreticalspectra[i].setNumberOfCompletedSeries(theoreticalspectra[i].getNumberOfCompletedSeries() + 1); + theoreticalspectra[j].setNumberOfCompletedSeries(theoreticalspectra[j].getNumberOfCompletedSeries() + 1); + } + } + } +} + + +void cTheoreticalSpectrumList::fixRegularExpression(string& s) { + if (s.size() == 0) { + return; + } + + bool fixbegin = false; + bool fixend = false; + + if ((s[0] >= '0') && (s[0] <= '9')) { + fixbegin = true; + } + + if ((s[s.size() - 1] >= '0') && (s[s.size() - 1] <= '9')) { + fixend = true; + } + + if (fixbegin) { + s = "(^|[^0-9])" + s; + } + + if (fixend) { + s += "($|[^0-9])"; + } +} + + +cTheoreticalSpectrumList::cTheoreticalSpectrumList() { + theoreticalspectra.clear(); + os = 0; + parameters = 0; + graph = 0; + + worstScore = 0; + worstNumberOfMatchedPeaks = 0; +} + + +void cTheoreticalSpectrumList::initialize(cMainThread& os, cParameters& parameters, cDeNovoGraph* graph) { + this->os = &os; + this->parameters = ¶meters; + this->graph = graph; + + refreshlimit = parameters.hitsreported + 500; +} + + +void cTheoreticalSpectrumList::add(cTheoreticalSpectrum& theoreticalspectrum) { + theoreticalspectra.push_back(theoreticalspectrum); +} + + +int cTheoreticalSpectrumList::size() { + return (int)theoreticalspectra.size(); +} + + +cTheoreticalSpectrum& cTheoreticalSpectrumList::operator[](int position) { + return theoreticalspectra[position]; +} + + +int cTheoreticalSpectrumList::parallelCompareAndStore(cCandidateSet& candidates, bool& terminatecomputation) { + cPeaksList peaklist = parameters->peaklist; + peaklist.sortbyMass(); + cCandidateSet permutations; + theoreticalspectra.clear(); + regex rxsequencetag, rxsearchedsequence; + cSpectrumComparatorThread* comparatorthread; + string stmp; + cBricksDatabase* bricksdb = (parameters->mode == 0) ? graph->getBrickDatabaseWithCombinations() : ¶meters->bricksdatabase; + vector resultspectra; + //int pos; + + int theoreticalpeaksrealsize = 0; + worstScore = 0; + worstNumberOfMatchedPeaks = 0; + + stmp = parameters->sequencetag; + fixRegularExpression(stmp); + + /* + pos = (int)stmp.find("("); + if (pos != string::npos) { + stmp.replace(pos, 1, "\\("); + } + pos = (int)stmp.find(")"); + if (pos != string::npos) { + stmp.replace(pos, 1, "\\)"); + } + */ + + try { + rxsequencetag = stmp; + } + catch (const std::regex_error& e) { + *os << endl << endl << "Error: Bad Regular Expression in Peptide Sequence Tag." << endl << e.what() << endl; + return -1; + } + + stmp = parameters->searchedsequence; + fixRegularExpression(stmp); + + /* + pos = (int)stmp.find("("); + if (pos != string::npos) { + stmp.replace(pos, 1, "\\("); + } + pos = (int)stmp.find(")"); + if (pos != string::npos) { + stmp.replace(pos, 1, "\\)"); + } + */ + + try { + rxsearchedsequence = stmp; + } + catch (const std::regex_error& e) { + *os << endl << endl << "Error: Bad Regular Expression in Searched Peptide Sequence." << endl << e.what() << endl; + return -1; + } + + if (parameters->mode == 0) { + + QThreadPool::globalInstance()->setMaxThreadCount(parameters->maximumnumberofthreads); + + // compare theoretical spectra with the peaklist in parallel + int i = 0; + int size; + candidates.lock(); + size = candidates.size(); + candidates.unlock(); + while ((size > 0) || (os->isGraphReaderWorking())) { + + if (terminatecomputation) { + break; + } + + if ((QThreadPool::globalInstance()->activeThreadCount() < QThreadPool::globalInstance()->maxThreadCount()) && (size > 0)) { + comparatorthread = new cSpectrumComparatorThread(); + candidates.lock(); + auto x = candidates.getSet().begin(); + comparatorthread->initialize((cCandidate&)(*x), peaklist, bricksdb, this, parameters, &rxsequencetag, &rxsearchedsequence, getCurrentWorstScore(), &terminatecomputation); + candidates.getSet().erase(candidates.getSet().begin()); + candidates.unlock(); + QThreadPool::globalInstance()->start(comparatorthread); + + if ((i % 100 == 0) && (i > 0)) { + *os << "."; + } + + if ((i % 1000 == 0) && (i > 0)) { + *os << i << " "; + } + + if ((i % 10000 == 0) && (i > 0)) { + *os << "(Remaining candidates in buffer: " << size << "; Are they all ?: " << (os->isGraphReaderWorking() ? "no" : "yes") << ")" << endl; + } + + i++; + } + else { + os->usleep(100); + } + + candidates.lock(); + size = candidates.size(); + candidates.unlock(); + + } + + QThreadPool::globalInstance()->waitForDone(); + + while (os->isGraphReaderWorking()) { + os->usleep(1000); + } + + sortAndFitSize(); + + } + else { + + cTheoreticalSpectrum t(parameters, (cCandidate &)(*candidates.getSet().begin())); + theoreticalspectra.push_back(t); + + } + + cTheoreticalSpectrum tsp; + tsp.resizePeakList(5000); + + // fill descriptions of peaks + resultspectra.resize(theoreticalspectra.size()); + for (int i = 0; i < (int)theoreticalspectra.size(); i++) { + + tsp.clear(false); + tsp.setParameters(parameters); + tsp.setCandidate(theoreticalspectra[i].getCandidate()); + + switch (parameters->peptidetype) + { + case linear: + theoreticalpeaksrealsize = tsp.compareLinear(peaklist, *bricksdb, true, rxsequencetag, rxsearchedsequence); + break; + case cyclic: + theoreticalpeaksrealsize = tsp.compareCyclic(peaklist, *bricksdb, true, rxsequencetag, rxsearchedsequence); + break; + case branched: + theoreticalpeaksrealsize = tsp.compareBranched(peaklist, *bricksdb, true, rxsequencetag, rxsearchedsequence); + break; + case lasso: + theoreticalpeaksrealsize = tsp.compareLasso(peaklist, *bricksdb, true, rxsequencetag, rxsearchedsequence); + break; + case linearpolysaccharide: + theoreticalpeaksrealsize = tsp.compareLinearPolysaccharide(peaklist, *bricksdb, true, rxsequencetag, rxsearchedsequence); + break; + default: + break; + } + + // invalid sequence tag + if (theoreticalpeaksrealsize == -2) { + continue; + } + resultspectra[i] = tsp; + resultspectra[i].resizePeakList(theoreticalpeaksrealsize); + } + + theoreticalspectra = resultspectra; + + //computeNumbersOfCompletedSeries(); + + // sort peaks in theoretical spectra by mass and set real names of peptides + for (int i = 0; i < (int)theoreticalspectra.size(); i++) { + theoreticalspectra[i].sortByMass(); + theoreticalspectra[i].setRealPeptideName(*bricksdb, parameters->peptidetype); + theoreticalspectra[i].setAcronymPeptideNameWithHTMLReferences(*bricksdb, parameters->peptidetype); + theoreticalspectra[i].setAcronyms(*bricksdb); + if (parameters->mode == 0) { + theoreticalspectra[i].setPath(*graph); + } + // parameters must not be used by viewer, they are not stored/loaded + theoreticalspectra[i].setParameters(0); + } + + // -1 = partial results, aborted by user + return terminatecomputation ? -1 : 0; +} + + +void cTheoreticalSpectrumList::printPeptideSpectrumMatches(ofstream& os, int limit, peptideType peptidetype) { + int count = min(limit, (int)theoreticalspectra.size()); + for (int i = 0; i < count; i++) { + os << "--------------------------------------------------------------------------------" << endl; + os << "Peptide-Spectrum Match no. " << i+1 << endl; + theoreticalspectra[i].printMatch(os, peptidetype); + } +} + + +void cTheoreticalSpectrumList::addButDoNotFitSize(cTheoreticalSpectrum& theoreticalspectrum, int theoreticalpeaksrealsize) { + QMutexLocker ml(&mutex); + + if ((int)theoreticalspectra.size() < parameters->hitsreported) { + + theoreticalspectra.push_back(theoreticalspectrum); + theoreticalspectra.back().resizePeakList(theoreticalpeaksrealsize); + + if ((int)theoreticalspectra.size() == parameters->hitsreported) { + switch (parameters->scoretype) { + case b_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareBandAllIonsDesc); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaks(b_ion); + break; + case b_ions_and_b_water_loss_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareBBwaterLossAndAllIonsDesc); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaks(b_ion) + theoreticalspectra.back().getNumberOfMatchedPeaks(b_ion_water_loss); + break; + case b_ions_and_b_ammonia_loss_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareBBammoniaLossAndAllIonsDesc); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaks(b_ion) + theoreticalspectra.back().getNumberOfMatchedPeaks(b_ion_ammonia_loss); + break; + case y_ions_and_b_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareYBandAllIonsDesc); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaksYB(); + break; + case y_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareYandAllIonsDesc); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaks(y_ion); + break; + case weighted_intensity: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareWeightedIntensityDesc); + worstScore = theoreticalspectra.back().getWeightedIntensityScore(); + break; + case matched_peaks: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareNumberOfMatchedPeaksDesc); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaks(); + break; + case matched_bricks: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareNumberOfMatchedBricksDesc); + worstScore = theoreticalspectra.back().getNumberOfMatchedBricks(); + break; + } + worstNumberOfMatchedPeaks = theoreticalspectra.back().getNumberOfMatchedPeaks(); + } + + } + else { + + switch (parameters->scoretype) { + case b_ions: + if ((worstScore < theoreticalspectrum.getNumberOfMatchedPeaks(b_ion)) || ((worstScore == theoreticalspectrum.getNumberOfMatchedPeaks(b_ion)) && (worstNumberOfMatchedPeaks < theoreticalspectrum.getNumberOfMatchedPeaks()))) { + theoreticalspectra.push_back(theoreticalspectrum); + theoreticalspectra.back().resizePeakList(theoreticalpeaksrealsize); + } + break; + case b_ions_and_b_water_loss_ions: + if ((worstScore < theoreticalspectrum.getNumberOfMatchedPeaks(b_ion) + theoreticalspectrum.getNumberOfMatchedPeaks(b_ion_water_loss)) || ((worstScore == theoreticalspectrum.getNumberOfMatchedPeaks(b_ion) + theoreticalspectrum.getNumberOfMatchedPeaks(b_ion_water_loss)) && (worstNumberOfMatchedPeaks < theoreticalspectrum.getNumberOfMatchedPeaks()))) { + theoreticalspectra.push_back(theoreticalspectrum); + theoreticalspectra.back().resizePeakList(theoreticalpeaksrealsize); + } + break; + case b_ions_and_b_ammonia_loss_ions: + if ((worstScore < theoreticalspectrum.getNumberOfMatchedPeaks(b_ion) + theoreticalspectrum.getNumberOfMatchedPeaks(b_ion_ammonia_loss)) || ((worstScore == theoreticalspectrum.getNumberOfMatchedPeaks(b_ion) + theoreticalspectrum.getNumberOfMatchedPeaks(b_ion_ammonia_loss)) && (worstNumberOfMatchedPeaks < theoreticalspectrum.getNumberOfMatchedPeaks()))) { + theoreticalspectra.push_back(theoreticalspectrum); + theoreticalspectra.back().resizePeakList(theoreticalpeaksrealsize); + } + break; + case y_ions_and_b_ions: + if ((worstScore < theoreticalspectrum.getNumberOfMatchedPeaksYB()) || ((worstScore == theoreticalspectrum.getNumberOfMatchedPeaksYB()) && (worstNumberOfMatchedPeaks < theoreticalspectrum.getNumberOfMatchedPeaks()))) { + theoreticalspectra.push_back(theoreticalspectrum); + theoreticalspectra.back().resizePeakList(theoreticalpeaksrealsize); + } + break; + case y_ions: + if (worstScore < theoreticalspectrum.getNumberOfMatchedPeaks(y_ion)) { + theoreticalspectra.push_back(theoreticalspectrum); + theoreticalspectra.back().resizePeakList(theoreticalpeaksrealsize); + } + break; + case weighted_intensity: + if (worstScore < theoreticalspectrum.getWeightedIntensityScore()) { + theoreticalspectra.push_back(theoreticalspectrum); + theoreticalspectra.back().resizePeakList(theoreticalpeaksrealsize); + } + break; + case matched_peaks: + if (worstScore < theoreticalspectrum.getNumberOfMatchedPeaks()) { + theoreticalspectra.push_back(theoreticalspectrum); + theoreticalspectra.back().resizePeakList(theoreticalpeaksrealsize); + } + break; + case matched_bricks: + if (worstScore < theoreticalspectrum.getNumberOfMatchedBricks()) { + theoreticalspectra.push_back(theoreticalspectrum); + theoreticalspectra.back().resizePeakList(theoreticalpeaksrealsize); + } + break; + } + + if ((int)theoreticalspectra.size() >= refreshlimit) { + + switch (parameters->scoretype) { + case b_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareBandAllIonsDesc); + theoreticalspectra.resize(parameters->hitsreported); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaks(b_ion); + break; + case b_ions_and_b_water_loss_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareBBwaterLossAndAllIonsDesc); + theoreticalspectra.resize(parameters->hitsreported); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaks(b_ion) + theoreticalspectra.back().getNumberOfMatchedPeaks(b_ion_water_loss); + break; + case b_ions_and_b_ammonia_loss_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareBBammoniaLossAndAllIonsDesc); + theoreticalspectra.resize(parameters->hitsreported); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaks(b_ion) + theoreticalspectra.back().getNumberOfMatchedPeaks(b_ion_ammonia_loss); + break; + case y_ions_and_b_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareYBandAllIonsDesc); + theoreticalspectra.resize(parameters->hitsreported); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaksYB(); + break; + case y_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareYandAllIonsDesc); + theoreticalspectra.resize(parameters->hitsreported); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaks(y_ion); + break; + case weighted_intensity: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareWeightedIntensityDesc); + theoreticalspectra.resize(parameters->hitsreported); + worstScore = theoreticalspectra.back().getWeightedIntensityScore(); + break; + case matched_peaks: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareNumberOfMatchedPeaksDesc); + theoreticalspectra.resize(parameters->hitsreported); + worstScore = theoreticalspectra.back().getNumberOfMatchedPeaks(); + break; + case matched_bricks: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareNumberOfMatchedBricksDesc); + theoreticalspectra.resize(parameters->hitsreported); + worstScore = theoreticalspectra.back().getNumberOfMatchedBricks(); + break; + } + + worstNumberOfMatchedPeaks = theoreticalspectra.back().getNumberOfMatchedPeaks(); + + } + } + +} + + +void cTheoreticalSpectrumList::sortAndFitSize() { + + switch (parameters->scoretype) { + case b_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareBandAllIonsDesc); + break; + case b_ions_and_b_water_loss_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareBBwaterLossAndAllIonsDesc); + break; + case b_ions_and_b_ammonia_loss_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareBBammoniaLossAndAllIonsDesc); + break; + case y_ions_and_b_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareYBandAllIonsDesc); + break; + case y_ions: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareYandAllIonsDesc); + break; + case weighted_intensity: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareWeightedIntensityDesc); + break; + case matched_peaks: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareNumberOfMatchedPeaksDesc); + break; + case matched_bricks: + sort(theoreticalspectra.begin(), theoreticalspectra.end(), compareNumberOfMatchedBricksDesc); + break; + } + + if ((int)theoreticalspectra.size() > parameters->hitsreported) { + theoreticalspectra.resize(parameters->hitsreported); + } + +} + diff --git a/CycloBranch/core/cTheoreticalSpectrumList.h b/CycloBranch/core/cTheoreticalSpectrumList.h new file mode 100644 index 0000000..5d881a0 --- /dev/null +++ b/CycloBranch/core/cTheoreticalSpectrumList.h @@ -0,0 +1,115 @@ +/** + \file cTheoreticalSpectrumList.h + \brief The representation of a list of theoretical mass spectra. +*/ + + +#ifndef _CTHEORETICALSPECTRUMLIST_H +#define _CTHEORETICALSPECTRUMLIST_H + +#include +#include + +#include "parallel/cSpectrumComparatorThread.h" + +class cMainThread; + + +/** + \brief The class representing a list of theoretical spectra. +*/ +class cTheoreticalSpectrumList { + + vector theoreticalspectra; + cMainThread* os; + cParameters* parameters; + cDeNovoGraph* graph; + + double worstScore; + int worstNumberOfMatchedPeaks; + int refreshlimit; + + QMutex mutex; + + double getCurrentWorstScore(); + + void computeNumbersOfCompletedSeries(); + + void fixRegularExpression(string& s); + +public: + + + /** + \brief The constructor. + */ + cTheoreticalSpectrumList(); + + + /** + \brief Initialize the list. + \param os reference to the main thread of the application + \param parameters reference to the parameters of the application + \param graph pointer to the de novo graph + */ + void initialize(cMainThread& os, cParameters& parameters, cDeNovoGraph* graph); + + + /** + \brief Add a spectrum to the list. + \param theoreticalspectrum reference to a spectrum + */ + void add(cTheoreticalSpectrum& theoreticalspectrum); + + + /** + \brief Get the number of spectra. + \retval int number of spectra + */ + int size(); + + + /** + \brief Overloaded operator []. + \param position position of a spectrum in the vector + \retval reference to the spectrum + */ + cTheoreticalSpectrum& operator[](int position); + + + /** + \brief Parallel comparison of theoretical spectra with an experimental spectrum. + \param candidates reference to a set of peptide sequence candidates + \param terminatecomputation reference to a variable determining that the computation must be stopped + \retval int 0 when successfully finished; -1 when an error occurred + */ + int parallelCompareAndStore(cCandidateSet& candidates, bool& terminatecomputation); + + + /** + \brief Print peptide spectrum matches into a stream. + \param os reference to the main thread of the application (output stream) + \param limit a number of peptide spectrum matches printed + \param peptidetype the type of peptide corresponding to the experimental spectrum + */ + void printPeptideSpectrumMatches(ofstream& os, int limit, peptideType peptidetype); + + /** + \brief Add a new spectrum to the list when the number cParameters::hitsreported has not been exceeded or when it has been exceeded but + the score of the newly added spectrum is better than the worst score of a peptide in the list (thread-safe). + \param theoreticalspectrum reference to a newly added spectrum + \param theoreticalpeaksrealsize the number of peaks in the newly added spectrum (required because of a performance improvement) + */ + void addButDoNotFitSize(cTheoreticalSpectrum& theoreticalspectrum, int theoreticalpeaksrealsize); + + + /** + \brief Sort the list according to a score defined by cParameters::scoretype and crop the list according cParameters::hitsreported. + */ + void sortAndFitSize(); + +}; + + +#endif + diff --git a/CycloBranch/gui/cAboutWidget.cpp b/CycloBranch/gui/cAboutWidget.cpp new file mode 100644 index 0000000..c42b149 --- /dev/null +++ b/CycloBranch/gui/cAboutWidget.cpp @@ -0,0 +1,54 @@ +#include "gui/cAboutWidget.h" +#include "gui/cMainThread.h" + +#include +#include +#include + + + +cAboutWidget::cAboutWidget(QWidget* parent) { + this->parent = parent; + + setWindowTitle("About..."); + + layout = new QVBoxLayout(); + + message = new QTextBrowser(); + message->setReadOnly(true); + message->setAcceptRichText(true); + message->setOpenExternalLinks(true); + message->setHtml(appname + " " + appversion + "

Developers:

Jiri Novak
Laboratory of Molecular Structure Characterization
Institute of Microbiology
Academy of Sciences of the Czech Republic
Videnska 1083
142 20 Prague
Czech Republic
jiri.novak@biomed.cas.cz
http://ms.biomed.cas.cz/staff-novak_jiri.php
https://cas-cz.academia.edu/JiriNovak

(C) 2013-2014"); + + buttonbox = new QDialogButtonBox(QDialogButtonBox::Ok); + //buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + connect(buttonbox, SIGNAL(accepted()), this, SLOT(accept())); + //connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + layout->addWidget(message); + layout->addWidget(buttonbox); + + setLayout(layout); + + resize(600, 400); +} + + +cAboutWidget::~cAboutWidget() { + delete layout; + delete message; + delete buttonbox; +} + + +void cAboutWidget::closeEvent(QCloseEvent *event) { + accept(); +} + + +void cAboutWidget::accept() { + hide(); + //parent->setEnabled(true); +} + diff --git a/CycloBranch/gui/cAboutWidget.h b/CycloBranch/gui/cAboutWidget.h new file mode 100644 index 0000000..f787147 --- /dev/null +++ b/CycloBranch/gui/cAboutWidget.h @@ -0,0 +1,62 @@ +/** + \file cAboutWidget.h + \brief The implementation of the dialog 'Help->About'. +*/ + + +#ifndef _CABOUTWIDGET_H +#define _CABOUTWIDGET_H + +#include + + +// forward declaration +class QVBoxLayout; +class QTextBrowser; +class QDialogButtonBox; + + +/** + \brief The widget representing the dialog 'About'. +*/ +class cAboutWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + \param parent pointer to a parent widget + */ + cAboutWidget(QWidget* parent = (QWidget *)0); + + + /** + \brief The destructor. + */ + ~cAboutWidget(); + + + /** + \brief Handle the window close event. + \param event pointer to QCloseEvent + */ + void closeEvent(QCloseEvent *event); + + +private: + QWidget* parent; + QVBoxLayout* layout; + QTextBrowser* message; + QDialogButtonBox* buttonbox; + + +private slots: + + void accept(); + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cBranchedWidget.cpp b/CycloBranch/gui/cBranchedWidget.cpp new file mode 100644 index 0000000..549cd78 --- /dev/null +++ b/CycloBranch/gui/cBranchedWidget.cpp @@ -0,0 +1,283 @@ +#include "gui/cBranchedWidget.h" + +#include +#include +#include +#include + + +cBranchedWidget::cBranchedWidget() { + parameters = 0; + theoreticalspectrum = 0; +} + + +void cBranchedWidget::initialize(cParameters* parameters, cTheoreticalSpectrum* theoreticalspectrum) { + this->parameters = parameters; + this->theoreticalspectrum = theoreticalspectrum; +} + + +void cBranchedWidget::paintEvent(QPaintEvent *event) { + + if (theoreticalspectrum->getVisualCoverage().size() == 0) { + return; + } + + vector backboneacronyms; + vector branchacronyms; + theoreticalspectrum->getCandidate().getBackboneAcronyms(parameters->bricksdatabase, backboneacronyms); + theoreticalspectrum->getCandidate().getBranchAcronyms(parameters->bricksdatabase, branchacronyms); + + QPainter painter(this); + const int topmargin = 20; + const int leftmargin = 20; + const int bottommargin = 80; + const int rightmargin = 20; + + int branchsize = (int)branchacronyms.size(); + int backbonesize = (int)theoreticalspectrum->getAcronyms().size() - branchsize; + + vector tpermutations; + theoreticalspectrum->getCandidate().getPermutationsOfBranches(tpermutations); + + const int horizontalstep = (width() - leftmargin - rightmargin)/std::max(backbonesize, 1); + const int verticalstep = (height() - topmargin - bottommargin)/std::max(branchsize, 1); + + QFont myFont("Courier", 9); + painter.setFont(myFont); + + for (int i = 0; i < backbonesize; i++) { + painter.setPen(QPen(Qt::blue, 2, Qt::SolidLine)); + painter.drawText(leftmargin + horizontalstep/4 + horizontalstep*i, topmargin + verticalstep*branchsize, horizontalstep/2, 20, Qt::AlignCenter, backboneacronyms[i].c_str()); + + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawRect(leftmargin + horizontalstep/4 + horizontalstep*i, topmargin + verticalstep*branchsize, horizontalstep/2, 20); + + if (i < backbonesize - 1) { + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawLine(leftmargin + horizontalstep/4 + horizontalstep*i + horizontalstep/2, topmargin + verticalstep*branchsize + 11, leftmargin + horizontalstep/4 + horizontalstep*(i + 1), topmargin + verticalstep*branchsize + 11); + painter.setPen(QPen(Qt::black, 2, Qt::DashLine)); + painter.drawLine(leftmargin + horizontalstep*(i + 1), topmargin + verticalstep*branchsize - 10, leftmargin + horizontalstep*(i + 1), topmargin + verticalstep*branchsize + 30); + painter.drawLine(leftmargin + horizontalstep/4 + horizontalstep/8 + horizontalstep*i + horizontalstep/2, topmargin + verticalstep*branchsize - 10, leftmargin + horizontalstep*(i + 1), topmargin + verticalstep*branchsize - 10); + painter.drawLine(leftmargin + horizontalstep*(i + 1), topmargin + verticalstep*branchsize + 30, leftmargin + horizontalstep*(i + 1) + horizontalstep/8, topmargin + verticalstep*branchsize + 30); + } + } + + for (int i = 0; i < branchsize; i++) { + painter.setPen(QPen(Qt::blue, 2, Qt::SolidLine)); + painter.drawText(leftmargin + horizontalstep/4 + horizontalstep*tpermutations[0].middlebranchstart, topmargin + verticalstep*i, horizontalstep/2, 20, Qt::AlignCenter, branchacronyms[branchsize - i - 1].c_str()); + + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawRect(leftmargin + horizontalstep/4 + horizontalstep*tpermutations[0].middlebranchstart, topmargin + verticalstep*i, horizontalstep/2, 20); + + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawLine(leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart, topmargin + verticalstep*i + 20, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart, topmargin + verticalstep*i + verticalstep); + painter.setPen(QPen(Qt::black, 2, Qt::DashLine)); + painter.drawLine(leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart - 20, topmargin + verticalstep*i + (verticalstep + 10)/2, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart + 20, topmargin + verticalstep*i + (verticalstep + 10)/2); + painter.drawLine(leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart - 20, topmargin + verticalstep*i + (verticalstep + 10)/2, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart - 20, topmargin + verticalstep*i + (verticalstep + 10)/2 + verticalstep/8); + painter.drawLine(leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart + 20, topmargin + verticalstep*i + (verticalstep + 10)/2 - verticalstep/8, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart + 20, topmargin + verticalstep*i + (verticalstep + 10)/2); + } + + unordered_set labels; + labels.clear(); + + int position; + string name; + int len = (int)theoreticalspectrum->getVisualCoverage()[0].series.size(); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < (int)parameters->fragmentionsfortheoreticalspectra.size(); j++) { + + position = 0; + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].nterminal) { + for (int k = 0; k < len; k++) { + switch (i) + { + case 0: + if ((k < tpermutations[i].middlebranchstart) || (k >= tpermutations[i].middlebranchend)) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/4 + horizontalstep/8 + horizontalstep*position + horizontalstep/2, topmargin + verticalstep*branchsize - 35, name, false); + } + position++; + } + break; + case 1: + if (k < tpermutations[i].middlebranchstart) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart + 25, topmargin + verticalstep*k + verticalstep/2 - verticalstep/8, name, false); + } + } + if (k >= tpermutations[i].middlebranchend) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/4 + horizontalstep/8 + horizontalstep*(position + tpermutations[i].middlebranchend - tpermutations[i].middlebranchstart) + horizontalstep/2, topmargin + verticalstep*branchsize - 35, name, false); + } + position++; + } + break; + case 2: + if ((k < tpermutations[i].middlebranchstart) || (k >= tpermutations[i].middlebranchend)) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep*(backbonesize - position - 2 + 1), topmargin + verticalstep*branchsize + 35, name, false); + } + position++; + } + break; + case 3: + if (k < tpermutations[i].middlebranchstart) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/4 + horizontalstep/8 + horizontalstep*position + horizontalstep/2, topmargin + verticalstep*branchsize - 35, name, false); + } + position++; + } + if (k >= tpermutations[i].middlebranchend) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart - 25, topmargin + verticalstep*(branchsize - k - 2 + backbonesize) + verticalstep/2, name, true); + } + } + break; + case 4: + if (k < tpermutations[i].middlebranchstart) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart + 25, topmargin + verticalstep*k + verticalstep/2 - verticalstep/8, name, false); + } + } + if (k >= tpermutations[i].middlebranchend) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep*(backbonesize - tpermutations[i].middlebranchend + tpermutations[i].middlebranchstart - position - 2 + 1), topmargin + verticalstep*branchsize + 35, name, false); + } + position++; + } + break; + case 5: + if (k < tpermutations[i].middlebranchstart) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep*(backbonesize - position - 2 + 1), topmargin + verticalstep*branchsize + 35, name, false); + } + position++; + } + if (k >= tpermutations[i].middlebranchend) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart - 25, topmargin + verticalstep*(branchsize - k - 2 + backbonesize) + verticalstep/2, name, true); + } + } + break; + default: + break; + } + } + } + + position = 0; + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].cterminal) { + for (int k = len - 1; k >= 0; k--) { + switch (i) + { + case 0: + if ((k < tpermutations[i].middlebranchstart) || (k >= tpermutations[i].middlebranchend)) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[len - k - 1] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(len - k) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep*(backbonesize - position - 1), topmargin + verticalstep*branchsize + 35, name, false); + } + position++; + } + break; + case 1: + if (k < tpermutations[i].middlebranchstart) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[len - k - 1] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(len - k) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart - 25, topmargin + verticalstep*k + verticalstep/2, name, true); + } + } + if (k >= tpermutations[i].middlebranchend) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[len - k - 1] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(len - k) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep*(backbonesize - position - 1), topmargin + verticalstep*branchsize + 35, name, false); + } + position++; + } + break; + case 2: + if ((k < tpermutations[i].middlebranchstart) || (k >= tpermutations[i].middlebranchend)) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[len - k - 1] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(len - k) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep*position + horizontalstep/2 + horizontalstep/4 + horizontalstep/8, topmargin + verticalstep*branchsize - 35, name, false); + } + position++; + } + break; + case 3: + if (k < tpermutations[i].middlebranchstart) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[len - k - 1] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(len - k) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep*(backbonesize - position - tpermutations[i].middlebranchend + tpermutations[i].middlebranchstart - 1), topmargin + verticalstep*branchsize + 35, name, false); + } + position++; + } + if (k >= tpermutations[i].middlebranchend) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[len - k - 1] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(len - k) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart + 25, topmargin + verticalstep*(branchsize - k - 2 + backbonesize) + verticalstep/2 - verticalstep/8, name, false); + } + } + break; + case 4: + if (k < tpermutations[i].middlebranchstart) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[len - k - 1] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(len - k) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart - 25, topmargin + verticalstep*k + verticalstep/2, name, true); + } + } + if (k >= tpermutations[i].middlebranchend) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[len - k - 1] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(len - k) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep*position + horizontalstep/2 + horizontalstep/4 + horizontalstep/8, topmargin + verticalstep*branchsize - 35, name, false); + } + position++; + } + break; + case 5: + if (k < tpermutations[i].middlebranchstart) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[len - k - 1] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(len - k) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep*(position + tpermutations[i].middlebranchend - tpermutations[i].middlebranchstart) + horizontalstep/2 + horizontalstep/4 + horizontalstep/8, topmargin + verticalstep*branchsize - 35, name, false); + } + position++; + } + if (k >= tpermutations[i].middlebranchend) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[len - k - 1] > 0) { + name = to_string(i + 1) + "_" + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(len - k) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/2 + horizontalstep*tpermutations[0].middlebranchstart + 25, topmargin + verticalstep*(branchsize - k - 2 + backbonesize) + verticalstep/2 - verticalstep/8, name, false); + } + } + break; + default: + break; + } + } + } + + } + } + + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + for (auto it = labels.begin(); it != labels.end(); ++it) { + if (it->alignright) { + painter.drawText(it->x - (int)it->label.size()*7, it->y, (int)it->label.size()*7, 20, Qt::AlignLeft, it->label.c_str()); + } + else { + painter.drawText(it->x, it->y, width(), 20, Qt::AlignLeft, it->label.c_str()); + } + } + +} + diff --git a/CycloBranch/gui/cBranchedWidget.h b/CycloBranch/gui/cBranchedWidget.h new file mode 100644 index 0000000..32b6d14 --- /dev/null +++ b/CycloBranch/gui/cBranchedWidget.h @@ -0,0 +1,60 @@ +/** + \file cBranchedWidget.h + \brief Visualization of a branched peptide. +*/ + + +#ifndef _CBRANCHEDWIDGET_H +#define _CBRANCHEDWIDGET_H + +#include + +#include "core/cTheoreticalSpectrum.h" +#include "gui/cLinearWidget.h" + +// forward declaration +class QPaintEvent; + + +/** + \brief Visualization of a branched peptide. +*/ +class cBranchedWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + */ + cBranchedWidget(); + + + /** + \brief Initialize the widget. + \param parameters a pointer to parameters + \param theoreticalspectrum a pointer to a theoretical spectrum + */ + void initialize(cParameters* parameters, cTheoreticalSpectrum* theoreticalspectrum); + + +protected: + + + /** + \brief Handle the paint event. + \param event pointer to QPaintEvent + */ + void paintEvent(QPaintEvent *event); + + +private: + + cParameters* parameters; + cTheoreticalSpectrum* theoreticalspectrum; + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cCyclicWidget.cpp b/CycloBranch/gui/cCyclicWidget.cpp new file mode 100644 index 0000000..73c3276 --- /dev/null +++ b/CycloBranch/gui/cCyclicWidget.cpp @@ -0,0 +1,323 @@ +#include "gui/cCyclicWidget.h" + +#include +#include +#include +#include + + +cCyclicWidget::cCyclicWidget() { + parameters = 0; + theoreticalspectrum = 0; + visiblerotationid = -1; +} + + +void cCyclicWidget::initialize(cParameters* parameters, cTheoreticalSpectrum* theoreticalspectrum) { + this->parameters = parameters; + this->theoreticalspectrum = theoreticalspectrum; +} + + +/* +void cCyclicWidget::paintEvent(QPaintEvent *event) { + string s; + + // count number of lines to draw + bool skip; + int linenumber = 0; + for (int i = 0; i < (int)theoreticalspectrum->getVisualCoverage().size(); i++) { + + skip = true; + for (int j = 0; j < (int)theoreticalspectrum->getVisualCoverage()[i].series.size(); j++) { + if (theoreticalspectrum->getVisualCoverage()[i].series[j] > 0) { + skip = false; + break; + } + } + + if (skip) { + continue; + } + + linenumber++; + } + + if ((theoreticalspectrum->getAcronyms().size() == 0) || (linenumber == 0)) { + return; + } + + QPainter painter(this); + const int topmargin = 80; + const int leftmargin = 60; + const int bottommargin = 50; + const int rightmargin = 50; + const int maskmargin = 30; + const int verticalstep = (height() - topmargin - bottommargin)/linenumber; + const int horizontalstep = (width() - leftmargin - rightmargin)/(int)theoreticalspectrum->getAcronyms().size(); + + QFont myFont("Courier", 9); + + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + painter.setFont(myFont); + + // draw candidate + int r = (int)theoreticalspectrum->getAcronyms().size(); + int hint = (int)theoreticalspectrum->getVisualCoverage().size()/(2*r); + for (int i = 0; i < r; i++) { + painter.drawLine(leftmargin + horizontalstep*i, topmargin - 30, leftmargin + horizontalstep*i, topmargin - 10); + painter.drawText(leftmargin + horizontalstep*i, topmargin - 30, horizontalstep, 20, Qt::AlignCenter, theoreticalspectrum->getAcronyms()[i].c_str()); + + s = theoreticalspectrum->getVisualCoverage()[i*hint].name.substr(0, theoreticalspectrum->getVisualCoverage()[i*hint].name.rfind('_')); + painter.drawText(leftmargin + horizontalstep*i - horizontalstep/2, topmargin - 80, horizontalstep, 30, Qt::AlignCenter, s.c_str()); + if (i == 0) { + painter.drawText(leftmargin + horizontalstep*r - horizontalstep/2, topmargin - 80, horizontalstep, 30, Qt::AlignCenter, s.c_str()); + } + + if (i == 0) { + s = theoreticalspectrum->getVisualCoverage()[r*hint].name.substr(0, theoreticalspectrum->getVisualCoverage()[r*hint].name.rfind('_')); + } + else { + s = theoreticalspectrum->getVisualCoverage()[(2*r - i)*hint].name.substr(0, theoreticalspectrum->getVisualCoverage()[(2*r - i)*hint].name.rfind('_')); + } + painter.drawText(leftmargin + horizontalstep*i - horizontalstep/2, topmargin - 60, horizontalstep, 30, Qt::AlignCenter, s.c_str()); + if (i == 0) { + painter.drawText(leftmargin + horizontalstep*r - horizontalstep/2, topmargin - 60, horizontalstep, 30, Qt::AlignCenter, s.c_str()); + } + } + painter.drawLine(leftmargin + horizontalstep*r, topmargin - 30, leftmargin + horizontalstep*r, topmargin - 10); + + painter.drawText(0, topmargin - 80, 20, 30, Qt::AlignCenter, ">>>"); + painter.drawText(0, topmargin - 60, 20, 30, Qt::AlignCenter, "<<<"); + + // draw lines + linenumber = 0; + for (int i = 0; i < (int)theoreticalspectrum->getVisualCoverage().size(); i++) { + + skip = true; + for (int j = 0; j < (int)theoreticalspectrum->getVisualCoverage()[i].series.size(); j++) { + if (theoreticalspectrum->getVisualCoverage()[i].series[j] > 0) { + skip = false; + break; + } + } + + if (skip) { + continue; + } + + painter.setPen(QPen(Qt::gray, 2, Qt::SolidLine)); + for (int j = 0; j < (int)theoreticalspectrum->getVisualCoverage()[i].series.size(); j++) { + if (theoreticalspectrum->getVisualCoverage()[i].series[j] > 0) { + painter.setBrush(QBrush(Qt::blue, Qt::SolidPattern)); + } + else { + painter.setBrush(QBrush(Qt::red, Qt::NoBrush)); + } + painter.drawRect(leftmargin + horizontalstep*j, topmargin + verticalstep*linenumber, horizontalstep, verticalstep); + } + + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + painter.setBrush(QBrush(Qt::red, Qt::NoBrush)); + + painter.drawText(0, topmargin + verticalstep*linenumber + verticalstep/2 - 9, 80, 20, Qt::AlignLeft, theoreticalspectrum->getVisualCoverage()[i].name.c_str()); + + linenumber++; + + } + +} +*/ + + +void cCyclicWidget::paintEvent(QPaintEvent *event) { + + if (theoreticalspectrum->getVisualCoverage().size() == 0) { + return; + } + + QPainter painter(this); + const int topmargin = 20;//max(20,(height() - 80)/2); + const int leftmargin = 20; + const int bottommargin = 80; + const int rightmargin = 20; + + int size = (int)theoreticalspectrum->getAcronyms().size(); + const double pi = 3.141592653589793; + double angle = 2*pi/(double)size; + int centerx = width()/2; + int centery = height()/2; + int radius = min(width() - leftmargin - rightmargin, height() - topmargin - bottommargin)/2; + double cumulativeangle; + + const int horizontalstep = (width() - leftmargin - rightmargin)/std::max(size, 1); + + QFont myFont("Courier", 9); + painter.setFont(myFont); + + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawEllipse(QPointF(centerx,centery), radius, radius); + + int xsize = horizontalstep*2/3; + for (int i = 0; i < size; i++) { + cumulativeangle = angle*(double)i; + if (cumulativeangle < pi/2) { + painter.setBrush(QBrush(palette().color(QPalette::Background), Qt::SolidPattern)); + painter.drawRect(centerx + sin(cumulativeangle)*radius - xsize/2, centery - sin(pi/2 - cumulativeangle)*radius - 10, xsize, 20); + painter.setBrush(QBrush(palette().color(QPalette::Background), Qt::NoBrush)); + painter.setPen(QPen(Qt::blue, 2, Qt::SolidLine)); + painter.drawText(centerx + sin(cumulativeangle)*radius - xsize/2, centery - sin(pi/2 - cumulativeangle)*radius - 10, xsize, 20, Qt::AlignCenter, theoreticalspectrum->getAcronyms()[i].c_str()); + painter.drawText(centerx + sin(cumulativeangle)*radius - xsize/2, centery - sin(pi/2 - cumulativeangle)*radius - 30, xsize, 20, Qt::AlignLeft, to_string(i + 1).c_str()); + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawRect(centerx + sin(cumulativeangle)*radius - xsize/2, centery - sin(pi/2 - cumulativeangle)*radius - 10, xsize, 20); + } + else if ((cumulativeangle >= pi/2) && (cumulativeangle <= pi)) { + painter.setBrush(QBrush(palette().color(QPalette::Background), Qt::SolidPattern)); + painter.drawRect(centerx + sin(pi - cumulativeangle)*radius - xsize/2, centery + sin(cumulativeangle - pi/2)*radius - 10, xsize, 20); + painter.setBrush(QBrush(palette().color(QPalette::Background), Qt::NoBrush)); + painter.setPen(QPen(Qt::blue, 2, Qt::SolidLine)); + painter.drawText(centerx + sin(pi - cumulativeangle)*radius - xsize/2, centery + sin(cumulativeangle - pi/2)*radius - 10, xsize, 20, Qt::AlignCenter, theoreticalspectrum->getAcronyms()[i].c_str()); + painter.drawText(centerx + sin(pi - cumulativeangle)*radius - xsize/2, centery + sin(cumulativeangle - pi/2)*radius - 30, xsize, 20, Qt::AlignLeft, to_string(i + 1).c_str()); + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawRect(centerx + sin(pi - cumulativeangle)*radius - xsize/2, centery + sin(cumulativeangle - pi/2)*radius - 10, xsize, 20); + } + else if ((cumulativeangle >= pi) && (cumulativeangle <= 3*pi/2)) { + painter.setBrush(QBrush(palette().color(QPalette::Background), Qt::SolidPattern)); + painter.drawRect(centerx - sin(cumulativeangle - pi)*radius - xsize/2, centery + sin(3*pi/2 - cumulativeangle)*radius - 10, xsize, 20); + painter.setBrush(QBrush(palette().color(QPalette::Background), Qt::NoBrush)); + painter.setPen(QPen(Qt::blue, 2, Qt::SolidLine)); + painter.drawText(centerx - sin(cumulativeangle - pi)*radius - xsize/2, centery + sin(3*pi/2 - cumulativeangle)*radius - 10, xsize, 20, Qt::AlignCenter, theoreticalspectrum->getAcronyms()[i].c_str()); + painter.drawText(centerx - sin(cumulativeangle - pi)*radius - xsize/2, centery + sin(3*pi/2 - cumulativeangle)*radius - 30, xsize, 20, Qt::AlignLeft, to_string(i + 1).c_str()); + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawRect(centerx - sin(cumulativeangle - pi)*radius - xsize/2, centery + sin(3*pi/2 - cumulativeangle)*radius - 10, xsize, 20); + } + else { + painter.setBrush(QBrush(palette().color(QPalette::Background), Qt::SolidPattern)); + painter.drawRect(centerx - sin(2*pi - cumulativeangle)*radius - xsize/2, centery - sin(cumulativeangle - 3*pi/2)*radius - 10, xsize, 20); + painter.setBrush(QBrush(palette().color(QPalette::Background), Qt::NoBrush)); + painter.setPen(QPen(Qt::blue, 2, Qt::SolidLine)); + painter.drawText(centerx - sin(2*pi - cumulativeangle)*radius - xsize/2, centery - sin(cumulativeangle - 3*pi/2)*radius - 10, xsize, 20, Qt::AlignCenter, theoreticalspectrum->getAcronyms()[i].c_str()); + painter.drawText(centerx - sin(2*pi - cumulativeangle)*radius - xsize/2, centery - sin(cumulativeangle - 3*pi/2)*radius - 30, xsize, 20, Qt::AlignLeft, to_string(i + 1).c_str()); + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawRect(centerx - sin(2*pi - cumulativeangle)*radius - xsize/2, centery - sin(cumulativeangle - 3*pi/2)*radius - 10, xsize, 20); + } + } + + painter.setPen(QPen(Qt::black, 2, Qt::DashLine)); + int linesize = 20; + int cornerlinesize = horizontalstep/8; + for (int i = 0; i < size; i++) { + cumulativeangle = angle*(double)i + angle/(double)2; + if (cumulativeangle < pi/2) { + QPoint p1(centerx + sin(cumulativeangle)*(radius - linesize), centery - sin(pi/2 - cumulativeangle)*(radius - linesize)); + QPoint p2(centerx + sin(cumulativeangle)*(radius + linesize), centery - sin(pi/2 - cumulativeangle)*(radius + linesize)); + QPoint p3(centerx + sin(cumulativeangle)*(radius + linesize) - sin(pi/2 - cumulativeangle)*cornerlinesize, centery - sin(pi/2 - cumulativeangle)*(radius + linesize) - sin(cumulativeangle)*cornerlinesize); + QPoint p4(centerx + sin(cumulativeangle)*(radius - linesize) + sin(pi/2 - cumulativeangle)*cornerlinesize, centery - sin(pi/2 - cumulativeangle)*(radius - linesize) + sin(cumulativeangle)*cornerlinesize); + painter.drawLine(p1, p2); + painter.drawLine(p3, p2); + painter.drawLine(p1, p4); + } + else if ((cumulativeangle >= pi/2) && (cumulativeangle <= pi)) { + QPoint p1(centerx + sin(pi - cumulativeangle)*(radius - linesize), centery + sin(cumulativeangle - pi/2)*(radius - linesize)); + QPoint p2(centerx + sin(pi - cumulativeangle)*(radius + linesize), centery + sin(cumulativeangle - pi/2)*(radius + linesize)); + QPoint p3(centerx + sin(pi - cumulativeangle)*(radius + linesize) + sin(cumulativeangle - pi/2)*cornerlinesize, centery + sin(cumulativeangle - pi/2)*(radius + linesize) - sin(pi - cumulativeangle)*cornerlinesize); + QPoint p4(centerx + sin(pi - cumulativeangle)*(radius - linesize) - sin(cumulativeangle - pi/2)*cornerlinesize, centery + sin(cumulativeangle - pi/2)*(radius - linesize) + sin(pi - cumulativeangle)*cornerlinesize); + painter.drawLine(p1, p2); + painter.drawLine(p3, p2); + painter.drawLine(p1, p4); + } + else if ((cumulativeangle >= pi) && (cumulativeangle <= 3*pi/2)) { + QPoint p1(centerx - sin(cumulativeangle - pi)*(radius - linesize), centery + sin(3*pi/2 - cumulativeangle)*(radius - linesize)); + QPoint p2(centerx - sin(cumulativeangle - pi)*(radius + linesize), centery + sin(3*pi/2 - cumulativeangle)*(radius + linesize)); + QPoint p3(centerx - sin(cumulativeangle - pi)*(radius + linesize) + sin(3*pi/2 - cumulativeangle)*cornerlinesize, centery + sin(3*pi/2 - cumulativeangle)*(radius + linesize) + sin(cumulativeangle - pi)*cornerlinesize); + QPoint p4(centerx - sin(cumulativeangle - pi)*(radius - linesize) - sin(3*pi/2 - cumulativeangle)*cornerlinesize, centery + sin(3*pi/2 - cumulativeangle)*(radius - linesize) - sin(cumulativeangle - pi)*cornerlinesize); + painter.drawLine(p1, p2); + painter.drawLine(p3, p2); + painter.drawLine(p1, p4); + } + else { + QPoint p1(centerx - sin(2*pi - cumulativeangle)*(radius - linesize), centery - sin(cumulativeangle - 3*pi/2)*(radius - linesize)); + QPoint p2(centerx - sin(2*pi - cumulativeangle)*(radius + linesize), centery - sin(cumulativeangle - 3*pi/2)*(radius + linesize)); + QPoint p3(centerx - sin(2*pi - cumulativeangle)*(radius + linesize) - sin(cumulativeangle - 3*pi/2)*cornerlinesize, centery - sin(cumulativeangle - 3*pi/2)*(radius + linesize) + sin(2*pi - cumulativeangle)*cornerlinesize); + QPoint p4(centerx - sin(2*pi - cumulativeangle)*(radius - linesize) + sin(cumulativeangle - 3*pi/2)*cornerlinesize, centery - sin(cumulativeangle - 3*pi/2)*(radius - linesize) - sin(2*pi - cumulativeangle)*cornerlinesize); + painter.drawLine(p1, p2); + painter.drawLine(p3, p2); + painter.drawLine(p1, p4); + } + } + + unordered_set labels; + labels.clear(); + + string name; + int shiftedposition = 0; + int len = (int)theoreticalspectrum->getVisualCoverage()[0].series.size(); + for (int i = 0; i < 2*size; i++) { + if ((visiblerotationid == -1) || (visiblerotationid == i)) { + for (int j = 0; j < (int)parameters->fragmentionsfortheoreticalspectra.size(); j++) { + for (int k = 0; k < len; k++) { + if (theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].series[k] > 0) { + name = theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].name.substr(0, theoreticalspectrum->getVisualCoverage()[i*parameters->fragmentionsfortheoreticalspectra.size() + j].name.find('_') + 1); + name += parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name[0] + to_string(k + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[j]].name.substr(1); + if (i < size) { + cumulativeangle = angle*(double)((i + k) % size) + angle/(double)2; + if (cumulativeangle < pi/2) { + QPoint p3(centerx + sin(cumulativeangle)*(radius + linesize) - sin(pi/2 - cumulativeangle)*cornerlinesize, centery - sin(pi/2 - cumulativeangle)*(radius + linesize) - sin(cumulativeangle)*cornerlinesize); + insertLabel(labels, p3.x() + 10, p3.y() - 10, name, false); + } + else if ((cumulativeangle >= pi/2) && (cumulativeangle <= pi)) { + QPoint p3(centerx + sin(pi - cumulativeangle)*(radius + linesize) + sin(cumulativeangle - pi/2)*cornerlinesize, centery + sin(cumulativeangle - pi/2)*(radius + linesize) - sin(pi - cumulativeangle)*cornerlinesize); + insertLabel(labels, p3.x() + 10, p3.y() - 10, name, false); + } + else if ((cumulativeangle >= pi) && (cumulativeangle <= 3*pi/2)) { + QPoint p3(centerx - sin(cumulativeangle - pi)*(radius + linesize) + sin(3*pi/2 - cumulativeangle)*cornerlinesize, centery + sin(3*pi/2 - cumulativeangle)*(radius + linesize) + sin(cumulativeangle - pi)*cornerlinesize); + insertLabel(labels, p3.x() - 10, p3.y() - 10, name, true); + } + else { + QPoint p3(centerx - sin(2*pi - cumulativeangle)*(radius + linesize) - sin(cumulativeangle - 3*pi/2)*cornerlinesize, centery - sin(cumulativeangle - 3*pi/2)*(radius + linesize) + sin(2*pi - cumulativeangle)*cornerlinesize); + insertLabel(labels, p3.x() - 10, p3.y() - 10, name, true); + } + } + else { + cumulativeangle = angle*(double)((2*size - i - 1 + size - k - 1) % size) + angle/(double)2; + if (cumulativeangle < pi/2) { + QPoint p4(centerx + sin(cumulativeangle)*(radius - linesize) + sin(pi/2 - cumulativeangle)*cornerlinesize, centery - sin(pi/2 - cumulativeangle)*(radius - linesize) + sin(cumulativeangle)*cornerlinesize); + insertLabel(labels, p4.x() - 5, p4.y() - 5, name, true); + } + else if ((cumulativeangle >= pi/2) && (cumulativeangle <= pi)) { + QPoint p4(centerx + sin(pi - cumulativeangle)*(radius - linesize) - sin(cumulativeangle - pi/2)*cornerlinesize, centery + sin(cumulativeangle - pi/2)*(radius - linesize) + sin(pi - cumulativeangle)*cornerlinesize); + insertLabel(labels, p4.x() - 5, p4.y() - 5, name, true); + } + else if ((cumulativeangle >= pi) && (cumulativeangle <= 3*pi/2)) { + QPoint p4(centerx - sin(cumulativeangle - pi)*(radius - linesize) - sin(3*pi/2 - cumulativeangle)*cornerlinesize, centery + sin(3*pi/2 - cumulativeangle)*(radius - linesize) - sin(cumulativeangle - pi)*cornerlinesize); + insertLabel(labels, p4.x() + 10, p4.y() - 10, name, false); + } + else { + QPoint p4(centerx - sin(2*pi - cumulativeangle)*(radius - linesize) + sin(cumulativeangle - 3*pi/2)*cornerlinesize, centery - sin(cumulativeangle - 3*pi/2)*(radius - linesize) - sin(2*pi - cumulativeangle)*cornerlinesize); + insertLabel(labels, p4.x() + 10, p4.y() - 10, name, false); + } + } + } + } + } + } + } + + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + for (auto it = labels.begin(); it != labels.end(); ++it) { + if (it->alignright) { + painter.drawText(it->x - (int)it->label.size()*7, it->y, (int)it->label.size()*7, 20, Qt::AlignLeft, it->label.c_str()); + } + else { + painter.drawText(it->x, it->y, width(), 20, Qt::AlignLeft, it->label.c_str()); + } + } + +} + + +void cCyclicWidget::rotationChanged(int index) { + visiblerotationid = index - 1; + repaint(); +} + diff --git a/CycloBranch/gui/cCyclicWidget.h b/CycloBranch/gui/cCyclicWidget.h new file mode 100644 index 0000000..dff0e87 --- /dev/null +++ b/CycloBranch/gui/cCyclicWidget.h @@ -0,0 +1,69 @@ +/** + \file cCyclicWidget.h + \brief Visualization of a cyclic peptide. +*/ + + +#ifndef _CCYCLICWIDGET_H +#define _CCYCLICWIDGET_H + +#include +#include +#include + +#include "core/cTheoreticalSpectrum.h" +#include "gui/cLinearWidget.h" + + +// forward declaration +class QPaintEvent; + + +/** + \brief Visualization of a cyclic peptide. +*/ +class cCyclicWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + */ + cCyclicWidget(); + + + /** + \brief Initialize the widget. + \param parameters a pointer to parameters + \param theoreticalspectrum a pointer to a theoretical spectrum + */ + void initialize(cParameters* parameters, cTheoreticalSpectrum* theoreticalspectrum); + + +protected: + + + /** + \brief Handle the paint event. + \param event pointer to QPaintEvent + */ + void paintEvent(QPaintEvent *event); + + +private: + + cParameters* parameters; + cTheoreticalSpectrum* theoreticalspectrum; + int visiblerotationid; + + +private slots: + + void rotationChanged(int index); + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cFragmentIonsListWidget.cpp b/CycloBranch/gui/cFragmentIonsListWidget.cpp new file mode 100644 index 0000000..8e002e8 --- /dev/null +++ b/CycloBranch/gui/cFragmentIonsListWidget.cpp @@ -0,0 +1,76 @@ +#include "gui/cFragmentIonsListWidget.h" + +#include +#include +#include + + +cFragmentIonsListWidget::cFragmentIonsListWidget(QObject* parent) { + this->parent = parent; + + vbox = new QVBoxLayout(); + hbox = new QHBoxLayout(); + + list = new QListWidget(); + list->setMinimumHeight(210); + list->setMaximumHeight(210); + list->setSelectionMode(QAbstractItemView::MultiSelection); + + selectall = new QPushButton("Select All"); + selectall->setToolTip("Select all fragment ion types in the list."); + clearall = new QPushButton("Clear All"); + clearall->setToolTip("Unselect all fragment ion types in the list."); + reset = new QPushButton("Reset"); + reset->setToolTip("Reset to a default selection of fragment ions considering selected \"Peptide Type\"."); + + hbox->addWidget(selectall); + hbox->addWidget(clearall); + hbox->addWidget(reset); + hbox->addStretch(1); + + vbox->setMargin(0); + vbox->addWidget(list); + vbox->addLayout(hbox); + + connect(selectall, SIGNAL(released()), this, SLOT(selectAllItems())); + connect(clearall, SIGNAL(released()), this, SLOT(clearAllItems())); + connect(reset, SIGNAL(released()), this, SLOT(sendResetReleased())); + + setLayout(vbox); +} + + +cFragmentIonsListWidget::~cFragmentIonsListWidget() { + delete list; + delete selectall; + delete clearall; + delete reset; + + delete hbox; + delete vbox; +} + + +QListWidget* cFragmentIonsListWidget::getList() { + return list; +} + + +void cFragmentIonsListWidget::selectAllItems() { + for (int i = 0; i < list->count(); i++) { + list->item(i)->setSelected(true); + } +} + + +void cFragmentIonsListWidget::clearAllItems() { + for (int i = 0; i < list->count(); i++) { + list->item(i)->setSelected(false); + } +} + + +void cFragmentIonsListWidget::sendResetReleased() { + emit resetReleased(); +} + diff --git a/CycloBranch/gui/cFragmentIonsListWidget.h b/CycloBranch/gui/cFragmentIonsListWidget.h new file mode 100644 index 0000000..d78ad06 --- /dev/null +++ b/CycloBranch/gui/cFragmentIonsListWidget.h @@ -0,0 +1,81 @@ +/** + \file cFragmentIonsListWidget.h + \brief The implementation of a widget where types of fragment ions generated in theoretical spectra are selected. +*/ + + +#ifndef _CFRAGMENTIONSLISTWIDGET_H +#define _CFRAGMENTIONSLISTWIDGET_H + +#include +#include +#include +#include + + +// forward declaration +class QPushButton; +class QHBoxLayout; +class QVBoxLayout; + + +/** + \brief The widget for selection of fragment ion types. +*/ +class cFragmentIonsListWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + \param parent pointer to a parent widget + */ + cFragmentIonsListWidget(QObject* parent); + + + /** + \brief The destructor. + */ + ~cFragmentIonsListWidget(); + + + /** + \brief Access to QListWidget. + \retval QListWidget pointer to QListWidget + */ + QListWidget* getList(); + + +private: + QObject* parent; + + QListWidget* list; + QPushButton* selectall; + QPushButton* clearall; + QPushButton* reset; + + QHBoxLayout* hbox; + QVBoxLayout* vbox; + + +private slots: + + void selectAllItems(); + + void clearAllItems(); + + void sendResetReleased(); + +signals: + + /** + \brief Reset button has been released. + */ + void resetReleased(); + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cGraphWidget.cpp b/CycloBranch/gui/cGraphWidget.cpp new file mode 100644 index 0000000..0cc512c --- /dev/null +++ b/CycloBranch/gui/cGraphWidget.cpp @@ -0,0 +1,69 @@ +#include "gui/cGraphWidget.h" + +#include +#include + + +cGraphWidget::cGraphWidget() { + htmlstring = ""; + + setWindowTitle("Graph"); + + layout = new QVBoxLayout(); + + textbrowser = new QTextBrowser(); + textbrowser->setReadOnly(true); + textbrowser->setFont(QFont("Courier", 9)); + textbrowser->setLineWrapMode(QTextEdit::NoWrap); + textbrowser->setAcceptRichText(true); + textbrowser->setOpenExternalLinks(true); + + layout->addWidget(textbrowser); + + setLayout(layout); + + resize(1280, 700); +} + + +cGraphWidget::~cGraphWidget() { + delete textbrowser; + + delete layout; +} + + +void cGraphWidget::setHTML(string s) { + textbrowser->setHtml(s.c_str()); + htmlstring = s; +} + + +string cGraphWidget::getHTML() { + return htmlstring; +} + + +void cGraphWidget::closeEvent(QCloseEvent *event) { + hide(); +} + + +void cGraphWidget::store(ofstream& os) { + int size; + + size = (int)htmlstring.size(); + os.write((char *)&size, sizeof(int)); + os.write(htmlstring.c_str(), htmlstring.size()); +} + + +void cGraphWidget::load(ifstream& is) { + int size; + + is.read((char *)&size, sizeof(int)); + htmlstring.resize(size); + is.read(&htmlstring[0], htmlstring.size()); + textbrowser->setHtml(htmlstring.c_str()); +} + diff --git a/CycloBranch/gui/cGraphWidget.h b/CycloBranch/gui/cGraphWidget.h new file mode 100644 index 0000000..338ade3 --- /dev/null +++ b/CycloBranch/gui/cGraphWidget.h @@ -0,0 +1,87 @@ +/** + \file cGraphWidget.h + \brief The implementation of the dialog 'View->Graph'. +*/ + + +#ifndef _CGRAPHWIDGET_H +#define _CGRAPHWIDGET_H + +#include +#include +#include + + +using namespace std; + + +// forward declaration +class QTextBrowser; +class QVBoxLayout; + + +/** + \brief The widget representing the dialog 'View->Graph'. +*/ +class cGraphWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + */ + cGraphWidget(); + + + /** + \brief The destructor. + */ + ~cGraphWidget(); + + + /** + \brief Set the HTML text into the widget. + \param s string with the HTML text + */ + void setHTML(string s); + + + /** + \brief Get the HTML text from the widget. + \retval string HTML string + */ + string getHTML(); + + + /** + \brief Handle the window close event. + \param event pointer to QCloseEvent + */ + void closeEvent(QCloseEvent *event); + + + /** + \brief Store the content into an output stream. + \param os an output stream + */ + void store(ofstream& os); + + + /** + \brief Load the content from an input stream. + \param is an input stream + */ + void load(ifstream& is); + + +private: + QVBoxLayout* layout; + QTextBrowser* textbrowser; + string htmlstring; + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cGraphicalSpectrumWidget.cpp b/CycloBranch/gui/cGraphicalSpectrumWidget.cpp new file mode 100644 index 0000000..a76bbb8 --- /dev/null +++ b/CycloBranch/gui/cGraphicalSpectrumWidget.cpp @@ -0,0 +1,344 @@ +#include "gui/cGraphicalSpectrumWidget.h" + +#include +#include +#include +#include +#include +#include + + +cGraphicalSpectrumWidget::cGraphicalSpectrumWidget(QWidget* parent) { + this->parent = parent; + origwidth = 0; + origheight = 0; + scale = 1; + hideunmatched = false; + hidematched = false; + factor = 0.2; + coloredrotationid = -1; + pressedx = -1; + pressedy = -1; + currentx = 0; + currenty = 0; + minmzratio = 0; + maxmzratio = 0; + + setDefaultSize(); +} + + +cGraphicalSpectrumWidget::~cGraphicalSpectrumWidget() { +} + + +void cGraphicalSpectrumWidget::setTheoreticalSpectrum(cTheoreticalSpectrum* theoreticalspectrum) { + this->theoreticalspectrum = theoreticalspectrum; + minmzratio = 0; + maxmzratio = theoreticalspectrum->getExperimentalSpectrum().getMaximumMZRatio(); + emit updateMZInterval(minmzratio, maxmzratio); +} + + +void cGraphicalSpectrumWidget::paintEvent(QPaintEvent *event) { + QPainter painter(this); + + setDefaultSize(); + + painter.setFont(QFont("Arial", 8)); + painter.translate(0, 0); + painter.scale(scale, scale); + painter.setPen(QPen(Qt::black, 1, Qt::DashLine)); + + // zooming window + if ((pressedx != -1) && (pressedy != -1)) { + painter.drawRect(pressedx, pressedy, currentx - pressedx, currenty - pressedy); + QString qstr = "m/z: "; + qstr += QString::number(getMZRatioFromXPosition((pressedx < currentx)?pressedx:currentx, origwidth)); + qstr += "-"; + qstr += QString::number(getMZRatioFromXPosition((pressedx < currentx)?currentx:pressedx, origwidth)); + painter.drawText(QPoint(pressedx, pressedy - 2), qstr); + } + + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + + int x; + double y; + + char tmpbuf[20]; + string s; + + int w = origwidth; + int h = origheight; + + // maximum intensity in the interval + double maxintensity = theoreticalspectrum->getExperimentalSpectrum().getMaximumIntensityFromMZInterval(minmzratio, maxmzratio); + + // x axis + painter.drawLine(QPoint(leftmargin, h - bottommargin), QPoint(w - rightmargin, h - bottommargin)); + + // x axis ruler + painter.drawLine(QPoint(leftmargin, h - bottommargin), QPoint(leftmargin, h - bottommargin + 10)); + painter.drawLine(QPoint(w - rightmargin, h - bottommargin), QPoint(w - rightmargin, h - bottommargin + 10)); + painter.drawText(QPoint(leftmargin - 2, h - bottommargin + 22), QString::number(minmzratio)); + painter.drawText(QPoint(w - rightmargin - 2, h - bottommargin + 22), QString::number(maxmzratio)); + + // y axis + painter.drawLine(QPoint(leftmargin, h - bottommargin), QPoint(leftmargin, topmargin)); + + // y axis ruler + painter.drawLine(QPoint(leftmargin - 10, topmargin), QPoint(leftmargin, topmargin)); + painter.drawLine(QPoint(leftmargin - 10, h - bottommargin), QPoint(leftmargin, h - bottommargin)); + drawVerticalText(&painter, QString::number(0), leftmargin - 15, h - bottommargin); + drawVerticalText(&painter, QString::number(maxintensity), leftmargin - 15, topmargin); + + // peaks + for (int i = 0; i < (int)theoreticalspectrum->getExperimentalSpectrum().size(); i++) { + + // skip peaks which are out of range + if ((theoreticalspectrum->getExperimentalSpectrum()[i].mzratio < minmzratio) || (theoreticalspectrum->getExperimentalSpectrum()[i].mzratio > maxmzratio)) { + continue; + } + + // hide unmatched peaks + if (hideunmatched && (theoreticalspectrum->getExperimentalSpectrum()[i].matched <= 0)) { + continue; + } + + // hide matched peaks + if (hidematched && (theoreticalspectrum->getExperimentalSpectrum()[i].matched > 0)) { + continue; + } + + x = getXPositionFromMZRatio(theoreticalspectrum->getExperimentalSpectrum()[i].mzratio, origwidth); + + y = theoreticalspectrum->getExperimentalSpectrum()[i].intensity/maxintensity * (h - topmargin - bottommargin); + + if ((theoreticalspectrum->getExperimentalSpectrum()[i].matched > 0) && ((coloredrotationid == -1) || ((coloredrotationid != -1) && (theoreticalspectrum->getExperimentalSpectrum()[i].hasMatchedRotation(coloredrotationid))))) { + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + } + else { + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + } + + painter.drawLine(QPoint(x, h - bottommargin - 2), QPoint(x, h - bottommargin - std::max((int)y, 3))); + + sprintf_s(tmpbuf,"%.3f\0",theoreticalspectrum->getExperimentalSpectrum()[i].mzratio); + s = tmpbuf; + if (theoreticalspectrum->getExperimentalSpectrum()[i].description.length() > 0) { + s += " (" + theoreticalspectrum->getExperimentalSpectrum()[i].description + ")"; + } + //painter.drawText(QPoint((int)x + margin, h - margin - (int)y), tmpbuf); + drawVerticalText(&painter, QString(s.c_str()), x + 3, h - bottommargin - (int)y - 5); + } + +} + + +void cGraphicalSpectrumWidget::wheelEvent(QWheelEvent *event) { + if (event->delta() > 0) { + zoomIn(); + } + else { + zoomOut(); + } + + event->accept(); +} + + +void cGraphicalSpectrumWidget::mouseMoveEvent(QMouseEvent *event) { + currentx = event->x()/scale; + currenty = event->y()/scale; + + repaint(); + + event->accept(); +} + + +void cGraphicalSpectrumWidget::mouseReleaseEvent(QMouseEvent *event) { + if (pressedx == currentx) { + pressedx = -1; + currentx = -1; + + repaint(); + } + + if ((event->button() == Qt::LeftButton) && (pressedx != -1) && (pressedy != -1)) { + + if (pressedx < leftmargin) { + pressedx = leftmargin; + } + + if (pressedx > origwidth - rightmargin) { + pressedx = origwidth - rightmargin; + } + + if (currentx < leftmargin) { + currentx = leftmargin; + } + + if (currentx > origwidth - rightmargin) { + currentx = origwidth - rightmargin; + } + + double tmpminmzratio = getMZRatioFromXPosition((pressedx < currentx)?pressedx:currentx, origwidth); + double tmpmaxmzratio = getMZRatioFromXPosition((pressedx < currentx)?currentx:pressedx, origwidth); + + minmzratio = tmpminmzratio; + maxmzratio = tmpmaxmzratio; + + emit updateMZInterval(minmzratio, maxmzratio); + + pressedx = -1; + pressedy = -1; + + repaint(); + + } + + event->accept(); +} + + +void cGraphicalSpectrumWidget::mousePressEvent(QMouseEvent *event) { + if (event->button() == Qt::LeftButton) { + pressedx = event->x()/scale; + pressedy = event->y()/scale; + + currentx = pressedx; + currenty = pressedy; + + repaint(); + } + + if (event->button() == Qt::RightButton) { + pressedx = -1; + pressedy = -1; + + repaint(); + } + + if (event->button() == Qt::MiddleButton) { + pressedx = -1; + pressedy = -1; + + resetMZInterval(); + + repaint(); + } + + event->accept(); +} + + +void cGraphicalSpectrumWidget::setDefaultSize() { + if ((origwidth != parent->width() - 2) || (origheight != parent->height() - 2)) { + origwidth = parent->width() - 2; + origheight = parent->height() - 2; + setFixedSize(origwidth*scale, origheight*scale); + } +} + + +double cGraphicalSpectrumWidget::getMZRatioFromXPosition(int x, int w) { + return (double)(x - leftmargin)/(double)(w - leftmargin - rightmargin)*(maxmzratio - minmzratio) + minmzratio; +} + + +int cGraphicalSpectrumWidget::getXPositionFromMZRatio(double mzratio, int w) { + double val = mzratio - minmzratio; + val /= maxmzratio - minmzratio; + val *= double(w - leftmargin - rightmargin); + return (int)val + leftmargin; +} + + +void cGraphicalSpectrumWidget::drawVerticalText(QPainter* painter, QString text, int x, int y) { + painter->save(); + painter->translate(x, y); + painter->rotate(-90); + painter->drawText(QPoint(0, 0), text); + painter->restore(); +} + + +void cGraphicalSpectrumWidget::hideUnmatchedPeaks(int state) { + if (state == Qt::Unchecked) { + hideunmatched = false; + } + else { + hideunmatched = true; + } + + repaint(); +} + + +void cGraphicalSpectrumWidget::hideMatchedPeaks(int state) { + if (state == Qt::Unchecked) { + hidematched = false; + } + else { + hidematched = true; + } + + repaint(); +} + + +void cGraphicalSpectrumWidget::zoomIn() { + if (scale < 32) { + scale += factor; + setFixedSize(origwidth*scale, origheight*scale); + repaint(); + ((QScrollArea *)parent)->verticalScrollBar()->setSliderPosition(((QScrollArea *)parent)->verticalScrollBar()->maximum()); + } +} + + +void cGraphicalSpectrumWidget::zoomOut() { + if (scale > 1) { + scale -= factor; + setFixedSize(origwidth*scale, origheight*scale); + repaint(); + ((QScrollArea *)parent)->verticalScrollBar()->setSliderPosition(((QScrollArea *)parent)->verticalScrollBar()->maximum()); + } +} + + +void cGraphicalSpectrumWidget::normalSize() { + scale = 1; + setFixedSize(origwidth, origheight); + repaint(); +} + + +void cGraphicalSpectrumWidget::setMZInterval(double minmz, double maxmz) { + if (maxmz < minmz) { + double tmp = maxmz; + maxmz = minmz; + minmz = tmp; + } + + minmzratio = std::max(0.0, minmz); + maxmzratio = std::min(maxmz, theoreticalspectrum->getExperimentalSpectrum().getMaximumMZRatio()); + emit updateMZInterval(minmzratio, maxmzratio); + repaint(); +} + + +void cGraphicalSpectrumWidget::resetMZInterval() { + minmzratio = 0; + maxmzratio = theoreticalspectrum->getExperimentalSpectrum().getMaximumMZRatio(); + emit updateMZInterval(minmzratio, maxmzratio); + repaint(); +} + + +void cGraphicalSpectrumWidget::rotationChanged(int index) { + coloredrotationid = index - 1; + repaint(); +} + diff --git a/CycloBranch/gui/cGraphicalSpectrumWidget.h b/CycloBranch/gui/cGraphicalSpectrumWidget.h new file mode 100644 index 0000000..0e58efc --- /dev/null +++ b/CycloBranch/gui/cGraphicalSpectrumWidget.h @@ -0,0 +1,157 @@ +/** + \file cGraphicalSpectrumWidget.h + \brief The implementation of a widget painting a 2D mass spectrum. +*/ + + +#ifndef _CGRAPHICALSPECTRUMWIDGET_H +#define _CGRAPHICALSPECTRUMWIDGET_H + +#include +#include + +#include "core/cTheoreticalSpectrum.h" + + +using namespace std; + + +// forward declaration +class QPaintEvent; +class QScrollBar; + + +/** + \brief The widget representing a 2D mass spectrum. +*/ +class cGraphicalSpectrumWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + \param parent pointer to a parent widget + */ + cGraphicalSpectrumWidget(QWidget* parent = 0); + + + /** + \brief The destructor. + */ + ~cGraphicalSpectrumWidget(); + + + /** + \brief Set the theoretical spectrum. + \param theoreticalspectrum pointer to a theoretical spectrum + */ + void setTheoreticalSpectrum(cTheoreticalSpectrum* theoreticalspectrum); + + +protected: + + + /** + \brief Handle the paint event. + \param event pointer to QPaintEvent + */ + void paintEvent(QPaintEvent *event); + + + /** + \brief Handle the mouse wheel event. + \param event pointer to QWheelEvent + */ + void wheelEvent(QWheelEvent *event); + + + /** + \brief Handle the mouse move event. + \param event pointer to QMouseEvent + */ + void mouseMoveEvent(QMouseEvent *event); + + + /** + \brief Handle the mouse release event. + \param event pointer to QMouseEvent + */ + void mouseReleaseEvent(QMouseEvent *event); + + + /** + \brief Handle the mouse press event. + \param event pointer to QMouseEvent + */ + void mousePressEvent(QMouseEvent *event); + + +private: + + void setDefaultSize(); + + double getMZRatioFromXPosition(int x, int w); + + int getXPositionFromMZRatio(double mzratio, int w); + + void drawVerticalText(QPainter* painter, QString text, int x, int y); + + QWidget* parent; + cTheoreticalSpectrum* theoreticalspectrum; + + qreal scale; + qreal factor; + + int origwidth, origheight; + int coloredrotationid; + + bool hideunmatched; + bool hidematched; + + int pressedx; + int pressedy; + + int currentx; + int currenty; + + double minmzratio; + double maxmzratio; + + static const int topmargin = 120; + static const int bottommargin = 30; + static const int leftmargin = 30; + static const int rightmargin = 60; + +signals: + + /** + \brief The signal is emitted when the range of m/z ratios has been changed. + \param minmz a minimum threshold of m/z ratio + \param maxmz a maximum threshold of m/z ratio + */ + void updateMZInterval(double minmz, double maxmz); + +private slots: + + void hideUnmatchedPeaks(int state); + + void hideMatchedPeaks(int state); + + void zoomIn(); + + void zoomOut(); + + void normalSize(); + + void setMZInterval(double minmz, double maxmz); + + void resetMZInterval(); + + void rotationChanged(int index); + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cLinearWidget.cpp b/CycloBranch/gui/cLinearWidget.cpp new file mode 100644 index 0000000..33ceddd --- /dev/null +++ b/CycloBranch/gui/cLinearWidget.cpp @@ -0,0 +1,110 @@ +#include "gui/cLinearWidget.h" + +#include +#include +#include +#include + + +bool operator == (cIonLabel const& a, cIonLabel const& b) { + return ((a.x == b.x) && (a.y == b.y)); +} + + +void insertLabel(unordered_set& labels, int x, int y, string& description, bool alignright) { + cIonLabel label; + label.x = x; + label.y = y; + label.label = description; + label.alignright = alignright; + + if (labels.count(label) == 1) { + auto it = labels.find(label); + label.label = it->label + "," + label.label; + labels.erase(it); + } + + labels.insert(label); +} + + +cLinearWidget::cLinearWidget() { + parameters = 0; + theoreticalspectrum = 0; +} + + +void cLinearWidget::initialize(cParameters* parameters, cTheoreticalSpectrum* theoreticalspectrum) { + this->parameters = parameters; + this->theoreticalspectrum = theoreticalspectrum; +} + + +void cLinearWidget::paintEvent(QPaintEvent *event) { + + if (theoreticalspectrum->getVisualCoverage().size() == 0) { + return; + } + + QPainter painter(this); + const int topmargin = max(20,(height() - 80)/2); + const int leftmargin = 20; + const int bottommargin = 80; + const int rightmargin = 20; + + int size = (int)theoreticalspectrum->getAcronyms().size(); + + const int horizontalstep = (width() - leftmargin - rightmargin)/std::max(size, 1); + + QFont myFont("Courier", 9); + painter.setFont(myFont); + + for (int i = 0; i < size; i++) { + painter.setPen(QPen(Qt::blue, 2, Qt::SolidLine)); + painter.drawText(leftmargin + horizontalstep/4 + horizontalstep*i, topmargin, horizontalstep/2, 20, Qt::AlignCenter, theoreticalspectrum->getAcronyms()[i].c_str()); + + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawRect(leftmargin + horizontalstep/4 + horizontalstep*i, topmargin, horizontalstep/2, 20); + + if (i < size - 1) { + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawLine(leftmargin + horizontalstep/4 + horizontalstep*i + horizontalstep/2, topmargin + 11, leftmargin + horizontalstep/4 + horizontalstep*(i + 1), topmargin + 11); + painter.setPen(QPen(Qt::black, 2, Qt::DashLine)); + painter.drawLine(leftmargin + horizontalstep*(i + 1), topmargin - 10, leftmargin + horizontalstep*(i + 1), topmargin + 30); + painter.drawLine(leftmargin + horizontalstep/4 + horizontalstep/8 + horizontalstep*i + horizontalstep/2, topmargin - 10, leftmargin + horizontalstep*(i + 1), topmargin + - 10); + painter.drawLine(leftmargin + horizontalstep*(i + 1), topmargin + 30, leftmargin + horizontalstep*(i + 1) + horizontalstep/8, topmargin + 30); + } + } + + unordered_set labels; + labels.clear(); + + string name; + int len = (int)theoreticalspectrum->getVisualCoverage()[0].series.size(); + + for (int i = 0; i < (int)parameters->fragmentionsfortheoreticalspectra.size(); i++) { + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].nterminal) { + for (int j = 0; j < len; j++) { + if (theoreticalspectrum->getVisualCoverage()[i].series[j] > 0) { + name = parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].name[0] + to_string(j + 1) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep/4 + horizontalstep/8 + horizontalstep*j + horizontalstep/2, topmargin - 35, name, false); + } + } + } + if (parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].cterminal) { + for (int j = len - 1; j >= 0; j--) { + if (theoreticalspectrum->getVisualCoverage()[i].series[len - j - 1] > 0) { + name = parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].name[0] + to_string(len - j) + parameters->fragmentdefinitions[parameters->fragmentionsfortheoreticalspectra[i]].name.substr(1); + insertLabel(labels, leftmargin + horizontalstep*(j + 1), topmargin + 35, name, false); + } + } + } + } + + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + for (auto it = labels.begin(); it != labels.end(); ++it) { + painter.drawText(it->x, it->y, width(), 20, Qt::AlignLeft, it->label.c_str()); + } + +} + diff --git a/CycloBranch/gui/cLinearWidget.h b/CycloBranch/gui/cLinearWidget.h new file mode 100644 index 0000000..092d3cc --- /dev/null +++ b/CycloBranch/gui/cLinearWidget.h @@ -0,0 +1,147 @@ +/** + \file cLinearWidget.h + \brief Visualization of a linear peptide. +*/ + + +#ifndef _CLINEARWIDGET_H +#define _CLINEARWIDGET_H + +#include + +#include "core/cTheoreticalSpectrum.h" + + +// forward declaration +class QPaintEvent; + + +/** + \brief Auxiliary structure for visualization of labels of fragment ions. +*/ +struct cIonLabel { + + /** + \brief x coordinate. + */ + int x; + + + /** + \brief y coordinate. + */ + int y; + + + /** + \brief Label of a ion. + */ + string label; + + + /** + \brief True when the label is aligned right. + */ + bool alignright; + + + /** + \brief The constructor. + */ + cIonLabel() { + clear(); + } + + + /** + \brief Clear the structure. + */ + void clear() { + x = 0; + y = 0; + label = ""; + alignright = false; + } + +}; + + +/** + \brief The structure defining a hash function of cIonLabel. +*/ +struct hash_cIonLabel { + + /** + \brief Hash a ion label. + \param label reference to a ion label + \retval size_t hashed ion label + */ + size_t operator()(const cIonLabel& label) const { + return hash()(to_string(label.x) + to_string(label.y)); + } + +}; + + +/** + \brief Overloaded operator ==. + \param a first ion label + \param b second ion label + \retval bool true when labels have equal coordinates +*/ +bool operator == (cIonLabel const& a, cIonLabel const& b); + + +/** + \brief Insert a fragment ion label into an unordered set of labels and concatenate descriptions of labels on the same coordinates. + \param labels unordered set of labels + \param x x coordinate + \param y y coordinate + \param description a description of a fragment ion + \param alignright true when the description is aligned right +*/ +void insertLabel(unordered_set& labels, int x, int y, string& description, bool alignright); + + +/** + \brief Visualization of a linear peptide. +*/ +class cLinearWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + */ + cLinearWidget(); + + + /** + \brief Initialize the widget. + \param parameters a pointer to parameters + \param theoreticalspectrum a pointer to a theoretical spectrum + */ + void initialize(cParameters* parameters, cTheoreticalSpectrum* theoreticalspectrum); + + +protected: + + + /** + \brief Handle the paint event. + \param event pointer to QPaintEvent + */ + void paintEvent(QPaintEvent *event); + + +private: + + cParameters* parameters; + cTheoreticalSpectrum* theoreticalspectrum; + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cMainThread.cpp b/CycloBranch/gui/cMainThread.cpp new file mode 100644 index 0000000..e490428 --- /dev/null +++ b/CycloBranch/gui/cMainThread.cpp @@ -0,0 +1,478 @@ +#include "gui/cMainThread.h" + + +QString appname = "CycloBranch"; +QString appversion = "v. 1.0.696 (64-bit)"; + + +cMainThread::cMainThread(cParameters& parameters, bool enablelogwindow, bool enablestdout) { + this->parameters = parameters; + this->enablelogwindow = enablelogwindow; + this->enablestdout = enablestdout; + + // delete thread when run is finished + connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); + + terminatecomputation = false; + graphreaderisworking = false; +} + + +void cMainThread::setGraphReaderIsWorking(bool working) { + graphreaderisworking = working; +} + + +bool cMainThread::isGraphReaderWorking() { + return graphreaderisworking; +} + + +cMainThread& cMainThread::operator<<(const char* x) { + if (enablelogwindow) { + emit message(x); + } + + if (enablestdout) { + cout << x; + } + + return *this; +} + + +cMainThread& cMainThread::operator<<(const string& x) { + if (enablelogwindow) { + emit message(x.c_str()); + } + + if (enablestdout) { + cout << x; + } + + return *this; +} + + +cMainThread& cMainThread::operator<<(StandardEndLine manip) { + if (enablelogwindow) { + QString qs = "\n"; + emit message(qs); + } + + if (enablestdout) { + manip(cout); + cout.flush(); + } + + return *this; +} + + +void cMainThread::run() { + + emitStartSignals(); + + cMainThread* os = this; + + cCandidateSet candidates; + candidates.getSet().clear(); + + QTime time; + time.start(); + + *os << "====================================================================================================" << endl; + + *os << appname.toStdString() << " started at " << time.currentTime().toString().toStdString() << "." << endl << endl; + + parameters.setOutputStream(*os); + if (parameters.checkAndPrepare() == -1) { + emit safeExit(); + return; + } + *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 == 1) { + if (parameters.searchedsequence.compare("") == 0) { + *os << "Error: Searched sequence is empty." << endl; + 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; + } + + try { + if (!(regex_search(parameters.searchedsequence, rx))) { + *os << "Error: The format of searched sequence is invalid." << endl; + 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; + } + + bool error = false; + string errormessage = ""; + for (int i = 0; i < (int)parameters.searchedmodifications.size(); i++) { + parameters.searchedmodifications[i].massdifference = getMassFromResidueSummary(parameters.searchedmodifications[i].summary, error, errormessage); + if (error) { + *os << errormessage << endl; + emit safeExit(); + return; + } + } + + 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(); + return; + } + parameters.peaklist.cropIntenzity(parameters.minimumrelativeintensitythreshold); + //parameters.peaklist.maxHighestPeaksInWindow(10, 50); + + *os << "Peaklist:" << endl; + *os << parameters.peaklist.print(); + if (parameters.masserrortolerancefordeisotoping > 0) { + parameters.peaklist.removeIsotopes(parameters.precursorcharge, parameters.masserrortolerancefordeisotoping, this); + } + + //search engine + if (parameters.mode == 0) { + + // create the de novo graph + graph.initialize(*os, parameters); + if (graph.createGraph(terminatecomputation) == -1) { + endNow(); + return; + } + + emit setGraph(graph.printGraph()); + + // blind paths are removed + // note: paths finishing in precursor minus X are removed, however, precursor peak is always present thus any candidate should not be lost + if (parameters.blindedges == 1) { + if (graph.removeEdgesFormingPathsNotStartingFromFirstNode(terminatecomputation) == -1) { + endNow(); + return; + } + + if (graph.removeEdgesFormingPathsNotFinishingInPrecursor(terminatecomputation) == -1) { + endNow(); + return; + } + } + + // blind paths are connected + if (parameters.blindedges == 2) { + if (graph.connectEdgesFormingPathsNotStartingFromFirstNode(terminatecomputation) == -1) { + endNow(); + return; + } + + if (graph.connectEdgesFormingPathsNotFinishingInPrecursor(terminatecomputation) == -1) { + endNow(); + return; + } + } + //graph.getBrickDatabaseWithCombinations()->print(); + + emit setGraph(graph.printGraph()); + + if (graph.removePathsWhichCanBeSubstitutedByLongerPath(terminatecomputation) == -1) { + endNow(); + return; + } + + graph.sortEdgesByTargetNodeIntensity(); + + 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; + + } + // comparison of a theoretical spectrum + else { + + vector v; + cCandidate c; + cBrick b; + string s; + int startmodifid, endmodifid, middlemodifid; + int branchstart = -1; + int branchend = -1; + + 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; + } + else { + startmodifid = 0; + endmodifid = 0; + } + + if ((parameters.peptidetype == branched) || (parameters.peptidetype == lasso)) { + middlemodifid = -1; + } + else { + middlemodifid = 0; + } + + 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(parameters.searchedsequenceNtermmodif) == 0) { + startmodifid = i; + } + + if (parameters.searchedmodifications[i].name.compare(parameters.searchedsequenceCtermmodif) == 0) { + endmodifid = i; + } + } + + if ((parameters.peptidetype == branched) || (parameters.peptidetype == lasso)) { + if (parameters.searchedmodifications[i].name.compare(parameters.searchedsequenceTmodif) == 0) { + middlemodifid = i; + } + } + + } + + if (startmodifid == -1) { + *os << endl << "Error: Unknown N-terminal modification is used." << endl; + emitEndSignals(); + endNow(); + return; + } + + if (endmodifid == -1) { + *os << endl << "Error: Unknown C-terminal modification is used." << endl; + emitEndSignals(); + endNow(); + return; + } + + if (middlemodifid == -1) { + *os << endl << "Error: Unknown T-modification is used." << endl; + emitEndSignals(); + endNow(); + return; + } + + } + + 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++; + } + } + + 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(v); + vector tmp; + c.setCandidate(v, tmp, startmodifid, endmodifid, middlemodifid, branchstart, branchend); + + 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; + } + theoreticalspectra.initialize(*os, parameters, &graph); + if (theoreticalspectra.parallelCompareAndStore(candidates, terminatecomputation) == -1) { + emitEndSignals(); + endNow(); + return; + } + *os << "ok" << endl; + + /* + *os << endl << "Explanation list of peaks (m/z ratio: etc.):" << endl; + if (theoreticalspectra.size() > 0) { + for (int i = 0; i < theoreticalspectra[0].getExperimentalSpectrum().size(); i++) { + *os << parameters.peaklist[i].mzratio << ": "; + for (int j = 0; j < theoreticalspectra.size(); j++) { + if (theoreticalspectra[j].getExperimentalSpectrum()[i].matched > 0) { + *os << j + 1 << " "; + } + } + *os << endl; + } + } + */ + + /* + double maxintensity; + double mzratio; + if (theoreticalspectra.size() > 0) { + for (int i = 0; i < theoreticalspectra.size(); i++) { + *os << i + 1 << ": "; + maxintensity = 0; + mzratio = 0; + for (int j = 0; j < theoreticalspectra[i].getExperimentalSpectrum().size(); j++) { + if ((theoreticalspectra[i].getExperimentalSpectrum()[j].matched == 0) && (theoreticalspectra[i].getExperimentalSpectrum()[j].intensity > maxintensity)) { + maxintensity = theoreticalspectra[i].getExperimentalSpectrum()[j].intensity; + mzratio = theoreticalspectra[i].getExperimentalSpectrum()[j].mzratio; + } + } + *os << mzratio << " " << maxintensity << endl; + } + } + */ + + emitEndSignals(); + + int secs = time.elapsed() / 1000; + int mins = (secs / 60) % 60; + int hrs = (secs / 3600); + secs = secs % 60; + + *os << endl << appname.toStdString() << " successfully finished at " << time.currentTime().toString().toStdString(); + *os << " (time elapsed: " << to_string(hrs) << " hrs, " << to_string(mins) << " min, " << to_string(secs) << " sec)." << endl; + + *os << "====================================================================================================" << endl; + +} + + +void cMainThread::emitStartSignals() { + emit enableRunButtonAndSettings(false); + emit enableStopButton(true); + emit enableButtonsHandlingResults(false); + + if (parameters.mode != 0) { + emit setGraph(""); + } +} + + +void cMainThread::emitEndSignals() { + emit sendParameters(parameters); + + emit prepareColumns(); + + for (int i = 0; i < theoreticalspectra.size(); i++) { + emit sendTheoreticalSpectrum(theoreticalspectra[i]); + theoreticalspectra[i].clear(); + } + + emit fitColumns(); + + emit enableRunButtonAndSettings(true); + emit enableStopButton(false); + emit enableButtonsHandlingResults(true); +} + + +void cMainThread::endNow() { + emit setGraph(graph.printGraph()); + emit safeExit(); + if (terminatecomputation) { + *this << endl << "Aborted by user." << endl; + } +} + + +void cMainThread::stopComputation() { + *this << endl << endl << "Please wait while stopping threads and generating partial results..." << endl; + terminatecomputation = true; +} + + +void cMainThread::graphReaderFinished() { + graphreaderisworking = false; +} + diff --git a/CycloBranch/gui/cMainThread.h b/CycloBranch/gui/cMainThread.h new file mode 100644 index 0000000..aaf9bdf --- /dev/null +++ b/CycloBranch/gui/cMainThread.h @@ -0,0 +1,231 @@ +/** + \file cMainThread.h + \brief The thread launched by the command 'Search->Run'. +*/ + + +#ifndef _CMAINTHREAD_H +#define _CMAINTHREAD_H + +#include +#include +#include +#include + +#include "core/cParameters.h" +#include "core/cDeNovoGraph.h" +#include "core/cTheoreticalSpectrum.h" + +using namespace std; + + +/** + \brief The name of the application. +*/ +extern QString appname; + + +/** + \brief The version of the application. +*/ +extern QString appversion; + + +/** + \brief The class representing a thread launched by the command 'Search->Run'. +*/ +class cMainThread : public QThread { + + Q_OBJECT + +private: + + bool enablelogwindow; + bool enablestdout; + bool terminatecomputation; + bool graphreaderisworking; + + cDeNovoGraph graph; + cTheoreticalSpectrumList theoreticalspectra; + cParameters parameters; + +public: + + + /** + \brief The constructor. + \param parameters reference to input paramaters + \param enablelogwindow if true then messages are logged into the log window + \param enablestdout if true then messages are logged into the standard output + */ + cMainThread(cParameters& parameters, bool enablelogwindow = true, bool enablestdout = true); + + + /** + \brief Set the flag that the graph reader is working. + \param working set true when the graph reader is working, otherwise set false + */ + void setGraphReaderIsWorking(bool working); + + + /** + \brief Check the flag whether the graph reader is working. + \retval bool true when the graph reader is working, false otherwise + */ + bool isGraphReaderWorking(); + + + /** + \brief This is the type of std::cout. + */ + typedef std::basic_ostream > CoutType; + + + /** + \brief This is the function signature of std::endl. + */ + typedef CoutType& (*StandardEndLine)(CoutType&); + + + /** + \brief Overloaded operator <<. + */ + template cMainThread& operator<<(const T& x) { + if (enablelogwindow) { + emit message(to_string(x).c_str()); + } + + if (enablestdout) { + cout << x; + } + + return *this; + } + + + /** + \brief Overloaded operator <<. + */ + cMainThread& operator<<(const char* x); + + + /** + \brief Overloaded operator <<. + */ + cMainThread& operator<<(const string& x); + + + /** + \brief Define an operator << to take in std::endl. + */ + cMainThread& operator<<(StandardEndLine manip); + + +protected: + + + /** + \brief The main method of the thread. + */ + void run(); + + + /** + \brief The signals emitted when the thread has launched. + */ + void emitStartSignals(); + + + /** + \brief The signals emitted when the thread has successfully finished. + */ + void emitEndSignals(); + + + /** + \brief The signals emitted when the thread was forced to stop. + */ + void endNow(); + + +signals: + + + /** + \brief A message which will be shown in log window. + \param s text of the message + */ + void message(QString s); + + + /** + \brief Enable or disable options 'Search->Run' and 'Search->Settings...'. + \param enable true == enable, false == disable + */ + void enableRunButtonAndSettings(bool enable); + + + /** + \brief Enable or disable the option 'Search->Stop'. + \param enable true == enable, false == disable + */ + void enableStopButton(bool enable); + + + /** + \brief Enable or disable buttons handling results. + \param enable true == enable, false == disable + */ + void enableButtonsHandlingResults(bool enable); + + + /** + \brief Send a theoretical spectrum to cMainWindow when the thread has finished. + \param theoreticalspectrum a theoretical spectrum + */ + void sendTheoreticalSpectrum(cTheoreticalSpectrum theoreticalspectrum); + + + /** + \brief Send parameters to cMainWindow when the thread has finished. + \param parameters parameters + */ + void sendParameters(cParameters parameters); + + + /** + \brief Prepare columns in cMainWindow when the thread has finished. + */ + void prepareColumns(); + + + /** + \brief Fit the width of columns in cMainWindow. + */ + void fitColumns(); + + + /** + \brief Set the graph into the cGraphWidget. + \param s graph printed as a string + */ + void setGraph(string s); + + + /** + \brief Safely exit when the thread was forced to stop. + */ + void safeExit(); + + +private slots: + + void stopComputation(); + + void graphReaderFinished(); + +}; + + +#endif + diff --git a/CycloBranch/gui/cMainWindow.cpp b/CycloBranch/gui/cMainWindow.cpp new file mode 100644 index 0000000..c6e68eb --- /dev/null +++ b/CycloBranch/gui/cMainWindow.cpp @@ -0,0 +1,719 @@ +#include "gui/cMainWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +cMainWindow::cMainWindow() { + + // main menu + menuBar = new QMenuBar(this); + + // items in the menu + menuFile = new QMenu(tr("&File"), this); + menuSearch = new QMenu(tr("&Search"), this); + menuView = new QMenu(tr("&View"), this); + menuHelp = new QMenu(tr("&Help"), this); + + // subitems in the menu + // actionOpen = new QAction(tr("&Open"), this); + actionOpenResults = new QAction(tr("&Open Results..."), this); + actionSaveResults = new QAction(tr("&Save Results..."), this); + actionExportToCsv = new QAction(tr("&Export to CSV"), this); + actionExportToHTML = new QAction(tr("&Export to HTML"), this); + actionQuit = new QAction(tr("&Quit"), this); + actionRun = new QAction(tr("&Run"), this); + actionStop = new QAction(tr("&Stop"), this); + actionStop->setEnabled(false); + actionProperties = new QAction(tr("&Settings..."), this); + actionGraph = new QAction(tr("&Graph"), this); + actionLog = new QAction(tr("&Log Window"), this); + actionHTMLDocumentation = new QAction(tr("&HTML Documentation"), this); + actionPDFManual = new QAction(tr("&PDF Manual"), this); + actionAbout = new QAction(tr("&About"), this); + + // widgets + results = new QTableWidget(0, 0, this); + logWindow = new QTextEdit(this); + splitter = new QSplitter(this); + + about = new cAboutWidget(this); + graph = new cGraphWidget(); + parameterswidget = new cParametersWidget(); + + // additional key shortcuts + // actionOpen->setShortcut(QKeySequence("Ctrl+O")); + + // connection of menu items with functions + // connect(actionOpen, SIGNAL(triggered()), this, SLOT(openDir())); + connect(actionOpenResults, SIGNAL(triggered()), this, SLOT(openResultsFile())); + connect(actionSaveResults, SIGNAL(triggered()), this, SLOT(saveResultsFile())); + connect(actionExportToCsv, SIGNAL(triggered()), this, SLOT(exportToCsv())); + connect(actionExportToHTML, SIGNAL(triggered()), this, SLOT(exportToHTML())); + connect(actionQuit, SIGNAL(triggered()), this, SLOT(stop())); + connect(actionQuit, SIGNAL(triggered()), qApp, SLOT(quit())); + connect(actionRun, SIGNAL(triggered()), this, SLOT(run())); + connect(actionStop, SIGNAL(triggered()), this, SLOT(stop())); + connect(actionProperties, SIGNAL(triggered()), this, SLOT(showProperties())); + connect(actionGraph, SIGNAL(triggered()), this, SLOT(showGraph())); + connect(actionLog, SIGNAL(triggered()), this, SLOT(showHideLog())); + connect(actionHTMLDocumentation, SIGNAL(triggered()), this, SLOT(showHTMLDocumentation())); + connect(actionPDFManual, SIGNAL(triggered()), this, SLOT(showPDFManual())); + connect(actionAbout, SIGNAL(triggered()), this, SLOT(showAbout())); + + // add subitems to the items in main menu + // menuFile->addAction(actionOpen); + menuFile->addAction(actionOpenResults); + menuFile->addAction(actionSaveResults); + menuFile->addSeparator(); + menuFile->addAction(actionExportToCsv); + menuFile->addAction(actionExportToHTML); + menuFile->addSeparator(); + menuFile->addAction(actionQuit); + menuSearch->addAction(actionRun); + menuSearch->addAction(actionStop); + menuSearch->addSeparator(); + menuSearch->addAction(actionProperties); + menuView->addAction(actionGraph); + menuView->addAction(actionLog); + menuHelp->addAction(actionHTMLDocumentation); + menuHelp->addAction(actionPDFManual); + menuHelp->addSeparator(); + menuHelp->addAction(actionAbout); + + // add items to the main menu + menuBar->addMenu(menuFile); + menuBar->addMenu(menuSearch); + menuBar->addMenu(menuView); + menuBar->addMenu(menuHelp); + + // enable the menu + setMenuBar(menuBar); + + results->setEditTriggers(QAbstractItemView::NoEditTriggers); + results->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); + results->horizontalHeader()->setSectionsMovable(true); + connect(results->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(headerItemDoubleClicked(int))); + connect(results, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(resultsCellClicked(int, int))); + + logWindow->setReadOnly(true); + + about->hide(); + graph->hide(); + parameterswidget->hide(); + + splitter->setOrientation(Qt::Vertical); + splitter->addWidget(results); + splitter->addWidget(logWindow); + splitter->setStretchFactor(0, 1); + + // set the central widget + setCentralWidget(splitter); + + // set the size of main window + resize(1280, 700); + + setWindowTitle(appname); + + resultsbasecolumncount = 7; + resultsspecificcolumncount = 0; + + resultsDetails.clear(); + + lastdirexporttocsv = "./"; + lastdirexporttohtml = "./"; + lastdirsaveresults = "./"; + lastdiropenresults = "./"; +} + + +void cMainWindow::closeEvent(QCloseEvent *event) { + emit stopComputation(); + qApp->quit(); +} + + +void cMainWindow::showHideLog() { + bool state = logWindow->isVisible(); + + if (state) { + logWindow->hide(); + } + else { + logWindow->show(); + } +} + + +void cMainWindow::showAbout() { + about->show(); + about->activateWindow(); +} + + +void cMainWindow::showGraph() { + graph->show(); + graph->activateWindow(); +} + + +void cMainWindow::showProperties() { + parameterswidget->show(); + parameterswidget->activateWindow(); +} + + +void cMainWindow::run() { + logWindow->clear(); + deleteResults(); + resultsDetails.clear(); + + cMainThread* thread = new cMainThread(parameterswidget->getParameters(), true, false); + connect(thread, SIGNAL(message(QString)), this, SLOT(updateLog(QString))); + connect(thread, SIGNAL(enableRunButtonAndSettings(bool)), this, SLOT(enableRunButtonAndSettings(bool))); + connect(thread, SIGNAL(enableStopButton(bool)), this, SLOT(enableStopButton(bool))); + connect(thread, SIGNAL(enableButtonsHandlingResults(bool)), this, SLOT(enableButtonsHandlingResults(bool))); + connect(thread, SIGNAL(sendTheoreticalSpectrum(cTheoreticalSpectrum)), this, SLOT(sendTheoreticalSpectrum(cTheoreticalSpectrum))); + connect(thread, SIGNAL(sendParameters(cParameters)), this, SLOT(sendParameters(cParameters))); + connect(thread, SIGNAL(prepareColumns()), this, SLOT(prepareColumns())); + connect(thread, SIGNAL(fitColumns()), this, SLOT(fitColumns())); + connect(thread, SIGNAL(setGraph(string)), this, SLOT(setGraph(string))); + connect(this, SIGNAL(stopComputation()), thread, SLOT(stopComputation())); + connect(thread, SIGNAL(safeExit()), this, SLOT(safeExit())); + + thread->start(); +} + + +void cMainWindow::stop() { + emit stopComputation(); +} + + +void cMainWindow::updateLog(QString qstr) { + QTextCursor cursor(logWindow->textCursor()); + cursor.movePosition(QTextCursor::End); + logWindow->setTextCursor(cursor); + logWindow->insertPlainText(qstr); + QScrollBar *sb = logWindow->verticalScrollBar(); + sb->setValue(sb->maximum()); +} + + +void cMainWindow::enableRunButtonAndSettings(bool enable) { + actionRun->setEnabled(enable); + + actionProperties->setEnabled(enable); + parameterswidget->hide(); +} + + +void cMainWindow::enableStopButton(bool enable) { + actionStop->setEnabled(enable); +} + + +void cMainWindow::enableButtonsHandlingResults(bool enable) { + actionOpenResults->setEnabled(enable); + actionSaveResults->setEnabled(enable); + actionExportToCsv->setEnabled(enable); + actionExportToHTML->setEnabled(enable); +} + + +void cMainWindow::sendTheoreticalSpectrum(cTheoreticalSpectrum theoreticalspectrum) { + int row = results->rowCount(); + results->insertRow(row); + + results->setItem(row, 0, new QTableWidgetItem("")); + + 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, getNumberOfBricks(theoreticalspectrum.getCandidate().getComposition())); + + switch (parameters.peptidetype) + { + case linear: + results->setItem(row, 4, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str())); + results->setItem(row, 5, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str())); + break; + case branched: + results->setItem(row, 4, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str())); + results->setItem(row, 5, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getMiddleModifID()].name.c_str())); + results->setItem(row, 6, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str())); + break; + case cyclic: + results->setItem(row, 4, new QTableWidgetItem()); + results->item(row, 4)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedBricks()); + break; + case lasso: + results->setItem(row, 4, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getMiddleModifID()].name.c_str())); + break; + case linearpolysaccharide: + results->setItem(row, 4, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getStartModifID()].name.c_str())); + results->setItem(row, 5, new QTableWidgetItem(parameters.searchedmodifications[theoreticalspectrum.getCandidate().getEndModifID()].name.c_str())); + break; + default: + break; + } + + results->setItem(row, 4 + resultsspecificcolumncount, new QTableWidgetItem()); + results->item(row, 4 + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getNumberOfMatchedPeaks()); + + results->setItem(row, 5 + resultsspecificcolumncount, new QTableWidgetItem()); + results->item(row, 5 + resultsspecificcolumncount)->setData(Qt::DisplayRole, theoreticalspectrum.getRatioOfMatchedPeaks()*100); + + results->setItem(row, 6 + resultsspecificcolumncount, new QTableWidgetItem()); + results->item(row, 6 + 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])); + } + + 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); + } + } + + cSpectrumDetailWidget sd; + sd.initialize(¶meters, theoreticalspectrum); + sd.setWindowTitle(("Theoretical Spectrum No. " + to_string(row+1)).c_str()); + resultsDetails.push_back(sd); +} + + +void cMainWindow::sendParameters(cParameters parameters) { + this->parameters = parameters; +} + + +void cMainWindow::prepareColumns() { + + switch (parameters.peptidetype) + { + case linear: + resultsspecificcolumncount = 2; + break; + case branched: + resultsspecificcolumncount = 3; + break; + case cyclic: + resultsspecificcolumncount = 1; + break; + case lasso: + resultsspecificcolumncount = 1; + break; + case linearpolysaccharide: + resultsspecificcolumncount = 2; + break; + default: + break; + } + + string s; + + results->setColumnCount(resultsbasecolumncount + resultsspecificcolumncount + (int)parameters.fragmentionsfortheoreticalspectra.size()); + + results->setHorizontalHeaderItem(0, new QTableWidgetItem("*")); + results->setHorizontalHeaderItem(1, new QTableWidgetItem("Result ID")); + results->setHorizontalHeaderItem(2, new QTableWidgetItem("Peptide Sequence")); + results->setHorizontalHeaderItem(3, new QTableWidgetItem("Number of Bricks")); + + switch (parameters.peptidetype) + { + case linear: + results->setHorizontalHeaderItem(4, new QTableWidgetItem("N-terminal Modification")); + results->setHorizontalHeaderItem(5, new QTableWidgetItem("C-terminal Modification")); + break; + case branched: + results->setHorizontalHeaderItem(4, new QTableWidgetItem("N-terminal Modification")); + results->setHorizontalHeaderItem(5, new QTableWidgetItem("T-Modification")); + results->setHorizontalHeaderItem(6, new QTableWidgetItem("C-terminal Modification")); + break; + case cyclic: + results->setHorizontalHeaderItem(4, new QTableWidgetItem("Matched Bricks")); + break; + case lasso: + results->setHorizontalHeaderItem(4, new QTableWidgetItem("T-Modification")); + break; + case linearpolysaccharide: + results->setHorizontalHeaderItem(4, new QTableWidgetItem("N-terminal Modification")); + results->setHorizontalHeaderItem(5, new QTableWidgetItem("C-terminal Modification")); + break; + default: + break; + } + + results->setHorizontalHeaderItem(4 + resultsspecificcolumncount, new QTableWidgetItem("Matched Peaks")); + results->setHorizontalHeaderItem(5 + resultsspecificcolumncount, new QTableWidgetItem("Ratio of Matched Peaks [%]")); + results->setHorizontalHeaderItem(6 + resultsspecificcolumncount, new QTableWidgetItem("Sum of Relative Intensities")); + + 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())); + } + results->resizeColumnsToContents(); + + resultsheadersort.resize(results->columnCount()); + for (int i = 0; i < results->columnCount(); i++) { + resultsheadersort[i] = -1; + } + +} + + +void cMainWindow::fitColumns() { + for (int i = 0; i < results->columnCount(); i++) { + results->resizeColumnToContents(i); + } +} + + +void cMainWindow::deleteResults() { + while (results->rowCount() > 0) { + for (int i = 0; i < results->columnCount(); i++) { + delete results->item(results->rowCount() - 1, i); + } + results->removeRow(results->rowCount() - 1); + } + + for (int i = 0; i < results->columnCount(); i++) { + delete results->horizontalHeaderItem(i); + } + results->setColumnCount(0); +} + + +void cMainWindow::resultsCellClicked(int row, int column) { + resultsDetails[results->item(row, 1)->data(Qt::DisplayRole).toInt() - 1].prepareToShow(parameters.peptidetype); + resultsDetails[results->item(row, 1)->data(Qt::DisplayRole).toInt() - 1].show(); + resultsDetails[results->item(row, 1)->data(Qt::DisplayRole).toInt() - 1].activateWindow(); +} + + +void cMainWindow::setGraph(string s) { + graph->setHTML(s); +} + + +void cMainWindow::headerItemDoubleClicked(int index) { + if (resultsheadersort[index] == -1) { + results->sortByColumn(index, Qt::DescendingOrder); + resultsheadersort[index] = 0; + return; + } + + if (resultsheadersort[index] == 0) { + results->sortByColumn(index, Qt::AscendingOrder); + resultsheadersort[index] = 1; + } + else { + results->sortByColumn(index, Qt::DescendingOrder); + resultsheadersort[index] = 0; + } +} + + +void cMainWindow::safeExit() { + enableRunButtonAndSettings(true); + enableStopButton(false); + enableButtonsHandlingResults(true); +} + + +void cMainWindow::exportToCsv() { + QString filename = QFileDialog::getSaveFileName(this, tr("Export to CSV"), lastdirexporttocsv, tr("Files (*.csv)")); + lastdirexporttocsv = filename; + + if (filename.toStdString().compare("") != 0) { + + QFile file(filename); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + return; + } + + QTextStream out(&file); + + for (int i = 0; i < results->columnCount(); i++) { + out << "\"" << results->horizontalHeaderItem(i)->text() << "\""; + if (i < results->columnCount() - 1) { + out << ","; + } + } + out << endl; + + for (int i = 0; i < results->rowCount(); i++) { + for (int j = 0; j < results->columnCount(); j++) { + out << "\"" << results->item(i, j)->data(Qt::DisplayRole).toString() << "\""; + if (j < results->columnCount() - 1) { + out << ","; + } + } + out << endl; + } + + file.close(); + } +} + + +void cMainWindow::exportToHTML() { + QString filename = QFileDialog::getSaveFileName(this, tr("Export to HTML"), lastdirexporttohtml, tr("HTML Files (*.htm *.html)")); + lastdirexporttohtml = filename; + + if (filename.toStdString().compare("") != 0) { + + QFile file(filename); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + return; + } + + QTextStream out(&file); + + if (results->rowCount() > 0) { + + bool matchedrow; + string title = appname.toStdString() + " " + appversion.toStdString() + " - Output Report"; + + out << "\n"; + out << "\n"; + out << "" << QString(title.c_str()) << "\n"; + out << "\n"; + + out << ""; + + out << "\n"; + out << "\n"; + + out << "

" << QString(title.c_str()) << "

\n"; + + out << "

Results

\n"; + + out << "

Hint: Click on a row to expand details about a peptide sequence candidate.

"; + + out << "

\n\n"; + for (int i = 0; i < results->columnCount(); i++) { + out << "\n"; + } + out << "\n"; + + for (int i = 0; i < results->rowCount(); i++) { + out << "\n"; + + matchedrow = false; + if (results->item(i, 0)->data(Qt::DisplayRole).toString().compare("*") == 0) { + matchedrow = true; + } + + for (int j = 0; j < results->columnCount(); j++) { + out << "" << results->item(i, j)->data(Qt::DisplayRole).toString() << "\n"; + } + + out << "\n"; + + out << "\n"; + } + out << "
" << results->horizontalHeaderItem(i)->text() << "
columnCount(); + out << "\">\n"; + + out << "

" << resultsDetails[i].getTheoreticalSpectrum().getCoverageBySeries().c_str(); + out << "
" << resultsDetails[i].getDetailsAsHTMLString().c_str() << "

\n"; + + out << "

\n"; + + out << "

Parameters

\n"; + + out << "

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

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

De Novo Graph

\n"; + + out << "

\n" << graph->getHTML().c_str() << "

"; + + } + + out << "\n"; + out << "\n"; + + } + + file.close(); + + } + +} + + +void cMainWindow::showHTMLDocumentation() { + QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo("docs/html/userguide.html").absoluteFilePath())); +} + + +void cMainWindow::showPDFManual() { + QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo("docs/refman.pdf").absoluteFilePath())); +} + + +void cMainWindow::saveResultsFile() { + + string filetypes = appname.toStdString() + " " + appversion.toStdString() + " Results Files (*.res)"; + QString filename = QFileDialog::getSaveFileName(this, tr("Save Results..."), lastdirsaveresults, tr(filetypes.c_str())); + lastdirsaveresults = filename; + + if (filename.toStdString().compare("") != 0) { + + ofstream outfile; + outfile.open(filename.toStdString().c_str(), ios::out | ios::binary | ios::trunc); + + if (outfile.is_open()) { + int size; + + // store graph window + graph->store(outfile); + + // store log window + size = logWindow->toPlainText().size(); + outfile.write((char *)&size, sizeof(int)); + outfile.write(logWindow->toPlainText().toStdString().c_str(), logWindow->toPlainText().size()); + + // store parameters + parameters.store(outfile); + + // store theoretical spectra + size = (int)resultsDetails.size(); + outfile.write((char *)&size, sizeof(int)); + for (int i = 0; i < (int)resultsDetails.size(); i++) { + resultsDetails[i].getTheoreticalSpectrum().store(outfile); + } + + // close file + outfile.close(); + } + + } + +} + + +void cMainWindow::openResultsFile() { + + string filetypes = appname.toStdString() + " " + appversion.toStdString() + " Results Files (*.res)"; + QString filename = QFileDialog::getOpenFileName(this, tr("Open Results..."), lastdiropenresults, tr(filetypes.c_str())); + lastdiropenresults = filename; + + if (filename.toStdString().compare("") != 0) { + + ifstream infile; + infile.open(filename.toStdString().c_str(), ios::in | ios::binary); + + if (infile.is_open()) { + int size; + string s; + cTheoreticalSpectrum theoreticalspectrum; + + deleteResults(); + resultsDetails.clear(); + + // load graph window + graph->load(infile); + + // load log window + infile.read((char *)&size, sizeof(int)); + s.resize(size); + infile.read(&s[0], s.size()); + logWindow->setPlainText(s.c_str()); + QScrollBar *sb = logWindow->verticalScrollBar(); + sb->setValue(sb->maximum()); + + // load parameters + parameters.load(infile); + parameterswidget->setAndRestoreParameters(parameters); + + // load theoretical spectra + prepareColumns(); + infile.read((char *)&size, sizeof(int)); + for (int i = 0; i < size; i++) { + theoreticalspectrum.load(infile); + sendTheoreticalSpectrum(theoreticalspectrum); + } + fitColumns(); + + // close file + infile.close(); + } + + } + +} + + +/* +void cMainWindow::showContextMenu(const QPoint &pt) { + QMenu *menu = logWindow->createStandardContextMenu(); + menu->addAction(clear); + menu->exec(logWindow->mapToGlobal(pt)); + delete menu; +} +*/ + + +cMainWindow::~cMainWindow() { + deleteResults(); + + delete menuBar; + + delete menuFile; + delete menuSearch; + delete menuView; + delete menuHelp; + + delete actionOpenResults; + delete actionSaveResults; + delete actionExportToCsv; + delete actionExportToHTML; + delete actionQuit; + delete actionProperties; + delete actionRun; + delete actionGraph; + delete actionLog; + delete actionHTMLDocumentation; + delete actionPDFManual; + delete actionAbout; + + delete results; + delete logWindow; + delete splitter; + + delete about; + delete graph; + delete parameterswidget; +} + diff --git a/CycloBranch/gui/cMainWindow.h b/CycloBranch/gui/cMainWindow.h new file mode 100644 index 0000000..779a713 --- /dev/null +++ b/CycloBranch/gui/cMainWindow.h @@ -0,0 +1,170 @@ +/** + \file cMainWindow.h + \brief The main window of the application. +*/ + + +#ifndef _MAINWINDOW_H +#define _MAINWINDOW_H + +#include +#include +#include +#include +#include "core/cTheoreticalSpectrum.h" +#include "gui/cAboutWidget.h" +#include "gui/cGraphWidget.h" +#include "gui/cParametersWidget.h" +#include "gui/cSpectrumDetailWidget.h" +#include "gui/cMainThread.h" + +// forward declaration +class QTextEdit; +class QSplitter; +class QTableWidget; + + +/** + \brief The class representing the main window of the application. +*/ +class cMainWindow : public QMainWindow +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + */ + cMainWindow(); + + + /** + \brief The destructor. + */ + ~cMainWindow(); + + +private: + + // main menu + QMenuBar* menuBar; + + // items in the menu + QMenu* menuFile; + QMenu* menuSearch; + QMenu* menuView; + QMenu* menuHelp; + + // subitems in the menu + QAction* actionOpenResults; + QAction* actionSaveResults; + QAction* actionExportToCsv; + QAction* actionExportToHTML; + QAction* actionQuit; + QAction* actionRun; + QAction* actionStop; + QAction* actionProperties; + QAction* actionGraph; + QAction* actionLog; + QAction* actionHTMLDocumentation; + QAction* actionPDFManual; + QAction* actionAbout; + + QTableWidget* results; + + vector resultsDetails; + cParameters parameters; + + QTextEdit* logWindow; + QSplitter* splitter; + + cAboutWidget* about; + cGraphWidget* graph; + cParametersWidget* parameterswidget; + + int resultsbasecolumncount; + int resultsspecificcolumncount; + + vector resultsheadersort; + + QString lastdirexporttocsv; + QString lastdirexporttohtml; + QString lastdirsaveresults; + QString lastdiropenresults; + + void closeEvent(QCloseEvent *event); + + +private slots: + + void showHideLog(); + + void showAbout(); + + void showGraph(); + + void showProperties(); + + void run(); + + void stop(); + + void updateLog(QString qstr); + + void enableRunButtonAndSettings(bool enable); + + void enableStopButton(bool enable); + + void enableButtonsHandlingResults(bool enable); + + void sendTheoreticalSpectrum(cTheoreticalSpectrum theoreticalspectrum); + + void sendParameters(cParameters parameters); + + void prepareColumns(); + + void fitColumns(); + + void deleteResults(); + + void resultsCellClicked(int row, int column); + + void setGraph(string s); + + void headerItemDoubleClicked(int); + + void safeExit(); + + void exportToCsv(); + + void exportToHTML(); + + void showHTMLDocumentation(); + + void showPDFManual(); + + void saveResultsFile(); + + void openResultsFile(); + + //void showContextMenu(const QPoint &pt); + +signals: + + /** + \brief The option 'Search->Stop' has been selected. + */ + void stopComputation(); + +}; + + +/** + \brief Register string by Qt. +*/ +Q_DECLARE_METATYPE(string); + + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cParametersWidget.cpp b/CycloBranch/gui/cParametersWidget.cpp new file mode 100644 index 0000000..06c8b41 --- /dev/null +++ b/CycloBranch/gui/cParametersWidget.cpp @@ -0,0 +1,1026 @@ +#include "gui/cParametersWidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +cParametersWidget::cParametersWidget() { + setWindowTitle("Settings..."); + + settingsfile = ""; + oldsettingsfile = ""; + peaklistfilename = ""; + brickdatabasefilename = ""; + + stdbuttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel); + stdbuttons->button(QDialogButtonBox::Ok)->setToolTip("Accept changes and hide window."); + stdbuttons->button(QDialogButtonBox::Apply)->setToolTip("Accept changes and keep window opened."); + stdbuttons->button(QDialogButtonBox::Cancel)->setToolTip("Drop changes and hide window."); + load = new QPushButton(tr("Load")); + load->setToolTip("Load settings from a file (*.ini)."); + save = new QPushButton(QString("Save")); + save->setToolTip("Save settings in the current file (*.ini). When a file has not been loaded yet, the \"Save As ...\" file dialog is opened."); + saveas = new QPushButton(tr("Save As...")); + saveas->setToolTip("Save settings into a file (*.ini)."); + + buttons = new QHBoxLayout(); + buttons->addWidget(stdbuttons); + buttons->addStretch(1); + buttons->addWidget(load); + buttons->addWidget(save); + buttons->addWidget(saveas); + + + peaklistformlayout = new QFormLayout(); + + peptidetype = new QComboBox(); + peptidetype->setToolTip("Select the type of peptide best corresponding to the peaklist."); + peptidetype->addItem(tr("Linear")); + peptidetype->addItem(tr("Cyclic")); + peptidetype->addItem(tr("Branched")); + peptidetype->addItem(tr("Lasso")); + peptidetype->addItem(tr("Linear polysaccharide (beta version)")); + peaklistformlayout->addRow(tr("Peptide Type: "), peptidetype); + + peaklistline = new QLineEdit(); + peaklistline->setToolTip("Select the peaklist. Following formats are supported: txt, mgf, mzML, mzXML, baf."); + peaklistbutton = new QPushButton("Select"); + peaklistbutton->setToolTip("Select the peaklist. Following formats are supported: txt, mgf, mzML, mzXML, baf."); + peaklistlayout = new QHBoxLayout(); + peaklistlayout->addWidget(peaklistline); + peaklistlayout->addWidget(peaklistbutton); + peaklistformlayout->addRow(tr("Peaklist File: "), peaklistlayout); + + precursormass = new QDoubleSpinBox(); + precursormass->setToolTip("Enter the precursor mass-to-charge (m/z) ratio (a precursor m/z ratio in the peaklist file is ignored). The value will be automatically decharged."); + precursormass->setDecimals(6); + precursormass->setRange(0, 100000); + precursormass->setSingleStep(1); + peaklistformlayout->addRow(tr("Precursor m/z Ratio: "), precursormass); + + precursorcharge = new QSpinBox(); + precursorcharge->setToolTip("Enter the precursor charge (a precursor charge in the peaklist file is ignored)."); + precursorcharge->setRange(1, 100); + precursorcharge->setSingleStep(1); + peaklistformlayout->addRow(tr("Precursor Charge: "), precursorcharge); + + precursormasserrortolerance = new QDoubleSpinBox(); + precursormasserrortolerance->setToolTip("Enter the precursor m/z error tolerance in ppm."); + precursormasserrortolerance->setDecimals(3); + precursormasserrortolerance->setRange(0, 10000); + precursormasserrortolerance->setSingleStep(1); + precursormasserrortolerance->setSuffix(" ppm"); + peaklistformlayout->addRow(tr("Precursor m/z Error Tolerance: "), precursormasserrortolerance); + + fragmentmasserrortolerance = new QDoubleSpinBox(); + fragmentmasserrortolerance->setToolTip("Enter the fragment m/z error tolerance in ppm."); + fragmentmasserrortolerance->setDecimals(3); + fragmentmasserrortolerance->setRange(0, 10000); + fragmentmasserrortolerance->setSingleStep(1); + fragmentmasserrortolerance->setSuffix(" ppm"); + peaklistformlayout->addRow(tr("Fragment m/z Error Tolerance: "), fragmentmasserrortolerance); + + masserrortolerancefordeisotoping = new QDoubleSpinBox(); + masserrortolerancefordeisotoping->setToolTip("Enter the fragment m/z error tolerance for deisotoping in ppm (the same value like \"Fragment m/z Error Tolerance\" is recommended by default; 0 = the deisotoping is disabled)."); + masserrortolerancefordeisotoping->setDecimals(3); + masserrortolerancefordeisotoping->setRange(0, 10000); + masserrortolerancefordeisotoping->setSingleStep(1); + masserrortolerancefordeisotoping->setSuffix(" ppm"); + peaklistformlayout->addRow(tr("Fragment m/z Error Tolerance for Deisotoping: "), masserrortolerancefordeisotoping); + + minimumrelativeintensitythreshold = new QDoubleSpinBox(); + minimumrelativeintensitythreshold->setToolTip("Enter the threshold of relative intensity in %. Peaks having relative intensities below the threshold will be removed from the peaklist."); + minimumrelativeintensitythreshold->setDecimals(3); + minimumrelativeintensitythreshold->setRange(0, 100); + minimumrelativeintensitythreshold->setSingleStep(1); + peaklistformlayout->addRow(tr("Minimum Threshold of Relative Intensity: "), minimumrelativeintensitythreshold); + + minimummz = new QDoubleSpinBox(); + minimummz->setToolTip("Enter the minimum m/z ratio. Peaks having m/z ratios below the threshold will be removed from the peaklist."); + minimummz->setDecimals(3); + minimummz->setRange(0, 10000); + minimummz->setSingleStep(1); + peaklistformlayout->addRow(tr("Minimum m/z Ratio: "), minimummz); + + peaklistgroupbox = new QGroupBox("Peaklist"); + peaklistgroupbox->setLayout(peaklistformlayout); + + + brickdatabaseformlayout = new QFormLayout(); + + brickdatabaseline = new QLineEdit(); + brickdatabaseline->setToolTip("Select the txt file containing a list of building blocks."); + brickdatabasebutton = new QPushButton("Select"); + brickdatabasebutton->setToolTip("Select the txt file containing a list of building blocks."); + brickdatabaselayout = new QHBoxLayout(); + brickdatabaselayout->addWidget(brickdatabaseline); + brickdatabaselayout->addWidget(brickdatabasebutton); + brickdatabaseformlayout->addRow(tr("Building Blocks Database File: "), brickdatabaselayout); + + maximumbricksincombinationbegin = new QSpinBox(); + maximumbricksincombinationbegin->setToolTip("Maximum number of combined building blocks to skip a gap leading from a start point in a de novo graph. A small value speeds up the search and vice versa."); + maximumbricksincombinationbegin->setRange(1, 20); + maximumbricksincombinationbegin->setSingleStep(1); + brickdatabaseformlayout->addRow(tr("Maximum Number of Combined Blocks (start): "), maximumbricksincombinationbegin); + + maximumbricksincombinationmiddle = new QSpinBox(); + maximumbricksincombinationmiddle->setToolTip("Maximum number of combined building blocks to skip a gap in a de novo graph (except gaps leading from a start point or to an end point). A small value speeds up the search and vice versa."); + maximumbricksincombinationmiddle->setRange(1, 20); + maximumbricksincombinationmiddle->setSingleStep(1); + brickdatabaseformlayout->addRow(tr("Maximum Number of Combined Blocks (middle): "), maximumbricksincombinationmiddle); + + maximumbricksincombinationend = new QSpinBox(); + maximumbricksincombinationend->setToolTip("Maximum number of combined building blocks to skip a gap leading to an end point in a de novo graph. A small value speeds up the search and vice versa."); + maximumbricksincombinationend->setRange(1, 20); + maximumbricksincombinationend->setSingleStep(1); + brickdatabaseformlayout->addRow(tr("Maximum Number of Combined Blocks (end): "), maximumbricksincombinationend); + + maximumcumulativemass = new QDoubleSpinBox(); + maximumcumulativemass->setToolTip("Enter the maximum cumulative mass of combined blocks (0 = the maximum mass is unlimited). A small value speeds up the search and vice versa."); + maximumcumulativemass->setDecimals(3); + maximumcumulativemass->setRange(0, 10000); + maximumcumulativemass->setSingleStep(1); + brickdatabaseformlayout->addRow(tr("Maximum Cumulative Mass of Blocks: "), maximumcumulativemass); + + generatebrickspermutations = new QCheckBox(); + generatebrickspermutations->setToolTip("Permutations of combined blocks are generated when checked (e.g., when an edge corresponds to a combination of blocks leucine, proline and valine, the order of blocks can be LPV, LVP, PVL, PLV, VLP or VPL).\nIt is recommended to enable this option by default."); + brickdatabaseformlayout->addRow(tr("Generate Permutations of Combined Blocks: "), generatebrickspermutations); + + brickdatabasegroupbox = new QGroupBox("Database of Building Blocks"); + brickdatabasegroupbox->setLayout(brickdatabaseformlayout); + + + modificationslayout = new QVBoxLayout(); + + modificationstable = new QTableWidget(); + modificationstable->setColumnCount(4); + modificationstable->setHorizontalHeaderItem(0, new QTableWidgetItem("Name")); + modificationstable->horizontalHeaderItem(0)->setToolTip("A name of a modification."); + modificationstable->setHorizontalHeaderItem(1, new QTableWidgetItem("Summary")); + modificationstable->horizontalHeaderItem(1)->setToolTip("A residue summary formula of a modification (e.g., H2C2O for acetylation or HNO-1 for amidation). Negative numbers of atoms are supported (e.g., H-2O3N-5 means remove two hydrogens, add three oxygens and remove five nitrogens)."); + modificationstable->setHorizontalHeaderItem(2, new QTableWidgetItem("N-terminal")); + modificationstable->horizontalHeaderItem(2)->setToolTip("When checked, the modification is considered to be N-terminal."); + modificationstable->setHorizontalHeaderItem(3, new QTableWidgetItem("C-terminal")); + modificationstable->horizontalHeaderItem(3)->setToolTip("When checked, the modification is considered to be C-terminal."); + modificationstable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + //modificationstable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Interactive); + + modificationsbuttoninsert = new QPushButton("Insert Modification"); + modificationsbuttoninsert->setToolTip("Insert a new row for a modification."); + modificationsbuttoninsert->setMinimumWidth(120); + modificationsbuttoninsert->setMaximumWidth(120); + modificationsbuttonremove = new QPushButton("Remove Empty Rows"); + modificationsbuttonremove->setToolTip("Remove rows having empty column \"Name\"."); + modificationsbuttonremove->setMinimumWidth(120); + modificationsbuttonremove->setMaximumWidth(120); + modificationsbuttonslayout = new QHBoxLayout(); + modificationsbuttonslayout->addWidget(modificationsbuttoninsert); + modificationsbuttonslayout->addWidget(modificationsbuttonremove); + modificationsbuttonslayout->addStretch(1); + modificationslayout->addWidget(modificationstable); + modificationslayout->addLayout(modificationsbuttonslayout); + + modificationsgroupbox = new QGroupBox("N-terminal and C-terminal Modifications"); + modificationsgroupbox->setLayout(modificationslayout); + + + 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->addItem(tr("De Novo Search Engine")); + mode->addItem(tr("Compare Spectrum of Searched Sequence with Peaklist")); + applicationformlayout->addRow(tr("Mode: "), mode); + + maximumnumberofthreads = new QSpinBox(); + maximumnumberofthreads->setToolTip("A maximum number of threads used when the peaklist is compared with theoretical spectra of peptide sequence candidates."); + maximumnumberofthreads->setRange(1, 1024); + maximumnumberofthreads->setSingleStep(1); + applicationformlayout->addRow(tr("Maximum Number of Threads: "), maximumnumberofthreads); + + 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 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")); + scoretype->addItem(tr("Number of matched peaks")); + scoretype->addItem(tr("Number of matched bricks (cyclic peptides)")); + applicationformlayout->addRow(tr("Score Type: "), scoretype); + + hitsreported = new QSpinBox(); + hitsreported->setToolTip("A maximum length of an output report with peptide sequence candidates. A great value may slow down the search and a lot of main memory may be spent."); + hitsreported->setRange(1, 100000); + hitsreported->setSingleStep(1); + applicationformlayout->addRow(tr("Maximum Number of Candidate Peptides Reported: "), hitsreported); + + sequencetag = new QLineEdit(); + sequencetag->setToolTip("Each peptide sequence candidate generated from a de novo graph must fulfil the peptide sequence tag. Otherwise, its theoretical spectrum is not generated and the peptide sequence candidate is excluded from the search.\nSee the syntax of tags in the documentation."); + sequencetag->setMaxLength(1024*1024); + applicationformlayout->addRow(tr("Peptide Sequence Tag: "), sequencetag); + + fragmentiontypes = new cFragmentIonsListWidget(this); + fragmentiontypes->setToolTip("Select fragment ion types which will be generated in theoretical spectra of peptide sequence candidates."); + 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)."); + applicationformlayout->addRow(tr("Remove Hits of Fragments without Hits of Parent Fragments: "), clearhitswithoutparent); + + cyclicnterminus = new QCheckBox(); + cyclicnterminus->setToolTip("N-terminal cyclization of a linear peptide is assumed when checked. H2O is subtracted from all theoretical N-terminal fragment ions and the theoretical precursor mass."); + applicationformlayout->addRow(tr("Cyclic N-terminus: "), cyclicnterminus); + + cycliccterminus = new QCheckBox(); + cycliccterminus->setToolTip("C-terminal cyclization of a linear peptide is assumed when checked. H2O is subtracted from all theoretical C-terminal fragment ions and the theoretical precursor mass."); + applicationformlayout->addRow(tr("Cyclic C-terminus: "), cycliccterminus); + + enablescrambling = new QCheckBox(); + enablescrambling->setToolTip("When checked, scrambled fragment ions of cyclic peptides are generated in theoretical spectra."); + applicationformlayout->addRow(tr("Enable Scrambling: "), enablescrambling); + + applicationgroupbox = new QGroupBox("Application"); + applicationgroupbox->setLayout(applicationformlayout); + + + denovographformlayout = new QFormLayout(); + + blindedges = new QComboBox(); + blindedges->setToolTip("An operation with edges in the de novo graph forming exclusively blind paths:\nnone (edges are kept - useful when you would like to see the whole de novo graph in 'View -> Graph');\nremove (edges are removed - speeds up the search);\nconnect (edges are connected - useful when you are looking for sequence tags)."); + blindedges->addItem(tr("none (you can see a complete de novo graph)")); + blindedges->addItem(tr("remove (speed up the search)")); + blindedges->addItem(tr("connect (allow detection of sequence tags)")); + denovographformlayout->addRow(tr("Action with Edges Forming Blind Paths: "), blindedges); + + denovographgroupbox = new QGroupBox("De Novo Graph"); + denovographgroupbox->setLayout(denovographformlayout); + + + 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->setMaxLength(1024*1024); + searchedsequenceformlayout->addRow(tr("Sequence: "), searchedsequence); + + searchedsequenceNtermmodif = new QLineEdit(); + searchedsequenceNtermmodif->setToolTip("A name of an N-terminal modification as defined in the window \"N-terminal and C-terminal Modifications\" which belongs to the searched peptide."); + searchedsequenceformlayout->addRow(tr("N-terminal Modification: "), searchedsequenceNtermmodif); + + searchedsequenceCtermmodif = new QLineEdit(); + searchedsequenceCtermmodif->setToolTip("A name of a C-terminal modification as defined in the window \"N-terminal and C-terminal Modifications\" which belongs to the searched peptide."); + searchedsequenceformlayout->addRow(tr("C-terminal Modification: "), searchedsequenceCtermmodif); + + searchedsequenceTmodif = new QLineEdit(); + searchedsequenceTmodif->setToolTip("A name of an N-terminal or C-terminal modification as defined in the window \"N-terminal and C-terminal Modifications\" which belongs to a branch of a searched peptide (branched and lasso peptides only)."); + searchedsequenceformlayout->addRow(tr("T-Modification: "), searchedsequenceTmodif); + + searchedsequencegroupbox = new QGroupBox("Searched Peptide Sequence"); + searchedsequencegroupbox->setLayout(searchedsequenceformlayout); + + + vlayout1 = new QVBoxLayout(); + vlayout1->addWidget(peaklistgroupbox); + vlayout1->addWidget(brickdatabasegroupbox); + vlayout1->addWidget(modificationsgroupbox); + + vlayout2 = new QVBoxLayout(); + vlayout2->addWidget(applicationgroupbox); + vlayout2->addWidget(denovographgroupbox); + vlayout2->addWidget(searchedsequencegroupbox); + vlayout2->addStretch(1); + + + hlayout = new QHBoxLayout(); + hlayout->addLayout(vlayout1); + hlayout->addLayout(vlayout2); + + + vlayout = new QVBoxLayout(); + vlayout->addLayout(hlayout); + vlayout->addStretch(1); + vlayout->addLayout(buttons); + + setLayout(vlayout); + + resize(1280, 700); + + connect(load, SIGNAL(released()), this, SLOT(loadSettings())); + connect(save, SIGNAL(released()), this, SLOT(saveSettings())); + connect(saveas, SIGNAL(released()), this, SLOT(saveSettingsAs())); + connect(stdbuttons, SIGNAL(accepted()), this, SLOT(updateParametersAndHide())); + connect(stdbuttons->button(QDialogButtonBox::Apply), SIGNAL(released()), this, SLOT(updateParameters())); + connect(stdbuttons, SIGNAL(rejected()), this, SLOT(restoreParameters())); + connect(peaklistbutton, SIGNAL(released()), this, SLOT(peaklistButtonReleased())); + connect(brickdatabasebutton, SIGNAL(released()), this, SLOT(brickDatabaseButtonReleased())); + connect(modificationsbuttoninsert, SIGNAL(released()), this, SLOT(modificationsInsertButtonReleased())); + connect(modificationsbuttonremove, SIGNAL(released()), this, SLOT(modificationsRemoveButtonReleased())); + 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())); + + + updateSettingsWhenPeptideTypeChanged(peptidetype->currentIndex()); + updateSettingsWhenModeChanged(mode->currentIndex()); + + restoreParameters(); + + + lastdirloadsettings = "./Settings/"; + lastdirsavesettings = "./Settings/"; + lastdirselectpeaklist = "./PeakLists/"; + lastdirselectbricksdatabase = "./BrickDatabases/"; +} + + +cParametersWidget::~cParametersWidget() { + + delete stdbuttons; + delete load; + delete save; + delete saveas; + delete buttons; + + delete peptidetype; + delete peaklistline; + delete peaklistbutton; + delete peaklistlayout; + delete precursormass; + delete precursorcharge; + delete precursormasserrortolerance; + delete fragmentmasserrortolerance; + delete masserrortolerancefordeisotoping; + delete minimumrelativeintensitythreshold; + delete minimummz; + delete peaklistformlayout; + delete peaklistgroupbox; + + delete brickdatabaseline; + delete brickdatabasebutton; + delete brickdatabaselayout; + delete maximumbricksincombinationbegin; + delete maximumbricksincombinationmiddle; + delete maximumbricksincombinationend; + delete maximumcumulativemass; + delete generatebrickspermutations; + delete brickdatabaseformlayout; + delete brickdatabasegroupbox; + + deleteModificationsTableBody(); + + for (int i = 0; i < modificationstable->columnCount(); i++) { + delete modificationstable->horizontalHeaderItem(i); + } + + delete modificationsbuttoninsert; + delete modificationsbuttonremove; + delete modificationsbuttonslayout; + delete modificationstable; + delete modificationslayout; + delete modificationsgroupbox; + + delete mode; + delete maximumnumberofthreads; + delete scoretype; + delete hitsreported; + delete sequencetag; + delete fragmentiontypes; + delete clearhitswithoutparent; + delete cyclicnterminus; + delete cycliccterminus; + delete enablescrambling; + delete applicationformlayout; + delete applicationgroupbox; + + delete blindedges; + delete denovographformlayout; + delete denovographgroupbox; + + delete searchedsequence; + delete searchedsequenceNtermmodif; + delete searchedsequenceCtermmodif; + delete searchedsequenceTmodif; + delete searchedsequenceformlayout; + delete searchedsequencegroupbox; + + delete vlayout1; + delete vlayout2; + delete hlayout; + delete vlayout; +} + + +cParameters& cParametersWidget::getParameters() { + return parameters; +} + + +void cParametersWidget::setAndRestoreParameters(cParameters& parameters) { + settingsfile = ""; + oldsettingsfile = ""; + + this->parameters = parameters; + this->parameters.bricksdatabase.clear(); + this->parameters.peaklist.clear(); + this->parameters.fragmentionsfordenovograph.clear(); + this->parameters.sequencetag = this->parameters.originalsequencetag; + this->parameters.searchedsequence = this->parameters.originalsearchedsequence; + + restoreParameters(); +} + + +void cParametersWidget::closeEvent(QCloseEvent *event) { + restoreParameters(); +} + + +void cParametersWidget::deleteRow(int number) { + for (int i = 0; i < modificationstable->columnCount(); i++) { + if ((i == 0) || (i == 1)) { + delete modificationstable->item(number, i); + } + else { + delete modificationstable->cellWidget(number, i); + } + } + modificationstable->removeRow(number); +} + + +void cParametersWidget::deleteModificationsTableBody() { + while (modificationstable->rowCount() > 0) { + deleteRow(modificationstable->rowCount() - 1); + } +} + + +void cParametersWidget::modificationsTableInsertRow() { + int row = modificationstable->rowCount(); + + modificationstable->insertRow(row); + + modificationstable->setItem(row, 0, new QTableWidgetItem()); + modificationstable->item(row, 0)->setData(Qt::DisplayRole, ""); + + modificationstable->setItem(row, 1, new QTableWidgetItem()); + modificationstable->item(row, 1)->setData(Qt::DisplayRole, ""); + + modificationstable->setCellWidget(row, 2, new QCheckBox()); + + modificationstable->setCellWidget(row, 3, new QCheckBox()); +} + + +void cParametersWidget::modificationsTableRemoveEmptyRows() { + int i = 0; + while (i < modificationstable->rowCount()) { + if (modificationstable->item(i, 0)->text().toStdString().compare("") == 0) { + deleteRow(i); + } + else { + i++; + } + } +} + + +void cParametersWidget::loadSettings() { + QString filename = QFileDialog::getOpenFileName(this, tr("Load Settings"), lastdirloadsettings, tr("Settings Files (*.ini)")); + lastdirloadsettings = filename; + + if (filename.toStdString().compare("") != 0) { + int loadedrows = 0; + QString qloadstring; + QCheckBox* tmpcheckbox; + + settingsfile = filename; + save->setText(QString(" Save '") + QString(settingsfile.toStdString().substr(settingsfile.toStdString().rfind('/') + 1, settingsfile.toStdString().size()).c_str()) + QString("' ")); + QSettings settings(settingsfile, QSettings::IniFormat); + + peptidetype->setCurrentIndex(settings.value("peptidetype", 0).toInt()); + peaklistline->setText(settings.value("peaklist", "").toString()); + precursormass->setValue(settings.value("precursormass", 0.0).toDouble()); + precursormasserrortolerance->setValue(settings.value("precursormasserrortolerance", 5.0).toDouble()); + precursorcharge->setValue(settings.value("precursorcharge", 1).toInt()); + fragmentmasserrortolerance->setValue(settings.value("fragmentmasserrortolerance", 5.0).toDouble()); + masserrortolerancefordeisotoping->setValue(settings.value("masserrortolerancefordeisotoping", 5.0).toDouble()); + minimumrelativeintensitythreshold->setValue(settings.value("minimumrelativeintensitythreshold", 0).toDouble()); + minimummz->setValue(settings.value("minimummz", 150).toDouble()); + + brickdatabaseline->setText(settings.value("brickdatabase", "").toString()); + maximumbricksincombinationbegin->setValue(settings.value("maximumbricksincombinationbegin", 3).toInt()); + maximumbricksincombinationmiddle->setValue(settings.value("maximumbricksincombinationmiddle", 2).toInt()); + maximumbricksincombinationend->setValue(settings.value("maximumbricksincombinationend", 3).toInt()); + maximumcumulativemass->setValue(settings.value("maximumcumulativemass", 0).toDouble()); + settings.value("generatebrickspermutations", 1).toInt() == 0 ? generatebrickspermutations->setChecked(false) : generatebrickspermutations->setChecked(true); + + deleteModificationsTableBody(); + + qloadstring = ("modification_" + to_string(loadedrows) + "_0").c_str(); + while (settings.value(qloadstring, "").toString().toStdString().compare("") != 0) { + modificationsTableInsertRow(); + + modificationstable->item(loadedrows, 0)->setText(settings.value(qloadstring, "").toString()); + + qloadstring = ("modification_" + to_string(loadedrows) + "_1").c_str(); + modificationstable->item(loadedrows, 1)->setText(settings.value(qloadstring, "").toString()); + + tmpcheckbox = (QCheckBox *)(modificationstable->cellWidget(loadedrows, 2)); + qloadstring = ("modification_" + to_string(loadedrows) + "_2").c_str(); + settings.value(qloadstring, 0).toInt() == 0 ? tmpcheckbox->setChecked(false) : tmpcheckbox->setChecked(true); + + tmpcheckbox = (QCheckBox *)(modificationstable->cellWidget(loadedrows, 3)); + qloadstring = ("modification_" + to_string(loadedrows) + "_3").c_str(); + settings.value(qloadstring, 0).toInt() == 0 ? tmpcheckbox->setChecked(false) : tmpcheckbox->setChecked(true); + + loadedrows++; + qloadstring = ("modification_" + to_string(loadedrows) + "_0").c_str(); + } + + mode->setCurrentIndex(settings.value("mode", 0).toInt()); + maximumnumberofthreads->setValue(settings.value("maximumnumberofthreads", 1).toInt()); + scoretype->setCurrentIndex(settings.value("scoretype", 0).toInt()); + hitsreported->setValue(settings.value("hitsreported", 1000).toInt()); + sequencetag->setText(settings.value("sequencetag", "").toString()); + + for (int i = 0; i < fragmentiontypes->getList()->count(); i++) { + qloadstring = ("fragmentiontype_" + to_string(i)).c_str(); + settings.value(qloadstring, 0).toInt() == 0 ? fragmentiontypes->getList()->item(i)->setSelected(false) : fragmentiontypes->getList()->item(i)->setSelected(true); + } + + settings.value("clearhitswithoutparent", 0).toInt() == 0 ? clearhitswithoutparent->setChecked(false) : clearhitswithoutparent->setChecked(true); + settings.value("cyclicnterminus", 0).toInt() == 0 ? cyclicnterminus->setChecked(false) : cyclicnterminus->setChecked(true); + settings.value("cycliccterminus", 0).toInt() == 0 ? cycliccterminus->setChecked(false) : cycliccterminus->setChecked(true); + settings.value("enablescrambling", 0).toInt() == 0 ? enablescrambling->setChecked(false) : enablescrambling->setChecked(true); + + blindedges->setCurrentIndex(settings.value("blindedges", 2).toInt()); + + searchedsequence->setText(settings.value("searchedsequence", "").toString()); + searchedsequenceNtermmodif->setText(settings.value("searchedsequenceNtermmodif", "").toString()); + searchedsequenceCtermmodif->setText(settings.value("searchedsequenceCtermmodif", "").toString()); + searchedsequenceTmodif->setText(settings.value("searchedsequenceTmodif", "").toString()); + + } + +} + + +void cParametersWidget::saveSettings() { + + if (settingsfile.compare("") == 0) { + saveSettingsAs(); + return; + } + + int savedrows = 0; + QString qsavestring; + QCheckBox* tmpcheckbox; + + QSettings settings(settingsfile, QSettings::IniFormat); + settings.clear(); + + settings.setValue("peptidetype", peptidetype->currentIndex()); + settings.setValue("peaklist", peaklistline->text()); + settings.setValue("precursormass", precursormass->value()); + settings.setValue("precursormasserrortolerance", precursormasserrortolerance->value()); + settings.setValue("precursorcharge", precursorcharge->value()); + settings.setValue("fragmentmasserrortolerance", fragmentmasserrortolerance->value()); + settings.setValue("masserrortolerancefordeisotoping", masserrortolerancefordeisotoping->value()); + settings.setValue("minimumrelativeintensitythreshold", minimumrelativeintensitythreshold->value()); + settings.setValue("minimummz", minimummz->value()); + + settings.setValue("brickdatabase", brickdatabaseline->text()); + settings.setValue("maximumbricksincombinationbegin", maximumbricksincombinationbegin->value()); + settings.setValue("maximumbricksincombinationmiddle", maximumbricksincombinationmiddle->value()); + settings.setValue("maximumbricksincombinationend", maximumbricksincombinationend->value()); + settings.setValue("maximumcumulativemass", maximumcumulativemass->value()); + generatebrickspermutations->isChecked() ? settings.setValue("generatebrickspermutations", 1) : settings.setValue("generatebrickspermutations", 0); + + modificationsTableRemoveEmptyRows(); + + for (int i = 0; i < modificationstable->rowCount(); i++) { + qsavestring = ("modification_" + to_string(savedrows) + "_0").c_str(); + settings.setValue(qsavestring, modificationstable->item(i, 0)->text()); + + qsavestring = ("modification_" + to_string(savedrows) + "_1").c_str(); + settings.setValue(qsavestring, modificationstable->item(i, 1)->text()); + + qsavestring = ("modification_" + to_string(savedrows) + "_2").c_str(); + tmpcheckbox = (QCheckBox *)(modificationstable->cellWidget(i, 2)); + tmpcheckbox->isChecked() ? settings.setValue(qsavestring, 1) : settings.setValue(qsavestring, 0); + + qsavestring = ("modification_" + to_string(savedrows) + "_3").c_str(); + tmpcheckbox = (QCheckBox *)(modificationstable->cellWidget(i, 3)); + tmpcheckbox->isChecked() ? settings.setValue(qsavestring, 1) : settings.setValue(qsavestring, 0); + + savedrows++; + } + + settings.setValue("mode", mode->currentIndex()); + settings.setValue("maximumnumberofthreads", maximumnumberofthreads->value()); + settings.setValue("scoretype", scoretype->currentIndex()); + settings.setValue("hitsreported", hitsreported->value()); + settings.setValue("sequencetag", sequencetag->text()); + + for (int i = 0; i < fragmentiontypes->getList()->count(); i++) { + qsavestring = ("fragmentiontype_" + to_string(i)).c_str(); + fragmentiontypes->getList()->item(i)->isSelected() ? settings.setValue(qsavestring, 1) : settings.setValue(qsavestring, 0); + } + + clearhitswithoutparent->isChecked() ? settings.setValue("clearhitswithoutparent", 1) : settings.setValue("clearhitswithoutparent", 0); + cyclicnterminus->isChecked() ? settings.setValue("cyclicnterminus", 1) : settings.setValue("cyclicnterminus", 0); + cycliccterminus->isChecked() ? settings.setValue("cycliccterminus", 1) : settings.setValue("cycliccterminus", 0); + enablescrambling->isChecked() ? settings.setValue("enablescrambling", 1) : settings.setValue("enablescrambling", 0); + + settings.setValue("blindedges", blindedges->currentIndex()); + + settings.setValue("searchedsequence", searchedsequence->text()); + settings.setValue("searchedsequenceNtermmodif", searchedsequenceNtermmodif->text()); + settings.setValue("searchedsequenceCtermmodif", searchedsequenceCtermmodif->text()); + settings.setValue("searchedsequenceTmodif", searchedsequenceTmodif->text()); + +} + + +void cParametersWidget::saveSettingsAs() { + QString filename = QFileDialog::getSaveFileName(this, tr("Save Settings As..."), lastdirsavesettings, tr("Files (*.ini)")); + lastdirsavesettings = filename; + + if (filename.toStdString().compare("") != 0) { + settingsfile = filename; + save->setText(QString(" Save '") + QString(settingsfile.toStdString().substr(settingsfile.toStdString().rfind('/') + 1, settingsfile.toStdString().size()).c_str()) + QString("' ")); + saveSettings(); + } +} + + +void cParametersWidget::peaklistButtonReleased() { + QString filename = QFileDialog::getOpenFileName(this, tr("Select Peaklist..."), lastdirselectpeaklist, tr("Peak Lists (*.txt *.mgf *.mzML *.mzXML *.baf)")); + lastdirselectpeaklist = filename; + + if (filename.toStdString().compare("") != 0) { + peaklistfilename = filename.toStdString(); + peaklistline->setText(filename); + } +} + + +void cParametersWidget::brickDatabaseButtonReleased() { + QString filename = QFileDialog::getOpenFileName(this, tr("Select Brick Database..."), lastdirselectbricksdatabase, tr("Text Files (*.txt)")); + lastdirselectbricksdatabase = filename; + + if (filename.toStdString().compare("") != 0) { + brickdatabasefilename = filename.toStdString(); + brickdatabaseline->setText(filename); + } +} + + +void cParametersWidget::modificationsInsertButtonReleased() { + modificationsTableInsertRow(); +} + + +void cParametersWidget::modificationsRemoveButtonReleased() { + modificationsTableRemoveEmptyRows(); +} + + +void cParametersWidget::updateParameters() { + parameters.peptidetype = (peptideType)peptidetype->currentIndex(); + parameters.peaklistfilename = peaklistline->text().toStdString(); + parameters.precursormass = precursormass->value(); + parameters.precursormasserrortolerance = precursormasserrortolerance->value(); + parameters.precursorcharge = precursorcharge->value(); + parameters.fragmentmasserrortolerance = fragmentmasserrortolerance->value(); + parameters.masserrortolerancefordeisotoping = masserrortolerancefordeisotoping->value(); + parameters.minimumrelativeintensitythreshold = minimumrelativeintensitythreshold->value(); + parameters.minimummz = minimummz->value(); + + parameters.bricksdatabasefilename = brickdatabaseline->text().toStdString(); + parameters.maximumbricksincombinationbegin = maximumbricksincombinationbegin->value(); + parameters.maximumbricksincombinationmiddle = maximumbricksincombinationmiddle->value(); + parameters.maximumbricksincombinationend = maximumbricksincombinationend->value(); + parameters.maximumcumulativemass = maximumcumulativemass->value(); + parameters.maximumbricksincombination = max(max(parameters.maximumbricksincombinationbegin, parameters.maximumbricksincombinationmiddle), parameters.maximumbricksincombinationend); + parameters.generatebrickspermutations = generatebrickspermutations->isChecked(); + + QCheckBox* tmpcheckbox1; + QCheckBox* tmpcheckbox2; + + parameters.searchedmodifications.clear(); + parameters.searchedmodifications.push_back(fragmentDescription("", 0, "", true, true)); + + modificationsTableRemoveEmptyRows(); + + int i = 0; + while (i < modificationstable->rowCount()) { + tmpcheckbox1 = (QCheckBox *)(modificationstable->cellWidget(i, 2)); + tmpcheckbox2 = (QCheckBox *)(modificationstable->cellWidget(i, 3)); + + parameters.searchedmodifications.push_back(fragmentDescription(modificationstable->item(i, 0)->text().toStdString(), 0, modificationstable->item(i, 1)->text().toStdString(), tmpcheckbox1->isChecked(), tmpcheckbox2->isChecked())); + + i++; + } + + parameters.mode = mode->currentIndex(); + parameters.maximumnumberofthreads = maximumnumberofthreads->value(); + parameters.scoretype = (scoreType)scoretype->currentIndex(); + parameters.hitsreported = hitsreported->value(); + parameters.sequencetag = sequencetag->text().toStdString(); + parameters.originalsequencetag = parameters.sequencetag; + + 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; + } + + for (int i = 0; i < fragmentiontypes->getList()->count(); i++) { + if (fragmentiontypes->getList()->item(i)->isSelected()) { + parameters.fragmentionsfortheoreticalspectra.push_back((fragmentIonType)(i + start)); + } + } + + parameters.clearhitswithoutparent = clearhitswithoutparent->isChecked(); + parameters.cyclicnterminus = cyclicnterminus->isChecked(); + parameters.cycliccterminus = cycliccterminus->isChecked(); + parameters.updateFragmentDefinitions(); + + parameters.enablescrambling = enablescrambling->isChecked(); + + parameters.blindedges = blindedges->currentIndex(); + + parameters.searchedsequence = searchedsequence->text().toStdString(); + parameters.originalsearchedsequence = parameters.searchedsequence; + parameters.searchedsequenceNtermmodif = searchedsequenceNtermmodif->text().toStdString(); + parameters.searchedsequenceCtermmodif = searchedsequenceCtermmodif->text().toStdString(); + parameters.searchedsequenceTmodif = searchedsequenceTmodif->text().toStdString(); + + oldsettingsfile = settingsfile; +} + + +void cParametersWidget::updateParametersAndHide() { + updateParameters(); + hide(); +} + + +void cParametersWidget::restoreParameters() { + peptidetype->setCurrentIndex(parameters.peptidetype); + peaklistline->setText(parameters.peaklistfilename.c_str()); + precursormass->setValue(parameters.precursormass); + precursormasserrortolerance->setValue(parameters.precursormasserrortolerance); + precursorcharge->setValue(parameters.precursorcharge); + fragmentmasserrortolerance->setValue(parameters.fragmentmasserrortolerance); + masserrortolerancefordeisotoping->setValue(parameters.masserrortolerancefordeisotoping); + minimumrelativeintensitythreshold->setValue(parameters.minimumrelativeintensitythreshold); + minimummz->setValue(parameters.minimummz); + + brickdatabaseline->setText(parameters.bricksdatabasefilename.c_str()); + maximumbricksincombinationbegin->setValue(parameters.maximumbricksincombinationbegin); + maximumbricksincombinationmiddle->setValue(parameters.maximumbricksincombinationmiddle); + maximumbricksincombinationend->setValue(parameters.maximumbricksincombinationend); + maximumcumulativemass->setValue(parameters.maximumcumulativemass); + generatebrickspermutations->setChecked(parameters.generatebrickspermutations); + + QCheckBox* tmpcheckbox; + + deleteModificationsTableBody(); + + int i = 1; + while (i < (int)parameters.searchedmodifications.size()) { + modificationsTableInsertRow(); + + modificationstable->item(i - 1, 0)->setText(parameters.searchedmodifications[i].name.c_str()); + + modificationstable->item(i - 1, 1)->setText(parameters.searchedmodifications[i].summary.c_str()); + + tmpcheckbox = (QCheckBox *)(modificationstable->cellWidget(i - 1, 2)); + tmpcheckbox->setChecked(parameters.searchedmodifications[i].nterminal); + + tmpcheckbox = (QCheckBox *)(modificationstable->cellWidget(i - 1, 3)); + tmpcheckbox->setChecked(parameters.searchedmodifications[i].cterminal); + + i++; + } + + mode->setCurrentIndex(parameters.mode); + maximumnumberofthreads->setValue(parameters.maximumnumberofthreads); + scoretype->setCurrentIndex(parameters.scoretype); + hitsreported->setValue(parameters.hitsreported); + 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; + } + + for (int i = 0; i < (int)parameters.fragmentionsfortheoreticalspectra.size(); i++) { + fragmentiontypes->getList()->item(parameters.fragmentionsfortheoreticalspectra[i] - start)->setSelected(true); + } + + clearhitswithoutparent->setChecked(parameters.clearhitswithoutparent); + cyclicnterminus->setChecked(parameters.cyclicnterminus); + cycliccterminus->setChecked(parameters.cycliccterminus); + enablescrambling->setChecked(parameters.enablescrambling); + + blindedges->setCurrentIndex(parameters.blindedges); + + searchedsequence->setText(parameters.searchedsequence.c_str()); + searchedsequenceNtermmodif->setText(parameters.searchedsequenceNtermmodif.c_str()); + searchedsequenceCtermmodif->setText(parameters.searchedsequenceCtermmodif.c_str()); + searchedsequenceTmodif->setText(parameters.searchedsequenceTmodif.c_str()); + + settingsfile = oldsettingsfile; + if (settingsfile.toStdString().compare("") == 0) { + save->setText(QString("Save")); + } + else { + save->setText(QString(" Save '") + QString(settingsfile.toStdString().substr(settingsfile.toStdString().rfind('/') + 1, settingsfile.toStdString().size()).c_str()) + QString("' ")); + } + + hide(); +} + + +void cParametersWidget::updateSettingsWhenPeptideTypeChanged(int index) { + + resetFragmentIonTypes(); + + switch ((peptideType)index) + { + case linear: + modificationsgroupbox->setDisabled(false); + searchedsequenceNtermmodif->setDisabled(false); + searchedsequenceCtermmodif->setDisabled(false); + searchedsequenceTmodif->setDisabled(true); + cyclicnterminus->setDisabled(false); + cycliccterminus->setDisabled(false); + enablescrambling->setDisabled(true); + break; + case cyclic: + modificationsgroupbox->setDisabled(true); + searchedsequenceNtermmodif->setDisabled(true); + searchedsequenceCtermmodif->setDisabled(true); + searchedsequenceTmodif->setDisabled(true); + cyclicnterminus->setDisabled(true); + cycliccterminus->setDisabled(true); + enablescrambling->setDisabled(false); + break; + case branched: + modificationsgroupbox->setDisabled(false); + searchedsequenceNtermmodif->setDisabled(false); + searchedsequenceCtermmodif->setDisabled(false); + searchedsequenceTmodif->setDisabled(false); + cyclicnterminus->setDisabled(true); + cycliccterminus->setDisabled(true); + enablescrambling->setDisabled(true); + break; + case lasso: + modificationsgroupbox->setDisabled(false); + searchedsequenceNtermmodif->setDisabled(true); + searchedsequenceCtermmodif->setDisabled(true); + searchedsequenceTmodif->setDisabled(false); + cyclicnterminus->setDisabled(true); + cycliccterminus->setDisabled(true); + enablescrambling->setDisabled(true); + break; + case linearpolysaccharide: + modificationsgroupbox->setDisabled(false); + searchedsequenceNtermmodif->setDisabled(false); + searchedsequenceCtermmodif->setDisabled(false); + searchedsequenceTmodif->setDisabled(true); + cyclicnterminus->setDisabled(true); + cycliccterminus->setDisabled(true); + enablescrambling->setDisabled(true); + break; + default: + break; + } +} + + +void cParametersWidget::updateSettingsWhenModeChanged(int index) { + + switch (index) + { + case 0: + precursormass->setDisabled(false); + precursormasserrortolerance->setDisabled(false); + maximumbricksincombinationbegin->setDisabled(false); + maximumbricksincombinationmiddle->setDisabled(false); + maximumbricksincombinationend->setDisabled(false); + maximumcumulativemass->setDisabled(false); + generatebrickspermutations->setDisabled(false); + maximumnumberofthreads->setDisabled(false); + scoretype->setDisabled(false); + hitsreported->setDisabled(false); + sequencetag->setDisabled(false); + denovographgroupbox->setDisabled(false); + break; + case 1: + precursormass->setDisabled(true); + precursormasserrortolerance->setDisabled(true); + 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); + denovographgroupbox->setDisabled(true); + break; + default: + break; + } + +} + + +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; + } + + for (int i = start; i <= end; i++) { + fragmentiontypes->getList()->addItem(tr(parameters.fragmentdefinitions[(fragmentIonType)i].name.c_str())); + + if (parameters.fragmentdefinitions[(fragmentIonType)i].parent == (fragmentIonType)i) { + fragmentiontypes->getList()->item(i-start)->setSelected(true); + } + } + +} + diff --git a/CycloBranch/gui/cParametersWidget.h b/CycloBranch/gui/cParametersWidget.h new file mode 100644 index 0000000..4318ca3 --- /dev/null +++ b/CycloBranch/gui/cParametersWidget.h @@ -0,0 +1,203 @@ +/** + \file cParametersWidget.h + \brief The widget for editing parameters of the application opened using the command 'Search->Settings'. +*/ + + +#ifndef _CPARAMETERSWIDGET_H +#define _CPARAMETERSWIDGET_H + +#include +#include + +#include +#include +#include + +#include "core/cFragmentIons.h" +#include "core/cParameters.h" + +#include "gui/cFragmentIonsListWidget.h" + + +using namespace std; + + +// forward declarations +class QFormLayout; +class QTextEdit; +class QVBoxLayout; +class QHBoxLayout; +class QComboBox; +class QSpinBox; +class QDoubleSpinBox; +class QDialogButtonBox; +class QGroupBox; +class QCheckBox; +class QTableWidget; +class QListWidget; + + +/** + \brief The class representing a widget for editing parameters of the application. +*/ +class cParametersWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + */ + cParametersWidget(); + + + /** + \brief The destructor. + */ + ~cParametersWidget(); + + + /** + \brief Get parameters. + \retval cParameters reference to parameters + */ + cParameters& getParameters(); + + + /** + \brief Set and restore parameters. + \param parameters reference to parameters + */ + void setAndRestoreParameters(cParameters& parameters); + + + /** + \brief Handle the window close event. + \param event pointer to QCloseEvent + */ + void closeEvent(QCloseEvent *event); + + +private: + cParameters parameters; + + QVBoxLayout* vlayout1; + QVBoxLayout* vlayout2; + QVBoxLayout* vlayout; + QHBoxLayout* hlayout; + + QString settingsfile; + QString oldsettingsfile; + + QDialogButtonBox* stdbuttons; + QHBoxLayout* buttons; + QPushButton* load; + QPushButton* save; + QPushButton* saveas; + + QFormLayout* peaklistformlayout; + QGroupBox* peaklistgroupbox; + QComboBox* peptidetype; + QLineEdit* peaklistline; + QPushButton* peaklistbutton; + QHBoxLayout* peaklistlayout; + string peaklistfilename; + QDoubleSpinBox* precursormass; + QSpinBox* precursorcharge; + QDoubleSpinBox* precursormasserrortolerance; + QDoubleSpinBox* fragmentmasserrortolerance; + QDoubleSpinBox* masserrortolerancefordeisotoping; + QDoubleSpinBox* minimumrelativeintensitythreshold; + QDoubleSpinBox* minimummz; + + QFormLayout* brickdatabaseformlayout; + QGroupBox* brickdatabasegroupbox; + QLineEdit* brickdatabaseline; + QPushButton* brickdatabasebutton; + QHBoxLayout* brickdatabaselayout; + string brickdatabasefilename; + QSpinBox* maximumbricksincombinationbegin; + QSpinBox* maximumbricksincombinationmiddle; + QSpinBox* maximumbricksincombinationend; + QDoubleSpinBox* maximumcumulativemass; + QCheckBox* generatebrickspermutations; + + QGroupBox* modificationsgroupbox; + QVBoxLayout* modificationslayout; + QTableWidget* modificationstable; + QHBoxLayout* modificationsbuttonslayout; + QPushButton* modificationsbuttoninsert; + QPushButton* modificationsbuttonremove; + + QFormLayout* applicationformlayout; + QGroupBox* applicationgroupbox; + QComboBox* mode; + QSpinBox* maximumnumberofthreads; + QComboBox* scoretype; + QSpinBox* hitsreported; + QLineEdit* sequencetag; + cFragmentIonsListWidget* fragmentiontypes; + QCheckBox* clearhitswithoutparent; + QCheckBox* cyclicnterminus; + QCheckBox* cycliccterminus; + QCheckBox* enablescrambling; + + QGroupBox* denovographgroupbox; + QFormLayout* denovographformlayout; + QComboBox* blindedges; + + QGroupBox* searchedsequencegroupbox; + QFormLayout* searchedsequenceformlayout; + QLineEdit* searchedsequence; + QLineEdit* searchedsequenceNtermmodif; + QLineEdit* searchedsequenceCtermmodif; + QLineEdit* searchedsequenceTmodif; + + QString lastdirloadsettings; + QString lastdirsavesettings; + QString lastdirselectpeaklist; + QString lastdirselectbricksdatabase; + + void deleteRow(int number); + + void deleteModificationsTableBody(); + + void modificationsTableInsertRow(); + + void modificationsTableRemoveEmptyRows(); + + +private slots: + + void loadSettings(); + + void saveSettings(); + + void saveSettingsAs(); + + void peaklistButtonReleased(); + + void brickDatabaseButtonReleased(); + + void modificationsInsertButtonReleased(); + + void modificationsRemoveButtonReleased(); + + void updateParameters(); + + void updateParametersAndHide(); + + void restoreParameters(); + + void updateSettingsWhenPeptideTypeChanged(int index); + + void updateSettingsWhenModeChanged(int index); + + void resetFragmentIonTypes(); + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/gui/cSpectrumDetailWidget.cpp b/CycloBranch/gui/cSpectrumDetailWidget.cpp new file mode 100644 index 0000000..5b298d7 --- /dev/null +++ b/CycloBranch/gui/cSpectrumDetailWidget.cpp @@ -0,0 +1,380 @@ +#include "gui/cSpectrumDetailWidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +cSpectrumDetailWidget::cSpectrumDetailWidget() { + rotation = 0; + parameters = 0; + + preparedToShow = false; + theoreticalspectrum = new cTheoreticalSpectrum(); +} + + +cSpectrumDetailWidget::cSpectrumDetailWidget(const cSpectrumDetailWidget& sd) { + rotation = 0; + parameters = sd.parameters; + + preparedToShow = false; + theoreticalspectrum = new cTheoreticalSpectrum(); + + if (parameters && sd.theoreticalspectrum) { + initialize(parameters, *sd.theoreticalspectrum); + } + + if (parameters && sd.preparedToShow) { + prepareToShow(parameters->peptidetype); + } + + setWindowTitle(sd.windowTitle()); +} + + +void cSpectrumDetailWidget::initialize(cParameters* parameters, cTheoreticalSpectrum& theoreticalspectrum) { + this->parameters = parameters; + *this->theoreticalspectrum = theoreticalspectrum; +} + + +cTheoreticalSpectrum& cSpectrumDetailWidget::getTheoreticalSpectrum() { + return *theoreticalspectrum; +} + + +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) { + 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); + } + + return s; +} + + +cSpectrumDetailWidget::~cSpectrumDetailWidget() { + + delete theoreticalspectrum; + + if (preparedToShow) { + + delete graphicalspectrum; + delete graphicalspectrumscroll; + + delete textedit; + delete textbrowser; + + delete zoomin; + delete zoomout; + delete normalsize; + delete zoom; + + delete minmz; + delete maxmz; + delete setmzinterval; + delete resetmzinterval; + delete mzinterval; + + delete hideunmatched; + delete hidematched; + + if (rotation) { + delete rotation; + } + + delete formlayout; + delete formwidget; + + if (parameters) { + switch (parameters->peptidetype) + { + case linear: + delete linearwidget; + break; + case cyclic: + delete cyclicwidget; + break; + case branched: + delete branchedwidget; + break; + case lasso: + break; + case linearpolysaccharide: + break; + default: + break; + } + } + + delete vsplitter1; + delete vsplitter2; + + delete hsplitter; + + delete mainbox; + } +} + + +void cSpectrumDetailWidget::closeEvent(QCloseEvent *event) { + hide(); +} + + +void cSpectrumDetailWidget::prepareToShow(peptideType peptidetype) { + + if (!preparedToShow) { + + hsplitter = new QSplitter(); + hsplitter->setOrientation(Qt::Horizontal); + + vsplitter1 = new QSplitter(); + vsplitter1->setOrientation(Qt::Vertical); + + 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: + break; + case linearpolysaccharide: + break; + default: + break; + } + + graphicalspectrumscroll = new QScrollArea(); + graphicalspectrum = new cGraphicalSpectrumWidget(graphicalspectrumscroll); + graphicalspectrumscroll->setWidget(graphicalspectrum); + //graphicalspectrumscroll->setWidgetResizable(true); + + textedit = new QTextEdit(); + textedit->setReadOnly(true); + textedit->setFont(QFont("Courier", 9)); + textedit->setLineWrapMode(QTextEdit::NoWrap); + + textbrowser = new QTextBrowser(); + textbrowser->setReadOnly(true); + textbrowser->setFont(QFont("Courier", 9)); + textbrowser->setLineWrapMode(QTextEdit::NoWrap); + textbrowser->setAcceptRichText(true); + textbrowser->setOpenExternalLinks(true); + + zoomin = new QPushButton("In"); + zoomin->setMaximumWidth(50); + connect(zoomin, SIGNAL(released()), graphicalspectrum, SLOT(zoomIn())); + + zoomout = new QPushButton("Out"); + zoomout->setMaximumWidth(50); + connect(zoomout, SIGNAL(released()), graphicalspectrum, SLOT(zoomOut())); + + normalsize = new QPushButton("Reset"); + normalsize->setMaximumWidth(50); + connect(normalsize, SIGNAL(released()), graphicalspectrum, SLOT(normalSize())); + + zoom = new QHBoxLayout(); + zoom->addWidget(zoomin); + zoom->addWidget(zoomout); + zoom->addWidget(normalsize); + + minmz = new QDoubleSpinBox(); + minmz->setDecimals(6); + minmz->setRange(0, 100000); + minmz->setSingleStep(1); + + maxmz = new QDoubleSpinBox(); + maxmz->setDecimals(6); + maxmz->setRange(0, 100000); + maxmz->setSingleStep(1); + + setmzinterval = new QPushButton("Set"); + setmzinterval->setMaximumWidth(50); + connect(setmzinterval, SIGNAL(released()), this, SLOT(setMZInterval())); + connect(this, SIGNAL(emitMZInterval(double, double)), graphicalspectrum, SLOT(setMZInterval(double, double))); + + resetmzinterval = new QPushButton("Reset"); + resetmzinterval->setMaximumWidth(50); + connect(resetmzinterval, SIGNAL(released()), graphicalspectrum, SLOT(resetMZInterval())); + + mzinterval = new QHBoxLayout(); + mzinterval->addWidget(minmz); + mzinterval->addWidget(maxmz); + mzinterval->addWidget(setmzinterval); + mzinterval->addWidget(resetmzinterval); + connect(graphicalspectrum, SIGNAL(updateMZInterval(double, double)), this, SLOT(updateMZInterval(double, double))); + + hideunmatched = new QCheckBox(); + connect(hideunmatched, SIGNAL(stateChanged(int)), graphicalspectrum, SLOT(hideUnmatchedPeaks(int))); + + hidematched = new QCheckBox(); + connect(hidematched, SIGNAL(stateChanged(int)), graphicalspectrum, SLOT(hideMatchedPeaks(int))); + + formlayout = new QFormLayout(); + formlayout->addRow(tr("Zoom: "), zoom); + formlayout->addRow(tr("View m/z (from - to): "), mzinterval); + 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); + + rotation = new QComboBox(); + rotation->addItem(tr("all")); + + string s; + for (int i = 0; i < 2*r; i++) { + s = theoreticalspectrum->getVisualCoverage()[i*hint].name.substr(0, theoreticalspectrum->getVisualCoverage()[i*hint].name.rfind('_')); + /* + if (i < r) { + s += " >>>"; + } + else { + s += " <<<"; + } + */ + rotation->addItem(tr(s.c_str())); + } + + connect(rotation, SIGNAL(currentIndexChanged(int)), graphicalspectrum, SLOT(rotationChanged(int))); + connect(rotation, SIGNAL(currentIndexChanged(int)), cyclicwidget, SLOT(rotationChanged(int))); + formlayout->addRow(tr("Show matched series: "), rotation); + } + + formwidget = new QWidget(); + formwidget->setLayout(formlayout); + + vsplitter1->addWidget(graphicalspectrumscroll); + vsplitter1->addWidget(textbrowser); + 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: + 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 (theoreticalspectrum) { + + 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: + break; + case linearpolysaccharide: + break; + default: + break; + } + + graphicalspectrum->setTheoreticalSpectrum(theoreticalspectrum); + + textedit->setHtml(theoreticalspectrum->getCoverageBySeries().c_str()); + textbrowser->setHtml(getDetailsAsHTMLString().c_str()); + } + + preparedToShow = true; + } + +} + + +void cSpectrumDetailWidget::updateMZInterval(double minmz, double maxmz) { + this->minmz->setValue(minmz); + this->maxmz->setValue(maxmz); +} + + +void cSpectrumDetailWidget::setMZInterval() { + emit emitMZInterval(minmz->value(), maxmz->value()); +} + diff --git a/CycloBranch/gui/cSpectrumDetailWidget.h b/CycloBranch/gui/cSpectrumDetailWidget.h new file mode 100644 index 0000000..61349dd --- /dev/null +++ b/CycloBranch/gui/cSpectrumDetailWidget.h @@ -0,0 +1,151 @@ +/** + \file cSpectrumDetailWidget.h + \brief The widget for visualisation of a detail of a spectrum (opened after doubleclick on a row when results are reported). +*/ + + +#ifndef _CSPECTRUMDETAILWIDGET_H +#define _CSPECTRUMDETAILWIDGET_H + +#include +#include "core/cTheoreticalSpectrum.h" +#include "gui/cLinearWidget.h" +#include "gui/cCyclicWidget.h" +#include "gui/cBranchedWidget.h" +#include "gui/cGraphicalSpectrumWidget.h" + + +// forward declaration +class QTextEdit; +class QTextBrowser; +class QHBoxLayout; +class QVBoxLayout; +class QFormLayout; +class QScrollArea; +class QCheckBox; +class QPushButton; +class QSplitter; +class QComboBox; +class QDoubleSpinBox; + + +/** + \brief The class representing a widget for visualisation of a detail of a spectrum (opened after doubleclick on a row when results are reported). +*/ +class cSpectrumDetailWidget : public QWidget +{ + Q_OBJECT + +public: + + + /** + \brief The constructor. + */ + cSpectrumDetailWidget(); + + + /** + \brief The copy constructor. + \param sd reference to a cSpectrumDetailWidget + */ + cSpectrumDetailWidget(const cSpectrumDetailWidget& sd); + + + /** + \brief The destructor. + */ + ~cSpectrumDetailWidget(); + + + /** + \brief Handle the window close event. + \param event pointer to QCloseEvent + */ + void closeEvent(QCloseEvent *event); + + + /** + \brief Initialize the widget. + \param parameters a pointer to parameters + \param theoreticalspectrum a reference to a theoretical spectrum + */ + void initialize(cParameters* parameters, cTheoreticalSpectrum& theoreticalspectrum); + + + /** + \brief Get the theoretical spectrum. + \retval cTheoreticalSpectrum reference to a theoretical spectrum + */ + cTheoreticalSpectrum& getTheoreticalSpectrum(); + + + /** + \brief Get details about a theoretical spectrum as a HTML string. + \retval string details about a theoretical spectrum + */ + string getDetailsAsHTMLString(); + + + /** + \brief Prepare the widget to show. + \param peptidetype a type of peptide + */ + void prepareToShow(peptideType peptidetype); + + +private: + QHBoxLayout* zoom; + QHBoxLayout* mzinterval; + + QSplitter* hsplitter; + QSplitter* vsplitter1; + QSplitter* vsplitter2; + + QWidget* formwidget; + QFormLayout* formlayout; + QPushButton* zoomin; + QPushButton* zoomout; + QPushButton* normalsize; + QDoubleSpinBox* minmz; + QDoubleSpinBox* maxmz; + QPushButton* setmzinterval; + QPushButton* resetmzinterval; + QCheckBox* hideunmatched; + QCheckBox* hidematched; + QComboBox* rotation; + + QTextEdit* textedit; + QTextBrowser* textbrowser; + cLinearWidget* linearwidget; + cCyclicWidget* cyclicwidget; + cBranchedWidget* branchedwidget; + + QScrollArea* graphicalspectrumscroll; + cGraphicalSpectrumWidget* graphicalspectrum; + + cTheoreticalSpectrum* theoreticalspectrum; + + QHBoxLayout* mainbox; + + bool preparedToShow; + cParameters* parameters; + +signals: + + /** + \brief The signal is emitted when the range of m/z ratios has been changed. + \param minmz a minimum threshold of m/z ratio + \param maxmz a maximum threshold of m/z ratio + */ + void emitMZInterval(double minmz, double maxmz); + +private slots: + + void updateMZInterval(double minmz, double maxmz); + + void setMZInterval(); + +}; + +#endif \ No newline at end of file diff --git a/CycloBranch/main.cpp b/CycloBranch/main.cpp new file mode 100644 index 0000000..cbfb6ab --- /dev/null +++ b/CycloBranch/main.cpp @@ -0,0 +1,31 @@ +#include +#include +#include + +#include "gui/cMainWindow.h" + + +/** + \brief The main function. + \param argc number of arguments + \param argv pointer to an array of arguments + \retval int 0 when the application finished successfully +*/ +int main(int argc, char** argv) { + + QApplication app(argc, argv); + qRegisterMetaType("cTheoreticalSpectrum"); + qRegisterMetaType("cParameters"); + qRegisterMetaType >("vector"); + qRegisterMetaType("peptideType"); + qRegisterMetaType >("vector"); + qRegisterMetaType("string"); + qRegisterMetaType("cFragmentIons"); + + cMainWindow mwin; + mwin.show(); + + return app.exec(); + +} + diff --git a/CycloBranch/parallel/cGraphReaderThread.cpp b/CycloBranch/parallel/cGraphReaderThread.cpp new file mode 100644 index 0000000..6697502 --- /dev/null +++ b/CycloBranch/parallel/cGraphReaderThread.cpp @@ -0,0 +1,214 @@ +#include "parallel/cGraphReaderThread.h" + +#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) { + nodeEdge ne; + int tmpmiddlemodifID = 0; + int finish; + int size; + bool cycle; + + if (*terminatecomputation) { + return -1; + } + + if ((cummass > precursormass) && !isInPpmMassErrorTolerance(cummass, precursormass, parameters->precursormasserrortolerance)) { + return 0; + } + + if ((*graph)[nodeid].size() > 0) { + + for (int i = 0; i < (int)(*graph)[nodeid].size(); i++) { + + // accumulation of middle modifications is not allowed + if (((parameters->peptidetype == branched) || (parameters->peptidetype == lasso)) && (middlemodifID != 0) && ((*graph)[nodeid][i].middlemodifID != 0)) { + continue; + } + + // eliminate candidates from cyclic paths + cycle = false; + for (int j = 0; j < (int)perspectivepath.size(); j++) { + if ((*graph)[nodeid][i].targetnode == perspectivepath[j].nodeid) { + cycle = true; + break; + } + } + + if (cycle) { + continue; + } + + ne.nodeid = nodeid; + ne.edgeid = i; + perspectivepath.push_back(ne); + + if ((parameters->peptidetype == branched) || (parameters->peptidetype == lasso)) { + tmpmiddlemodifID = max(middlemodifID, (*graph)[nodeid][i].middlemodifID); + if (tmpmiddlemodifID != middlemodifID) { + middlepos = (int)composition.size(); + } + } + + 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); + composition.pop_back(); + + perspectivepath.pop_back(); + + if (finish == -1) { + return -1; + } + + } + } + else { + cCandidate candidate(composition, perspectivepath, startmodifID, endmodifID, middlemodifID, middlepos); + if ((candidate.getComposition().compare("") != 0) && (!candidate.hasOnlyArtificialBricks(*bricksdatabasewithcombinations))) { + + if (isInPpmMassErrorTolerance(precursormass, candidate.getPrecursorMass(*bricksdatabasewithcombinations, parameters), parameters->precursormasserrortolerance)) { + + cCandidateSet result; + + if (cterminalstartingnode) { + candidate.revertComposition(); + } + + 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); + } + 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; + } + + candidates->lock(); + size = candidates->size(); + candidates->unlock(); + } + + } + + } + + } + + return 0; +} + + +int cGraphReaderThread::reverseCTerminalCandidates(int nodeid, cCandidateSet* candidates, double precursormass, long long &count, 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) { + return -1; + } + + return 0; +} + + +cGraphReaderThread::cGraphReaderThread() { + graph = 0; + bricksdatabasewithcombinations = 0; + candidates = 0; + parameters = 0; + os = 0; + lastsystemnode = 0; + mode = 0; + terminatecomputation = 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) { + this->graph = &graph; + this->bricksdatabasewithcombinations = &bricksdatabasewithcombinations; + this->candidates = &candidates; + this->parameters = parameters; + this->os = os; + this->lastsystemnode = lastsystemnode; + this->mode = mode; + this->terminatecomputation = &terminatecomputation; +} + + +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 + return; + } + break; + case linear: + case branched: + for (int i = 1; i <= lastsystemnode; i++) { + if (i - 2 > 0) { + startmodifID = i - 2; + } + if (reverseCTerminalCandidates(i, candidates, unchargedprecursormass, count, startmodifID, terminatecomputation) == -1) { + // terminated by user + return; + } + } + break; + case lasso: + for (int i = 1; i <= lastsystemnode; i++) { + if (i - 1/*2*/ > 0) { + startmodifID = i - 1/*2*/; + } + if (reverseCTerminalCandidates(i, candidates, unchargedprecursormass, count, startmodifID, terminatecomputation) == -1) { + // terminated by user + return; + } + } + break; + case linearpolysaccharide: + for (int i = 1; i <= lastsystemnode; i++) { + if (i - 1 > 0) { + startmodifID = i - 1; + } + if (reverseCTerminalCandidates(i, candidates, unchargedprecursormass, count, startmodifID, terminatecomputation) == -1) { + // terminated by user + return; + } + } + break; + default: + break; + } + +} + diff --git a/CycloBranch/parallel/cGraphReaderThread.h b/CycloBranch/parallel/cGraphReaderThread.h new file mode 100644 index 0000000..4084b04 --- /dev/null +++ b/CycloBranch/parallel/cGraphReaderThread.h @@ -0,0 +1,84 @@ +/** + \file cGraphReaderThread.h + \brief The thread which scans the de novo graph for peptide sequence candidates. +*/ + + +#ifndef _CGRAPHREADERTHREAD_H +#define _CGRAPHREADERTHREAD_H + +#include +#include +#include +#include +#include + +#include "core/cParameters.h" +#include "core/cCandidateSet.h" +#include "core/cDeNovoGraphNode.h" +#include "core/cBricksDatabase.h" + + +using namespace std; + + +class cMainThread; + + +/** + \brief The class representing a thread which scans the de novo graph for peptide sequence candidates. +*/ +class cGraphReaderThread : public QThread { + + Q_OBJECT + +private: + + vector* graph; + cBricksDatabase* bricksdatabasewithcombinations; + cCandidateSet* candidates; + cParameters* parameters; + cMainThread* os; + int lastsystemnode; + int mode; + 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 reverseCTerminalCandidates(int nodeid, cCandidateSet* candidates, double precursormass, long long& count, int startmodifID, bool* terminatecomputation); + +public: + + + /** + \brief The constructor. + */ + cGraphReaderThread(); + + + /** + \brief Initialize the graph reader. + \param graph reference to the de novo graph + \param bricksdatabasewithcombinations reference to a database of bricks with combinations of bricks + \param candidates reference to a set where peptide sequence candidates will be stored + \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 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); + + +protected: + + + /** + \brief The main method of the thread. + */ + void run(); + +}; + + +#endif + diff --git a/CycloBranch/parallel/cSpectrumComparatorThread.cpp b/CycloBranch/parallel/cSpectrumComparatorThread.cpp new file mode 100644 index 0000000..1ea74cd --- /dev/null +++ b/CycloBranch/parallel/cSpectrumComparatorThread.cpp @@ -0,0 +1,192 @@ +#include "parallel/cSpectrumComparatorThread.h" + +#include "core/cTheoreticalSpectrumList.h" + + +bool compareBandAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b) { + if (a.getNumberOfMatchedPeaks(b_ion) > b.getNumberOfMatchedPeaks(b_ion)) { + return true; + } + if (a.getNumberOfMatchedPeaks(b_ion) < b.getNumberOfMatchedPeaks(b_ion)) { + return false; + } + if (a.getNumberOfMatchedPeaks() > b.getNumberOfMatchedPeaks()) { + return true; + } + return false; +} + + +bool compareBBwaterLossAndAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b) { + if (a.getNumberOfMatchedPeaks(b_ion) + a.getNumberOfMatchedPeaks(b_ion_water_loss) > b.getNumberOfMatchedPeaks(b_ion) + b.getNumberOfMatchedPeaks(b_ion_water_loss)) { + return true; + } + if (a.getNumberOfMatchedPeaks(b_ion) + a.getNumberOfMatchedPeaks(b_ion_water_loss) < b.getNumberOfMatchedPeaks(b_ion) + b.getNumberOfMatchedPeaks(b_ion_water_loss)) { + return false; + } + if (a.getNumberOfMatchedPeaks() > b.getNumberOfMatchedPeaks()) { + return true; + } + return false; +} + + +bool compareBBammoniaLossAndAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b) { + if (a.getNumberOfMatchedPeaks(b_ion) + a.getNumberOfMatchedPeaks(b_ion_ammonia_loss) > b.getNumberOfMatchedPeaks(b_ion) + b.getNumberOfMatchedPeaks(b_ion_ammonia_loss)) { + return true; + } + if (a.getNumberOfMatchedPeaks(b_ion) + a.getNumberOfMatchedPeaks(b_ion_ammonia_loss) < b.getNumberOfMatchedPeaks(b_ion) + b.getNumberOfMatchedPeaks(b_ion_ammonia_loss)) { + return false; + } + if (a.getNumberOfMatchedPeaks() > b.getNumberOfMatchedPeaks()) { + return true; + } + return false; +} + + +bool compareYBandAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b) { + if (a.getNumberOfMatchedPeaksYB() > b.getNumberOfMatchedPeaksYB()) { + return true; + } + if (a.getNumberOfMatchedPeaksYB() < b.getNumberOfMatchedPeaksYB()) { + return false; + } + if (a.getNumberOfMatchedPeaks() > b.getNumberOfMatchedPeaks()) { + return true; + } + return false; +} + + +bool compareYandAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b) { + if (a.getNumberOfMatchedPeaks(y_ion) > b.getNumberOfMatchedPeaks(y_ion)) { + return true; + } + if (a.getNumberOfMatchedPeaks(y_ion) < b.getNumberOfMatchedPeaks(y_ion)) { + return false; + } + if (a.getNumberOfMatchedPeaks() > b.getNumberOfMatchedPeaks()) { + return true; + } + return false; +} + + +bool compareWeightedIntensityDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b) { + return (a.getWeightedIntensityScore() > b.getWeightedIntensityScore()); +} + + +bool compareNumberOfMatchedPeaksDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b) { + return (a.getNumberOfMatchedPeaks() > b.getNumberOfMatchedPeaks()); +} + + +bool compareNumberOfMatchedBricksDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b) { + return (a.getNumberOfMatchedBricks() > b.getNumberOfMatchedBricks()); +} + + +void cSpectrumComparatorThread::initialize(cCandidate& candidate, cPeaksList& peaklist, cBricksDatabase* bricksdatabasewithcombinations, cTheoreticalSpectrumList* theoreticalspectrumlist, cParameters* parameters, regex* rxsequencetag, regex* rxsearchedsequence, double worstscore, bool* terminatecomputation) { + this->candidate = candidate; + this->peaklist = peaklist; + this->theoreticalspectrumlist = theoreticalspectrumlist; + this->parameters = parameters; + this->rxsequencetag = rxsequencetag; + this->rxsearchedsequence = rxsearchedsequence; + this->worstscore = worstscore; + this->terminatecomputation = terminatecomputation; + this->bricksdatabasewithcombinations = bricksdatabasewithcombinations; +} + + +void cSpectrumComparatorThread::run() { + cCandidateSet permutations; + double score; + + permutations.getSet().clear(); + if ((parameters->mode == 0) && (parameters->generatebrickspermutations)) { + candidate.getPermutations(permutations, terminatecomputation); + } + else { + permutations.getSet().insert(candidate); + } + + cTheoreticalSpectrum tsp; + tsp.resizePeakList(5000); + int theoreticalpeaksrealsize = 0; + + for (auto i = permutations.getSet().begin(); i != permutations.getSet().end(); ++i) { + + if (*terminatecomputation) { + //terminated by user + return; + } + + tsp.clear(false); // hot + tsp.setParameters(parameters); + tsp.setCandidate((cCandidate&)*i); + + switch (parameters->peptidetype) + { + case linear: + theoreticalpeaksrealsize = tsp.compareLinear(peaklist, *bricksdatabasewithcombinations, false, *rxsequencetag, *rxsearchedsequence); + break; + case cyclic: + theoreticalpeaksrealsize = tsp.compareCyclic(peaklist, *bricksdatabasewithcombinations, false, *rxsequencetag, *rxsearchedsequence); + break; + case branched: + theoreticalpeaksrealsize = tsp.compareBranched(peaklist, *bricksdatabasewithcombinations, false, *rxsequencetag, *rxsearchedsequence); + break; + case lasso: + theoreticalpeaksrealsize = tsp.compareLasso(peaklist, *bricksdatabasewithcombinations, false, *rxsequencetag, *rxsearchedsequence); + break; + case linearpolysaccharide: + theoreticalpeaksrealsize = tsp.compareLinearPolysaccharide(peaklist, *bricksdatabasewithcombinations, false, *rxsequencetag, *rxsearchedsequence); + break; + default: + break; + } + + // invalid sequence tag + if (theoreticalpeaksrealsize == -2) { + continue; + } + + score = 0; + switch (parameters->scoretype) { + case b_ions: + score = tsp.getNumberOfMatchedPeaks(b_ion); + break; + case b_ions_and_b_water_loss_ions: + score = tsp.getNumberOfMatchedPeaks(b_ion) + tsp.getNumberOfMatchedPeaks(b_ion_water_loss); + break; + case b_ions_and_b_ammonia_loss_ions: + score = tsp.getNumberOfMatchedPeaks(b_ion) + tsp.getNumberOfMatchedPeaks(b_ion_ammonia_loss); + break; + case y_ions_and_b_ions: + score = tsp.getNumberOfMatchedPeaksYB(); + break; + case y_ions: + score = tsp.getNumberOfMatchedPeaks(y_ion); + break; + case weighted_intensity: + score = tsp.getWeightedIntensityScore(); + break; + case matched_peaks: + score = tsp.getNumberOfMatchedPeaks(); + break; + case matched_bricks: + score = tsp.getNumberOfMatchedBricks(); + break; + } + + if (score >= worstscore) { + theoreticalspectrumlist->addButDoNotFitSize(tsp, theoreticalpeaksrealsize); + } + + } + +} + diff --git a/CycloBranch/parallel/cSpectrumComparatorThread.h b/CycloBranch/parallel/cSpectrumComparatorThread.h new file mode 100644 index 0000000..b716ec4 --- /dev/null +++ b/CycloBranch/parallel/cSpectrumComparatorThread.h @@ -0,0 +1,140 @@ +/** + \file cSpectrumComparatorThread.h + \brief The thread for comparison of a theoretical spectrum with a peak list. +*/ + + +#ifndef _CSPECTRUMCOMPARATORTHREAD_H +#define _CSPECTRUMCOMPARATORTHREAD_H + +#include +#include + +#include "core/cTheoreticalSpectrum.h" + + +class cTheoreticalSpectrumList; + + +/** + \brief Compare scores of two theoretical spectra (number of b-ions and all ions secondly). + \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 +*/ +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). + \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 +*/ +bool compareBBwaterLossAndAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b); + + +/** + \brief Compare scores of two theoretical spectra (number of b-ions + ammonia loss 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 +*/ +bool compareBBammoniaLossAndAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b); + + +/** + \brief Compare scores of two theoretical spectra (number of b-ions + y-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 +*/ +bool compareYBandAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b); + + +/** + \brief Compare scores of two theoretical spectra (number of y-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 +*/ +bool compareYandAllIonsDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b); + + +/** + \brief Compare scores of two theoretical spectra (sum of relative intensities of matched peaks). + \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 +*/ +bool compareWeightedIntensityDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b); + + +/** + \brief Compare scores of two theoretical spectra (number of matched peaks). + \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 +*/ +bool compareNumberOfMatchedPeaksDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b); + + +/** + \brief Compare scores of two theoretical spectra (number of matched bricks). + \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 +*/ +bool compareNumberOfMatchedBricksDesc(cTheoreticalSpectrum& a, cTheoreticalSpectrum& b); + + +/** + \brief The class representing a thread for comparison of a theoretical spectrum with a peak list. +*/ +class cSpectrumComparatorThread : public QObject, public QRunnable { + + Q_OBJECT + +private: + + cCandidate candidate; + cPeaksList peaklist; + cTheoreticalSpectrumList* theoreticalspectrumlist; + cParameters* parameters; + regex* rxsequencetag; + regex* rxsearchedsequence; + double worstscore; + bool* terminatecomputation; + cBricksDatabase* bricksdatabasewithcombinations; + +public: + + + /** + \brief Initialize the spectrum comparator. + \param candidate reference to a peptide sequence candidate + \param peaklist reference to a peak list + \param bricksdatabasewithcombinations pointer to a database of bricks with combinations of bricks + \param theoreticalspectrumlist pointer to the result list of theoretical spectra + \param parameters pointer to program parameters + \param rxsequencetag pointer to a regular expression of a sequence tag + \param rxsearchedsequence pointer to a regular expression of a searched sequence + \param worstscore worst score in the resulting set of theoretical spectra + \param terminatecomputation reference to a variable determining that the thread must be stopped + */ + void initialize(cCandidate& candidate, cPeaksList& peaklist, cBricksDatabase* bricksdatabasewithcombinations, cTheoreticalSpectrumList* theoreticalspectrumlist, cParameters* parameters, regex* rxsequencetag, regex* rxsearchedsequence, double worstscore, bool* terminatecomputation); + + +protected: + + + /** + \brief The main method of the thread. + */ + void run(); + +}; + + +#endif + diff --git a/licence.txt b/licence.txt new file mode 100644 index 0000000..818433e --- /dev/null +++ b/licence.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..571ce70 --- /dev/null +++ b/readme.txt @@ -0,0 +1,3 @@ +CycloBranch.sln +- project for MS Visual Studio 2012 +- requires Qt 5.1.1 installed