diff -Nru minexpert2-7.4.1/appimage/mineXpert2-appimage-recipe.yml minexpert2-8.1.1/appimage/mineXpert2-appimage-recipe.yml --- minexpert2-7.4.1/appimage/mineXpert2-appimage-recipe.yml 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/appimage/mineXpert2-appimage-recipe.yml 2021-04-26 11:28:25.000000000 +0000 @@ -6,7 +6,7 @@ id: minexpert2 name: mineXpert2 icon: minexpert2 - version: 7.4.1 + version: 8.1.1 exec: usr/bin/minexpert2 exec_args: $@ runtime: diff -Nru minexpert2-7.4.1/CMakeLists.txt minexpert2-8.1.1/CMakeLists.txt --- minexpert2-7.4.1/CMakeLists.txt 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/CMakeLists.txt 2021-04-26 11:28:25.000000000 +0000 @@ -11,11 +11,11 @@ DESCRIPTION "A program to visualize and explore mass spectrometric data" HOMEPAGE_URL "http://wwww.msxpertsuite.org/minexpert2") -set(VERSION 7.4.1) +set(VERSION 8.1.1) # Set additional project information set(COMPANY "msXpertSuite.org") -set(COPYRIGHT "Copyright (c) 2008-2020 Filippo Rusconi. Licensed under GPLv3+") +set(COPYRIGHT "Copyright (c) 2008-2021 Filippo Rusconi. Licensed under GPLv3+") set(IDENTIFIER "org.msxpertsuite") @@ -195,11 +195,11 @@ # directory, because at that moment they will need what are # going to prepare right now. configure_file(${CMAKE_SOURCE_DIR}/CMakeStuff/splashscreen.svg.in - ${CMAKE_SOURCE_DIR}/images/splashscreen.svg @ONLY) + ${CMAKE_SOURCE_DIR}/images/svg/splashscreen.svg @ONLY) # Make the conversion of the svg file into a png, but only on GNU/Linux if(UNIX AND NOT APPLE) - execute_process(COMMAND convert ${CMAKE_SOURCE_DIR}/images/splashscreen.svg + execute_process(COMMAND convert ${CMAKE_SOURCE_DIR}/images/svg/splashscreen.svg ${CMAKE_SOURCE_DIR}/images/splashscreen.png) endif() diff -Nru minexpert2-7.4.1/CMakeStuff/toolchains/unix-toolchain.cmake minexpert2-8.1.1/CMakeStuff/toolchains/unix-toolchain.cmake --- minexpert2-7.4.1/CMakeStuff/toolchains/unix-toolchain.cmake 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/CMakeStuff/toolchains/unix-toolchain.cmake 2021-04-26 11:28:25.000000000 +0000 @@ -8,24 +8,6 @@ # This is used throughout all the build system files set(TARGET minexpert2) -# Now that we know what is the TARGET (in the toolchain files above, -# we can compute the lowercase TARGET (used for string replacements in -# configure files and also for the resource compilation with windres.exe. -string(TOLOWER ${TARGET} TARGET_LOWERCASE) -message("TARGET_LOWERCASE: ${TARGET_LOWERCASE}") - - -# No more used as now this code belongs to the PappsoMSppWidget library. -#set(CustomPwiz_FOUND 1) -#set(CustomPwiz_INCLUDE_DIRS "/home/rusconi/devel/custompwiz/development/src") -#set(CustomPwiz_LIBRARY "/home/rusconi/devel/custompwiz/build-area/src/libcustompwiz.so.3.0.0") -#if(NOT TARGET CustomPwiz::CustomPwiz) -#add_library(CustomPwiz::CustomPwiz UNKNOWN IMPORTED) -#set_target_properties(CustomPwiz::CustomPwiz PROPERTIES -#IMPORTED_LOCATION "${CustomPwiz_LIBRARY}" -#INTERFACE_INCLUDE_DIRECTORIES "${CustomPwiz_INCLUDE_DIRS}") -#endif() - find_package(QCustomPlot REQUIRED) # Per instructions of the lib author: @@ -47,15 +29,10 @@ # On UNIX, the libpappsomspp and libpappsomspp-widget libs # need to be installed and they ship the PappsoMSppConfig.cmake # config file. - find_package(PappsoMSpp COMPONENTS Core Widget REQUIRED) -if(PappsoMSpp_FOUND) - - message(STATUS "PappsoMSpp and PappsoMSppWidget were found at: ${PappsoMSpp_LIBRARY}") - message(STATUS "Include dir for PappsoMSpp is at: ${PappsoMSpp_INCLUDE_DIRS}") - -endif() +message(STATUS "PappsoMSpp and PappsoMSppWidget were found at: ${PappsoMSpp_LIBRARY}") +message(STATUS "Include dir for PappsoMSpp is at: ${PappsoMSpp_INCLUDE_DIRS}") ## Install directories if(NOT CMAKE_INSTALL_PREFIX) diff -Nru minexpert2-7.4.1/debian/changelog minexpert2-8.1.1/debian/changelog --- minexpert2-7.4.1/debian/changelog 2021-02-20 11:29:25.000000000 +0000 +++ minexpert2-8.1.1/debian/changelog 2021-04-26 11:24:01.000000000 +0000 @@ -1,3 +1,62 @@ +minexpert2 (8.1.1-1) unstable; urgency=low + + * New upstream release improving the setting of the low/high filtering + configuration for color map data. + + -- Filippo Rusconi Mon, 26 Apr 2021 13:24:01 +0200 + +minexpert2 (8.1.0-1) unstable; urgency=low + + * New upstream version adding signal-to-noise ratio enhancement features for + the color maps. + + -- Filippo Rusconi Wed, 21 Apr 2021 13:06:20 +0200 + +minexpert2 (8.0.3-1) unstable; urgency=low + + * New version with a reworked icon system based on svg files and not png + ones. + + -- Filippo Rusconi Thu, 15 Apr 2021 16:56:48 +0200 + +minexpert2 (8.0.2-2) unstable; urgency=low + + * Build that depends on new ABI of pappsomspp libs. + + -- Filippo Rusconi Mon, 12 Apr 2021 21:48:05 +0200 + +minexpert2 (8.0.2-1) unstable; urgency=low + + * New version to build with libpappsomspp 0.8.23 that provides a workaround + the failing tests on i386. + + * Other small changes. + + -- Filippo Rusconi Wed, 31 Mar 2021 15:00:05 +0200 + +minexpert2 (8.0.1-1) unstable; urgency=low + + * Fixes to the documentation (new figures with much more interesting data + set to document the skewed selection polygon feature). + + * Provide the new bibliographic reference for citation in the Help dialog + box. + + -- Filippo Rusconi Wed, 24 Mar 2021 11:20:13 +0100 + +minexpert2 (8.0.0-1) unstable; urgency=low + + * New major release with the skewed selection polygon feature. + + -- Filippo Rusconi Tue, 23 Mar 2021 16:49:24 +0100 + +minexpert2 (7.4.1-2) unstable; urgency=low + + * Update dependencies for libpappsomspp-dev (>= 0.8.18), + libpappsomspp-widget-dev (>= 0.8.18). + + -- Filippo Rusconi Wed, 03 Mar 2021 09:24:56 +0100 + minexpert2 (7.4.1-1) unstable; urgency=low * Fix glitch remaining for times where MzIntegrationParams belonged to this diff -Nru minexpert2-7.4.1/debian/control minexpert2-8.1.1/debian/control --- minexpert2-7.4.1/debian/control 2021-02-20 11:29:25.000000000 +0000 +++ minexpert2-8.1.1/debian/control 2021-04-26 11:24:01.000000000 +0000 @@ -21,10 +21,11 @@ fonts-mathjax-extras, texlive-fonts-extra (>= 2020.20210202), fonts-ebgaramond-extra, + gsfonts, libqcustomplot-dev(>= 2.0), libisospec++-dev (>=2.1.3), - libpappsomspp-dev (>= 0.8.15), - libpappsomspp-widget-dev (>= 0.8.15), + libpappsomspp-dev (>= 0.8.25), + libpappsomspp-widget-dev (>= 0.8.25), docbook-to-man, qttools5-dev-tools, qtchooser diff -Nru minexpert2-7.4.1/doc/history.html minexpert2-8.1.1/doc/history.html --- minexpert2-7.4.1/doc/history.html 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/doc/history.html 2021-04-26 11:28:25.000000000 +0000 @@ -3,9 +3,10 @@ - + - + + @@ -13,6 +14,8 @@ + +


-

-

2020-

- -

Following the publication - of mineXpert in the Journal of Proteome Research (ACS) in 2019, I decided to - rewrite the software to comply with the major criticism of the reviewers that - I accepted as perfectly legitimate: the drawback that MS2 data were not - handled easily in mineXpert. In my rewriting the code, I decided that I would - not limit the capabilities of the program to MS and MS/MS data, but that I - would code a support for MSn mass spectrometry. In -July 2020, the rewrite of the program was finished.

- -

From the parallel computing point of view, this new version of mineXpert is -very much more powerful than the previous one. Also, the mass spectral data -integration code was totally rewritten to execute much faster. The new version -of mineXpert is now named mineXpert2 as a testimonial of the full code rewrite. -The version numbering however follows the old numbers: the first mineXpert2 -version is numbered 6.0.0.

+
+

+

2021

+

The mineXpert2 +software has been published in the Journal +of the American Society for Mass Spectrometry: + +

+

O. +Langella and F. Rusconi. 2021. mineXpert2: +Full-Depth Visualization and Exploration of MSn +Mass Spectrometry Data. J. Am. Soc. Mass Spectrom. +https://doi.org/10.1021/jasms.0c00402.

+

2020

+

Following the +publication of mineXpert in the Journal of Proteome Research (ACS) in +2019, I decided to rewrite the software to comply with the major +criticism of the reviewers that I accepted as perfectly legitimate: +the drawback that MS2 data were not handled easily in mineXpert. In +my rewriting the code, I decided that I would not limit the +capabilities of the program to MS and MS/MS data, but that I would +code a support for MSn +mass spectrometry. In July 2020, +the rewrite of the program was finished.

+

From the parallel computing point of +view, this new version of mineXpert is very much more powerful than +the previous one. Also, the mass spectral data integration code was +totally rewritten to execute much faster. The new version of +mineXpert is now named mineXpert2 as a testimonial of the full code +rewrite. The version numbering however follows the old numbers: the +first mineXpert2 version is numbered 6.0.0. +

2016-2019

After a long period of successful use/maintenance of the code (in particular there has been the port to Qt5), the start @@ -147,4 +163,4 @@ https://www.biomedcentral.com/track/pdf/10.1186/1471-2105-7-226?site=bmcbioinformatics.biomedcentral.com

 

- + \ No newline at end of file diff -Nru minexpert2-7.4.1/doc/user-manual/CMakeLists.txt minexpert2-8.1.1/doc/user-manual/CMakeLists.txt --- minexpert2-7.4.1/doc/user-manual/CMakeLists.txt 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/doc/user-manual/CMakeLists.txt 2021-04-26 11:28:25.000000000 +0000 @@ -13,17 +13,22 @@ # make minexpert-doc # Makes use of the local Makefile file. # Will generate HTML and PDF documentation in the build directory - add_custom_target(${TARGET_LOWERCASE}-doc ALL + + # Note that TARGET needs to be lowercase. Since we build the documentation + # only on UNIX, that target is set in + # CMakeStuff/toolchains/unix-toolchain.cmake. + + add_custom_target(${TARGET}-doc ALL COMMAND make all WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "DocBook-based user manual documentation for ${CMAKE_PROJECT_NAME}") install(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/build/minexpert2-user-manual/${TARGET_LOWERCASE}-doc.pdf + ${CMAKE_CURRENT_SOURCE_DIR}/build/minexpert2-user-manual/${TARGET}-doc.pdf DESTINATION ${DOC_DIR}) install(DIRECTORY - ${CMAKE_CURRENT_SOURCE_DIR}/build/${TARGET_LOWERCASE}-user-manual/html/${TARGET_LOWERCASE}-user-manual/ + ${CMAKE_CURRENT_SOURCE_DIR}/build/${TARGET}-user-manual/html/${TARGET}-user-manual/ DESTINATION ${DOC_DIR}/html) message("") Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/doc/user-manual/images/src/png/print-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-final-step.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/doc/user-manual/images/src/png/print-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-final-step.png differ Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/doc/user-manual/images/src/png/print-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-initial-step.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/doc/user-manual/images/src/png/print-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-initial-step.png differ Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/doc/user-manual/images/src/png/print-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-result.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/doc/user-manual/images/src/png/print-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-result.png differ Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/doc/user-manual/images/src/png/print-minexpert-colormap-noise-reduction.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/doc/user-manual/images/src/png/print-minexpert-colormap-noise-reduction.png differ Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/doc/user-manual/images/src/png/print-minexpert-dt-mz-colormap-widget-original-z-scale.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/doc/user-manual/images/src/png/print-minexpert-dt-mz-colormap-widget-original-z-scale.png differ Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/doc/user-manual/images/src/png/web-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-final-step.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/doc/user-manual/images/src/png/web-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-final-step.png differ Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/doc/user-manual/images/src/png/web-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-initial-step.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/doc/user-manual/images/src/png/web-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-initial-step.png differ Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/doc/user-manual/images/src/png/web-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-result.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/doc/user-manual/images/src/png/web-minexpert-colormap-based-integrations-with-skewed-selection-rectangle-result.png differ Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/doc/user-manual/images/src/png/web-minexpert-colormap-noise-reduction.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/doc/user-manual/images/src/png/web-minexpert-colormap-noise-reduction.png differ Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/doc/user-manual/images/src/png/web-minexpert-dt-mz-colormap-widget-original-z-scale.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/doc/user-manual/images/src/png/web-minexpert-dt-mz-colormap-widget-original-z-scale.png differ diff -Nru minexpert2-7.4.1/doc/user-manual/xml/generalities.xml minexpert2-8.1.1/doc/user-manual/xml/generalities.xml --- minexpert2-7.4.1/doc/user-manual/xml/generalities.xml 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/doc/user-manual/xml/generalities.xml 2021-04-26 11:28:25.000000000 +0000 @@ -15,9 +15,9 @@ ]> + xml:id="chap_generalities" + xmlns="http://docbook.org/ns/docbook" version="5.0" + xmlns:xlink="http://www.w3.org/1999/xlink"> @@ -35,22 +35,43 @@ In this chapter, I wish to introduce some general concepts around the -&mineXp2; program and the way data elements are named in this manual and in -the program. + &mineXp2; program and the way data elements are named in this manual and in + the program. A mass spectrometry experiment generally involves monitoring the &mz; -value of analytes injected in the mass spectrometer along a certain time -duration. The &mz; value of each detected analyte is recorded along with the -corresponding signal intensity ∫, so that a mass spectrum is nothing but -a series of &mzi; pairs recorded along the acquisition duration. All along -the acquisition, the precise moment at which a given analyte is detected -(and its &mzi; pair is recorded), is called the retention time of that -analyte (&rt;). This retention time is not to be misunderstood as the drift -time of that analyte in an ion mobility mass spectrometry experiment. + value of analytes injected in the mass spectrometer along a certain time + duration. The &mz; value of each detected analyte is recorded along with the + corresponding signal intensity ∫, so that a mass spectrum is nothing but + a series of &mzi; pairs recorded along the acquisition duration. All along + the acquisition, the precise moment at which a given analyte is detected + (and its &mzi; pair is recorded), is called the retention time of that + analyte (&rt;). This retention time is not to be misunderstood as the drift + time of that analyte in an ion mobility mass spectrometry experiment. + + + Citing the &mineXp2; software. + + + + + + Please, cite the software using the following citation: + + mineXpert2: Full-Depth Visualization and Exploration of MSn Mass + Spectrometry Data. Olivier Langella and Filippo Rusconi. + Journal of the American Society for Mass Spectrometry + (check for pages, as this is a pub ahead of print reference). DOI: 10.1021/jasms.0c00402. + + + + + + + General concepts and terminologies Most generally, the mass spectrometer acquires an important number of @@ -89,31 +110,31 @@ MALDI-TOF mass spectrometers are used when manually acquiring data from samples deposited onto sample plates. We refer to this kind of acquisition as an accumulation mode - acquisition; + acquisition; - + - + - Mass spectra are acquired and stored on disk as a single file - containing all the spectra, appended one after the other. There is - no combination of the spectra: each time a new spectrum is displayed - on screen, that spectrum is appended to the - file.Although there certainly is spectrum - combination going on in the guts of the software, because the - system actually acquires much more spectra than is visible on - screen and each newly displayed spectrum is actually the - combination of many spectra acquired under the - surface. This is typically the case when mass - spectra are acquired all along a chromatography run and is - generally called a profile - mode acquisition. Note that this profile mode acquisition must - not be mistaken as the profile mass peak type that negates the - centroid mass peak type. + Mass spectra are acquired and stored on disk as a single file + containing all the spectra, appended one after the other. There is + no combination of the spectra: each time a new spectrum is displayed + on screen, that spectrum is appended to the + file.Although there certainly is spectrum + combination going on in the guts of the software, because the + system actually acquires much more spectra than is visible on + screen and each newly displayed spectrum is actually the + combination of many spectra acquired under the + surface. This is typically the case when mass + spectra are acquired all along a chromatography run and is + generally called a profile + mode acquisition. Note that this profile mode acquisition must + not be mistaken as the profile mass peak type that negates the + centroid mass peak type. - + - + @@ -129,56 +150,56 @@ a single combined spectrum? Say we have 200 spectra that need to be combined together into a single spectrum that summatively represents the - data of these 200 spectra. + data of these 200 spectra. - First, a new spectrum would be allocated (result - spectrum), entirely empty at first. Then, the very first - spectrum of the 200 spectra is literally copied into that result - spectrum. At this point the combination occurs, according to an - iterative process that has the following steps: + First, a new spectrum would be allocated (result + spectrum), entirely empty at first. Then, the very first + spectrum of the 200 spectra is literally copied into that result + spectrum. At this point the combination occurs, according to an + iterative process that has the following steps: - + - + - Pick the next spectrum of the 200-spectra dataset; + Pick the next spectrum of the 200-spectra dataset; - + - + - Pick the first &mzi; pair of the currently iterated - spectrum; + Pick the first &mzi; pair of the currently iterated + spectrum; - + - + - Look up in the result spectrum if a - &mz; value identical to the &mz; value of the current - &mzi; pair is already present; + Look up in the result spectrum if a + &mz; value identical to the &mz; value of the current + &mzi; pair is already present; - + - + - If the &mz; value is found, increment its intensity by - the intensity of the &mzi; pair; + If the &mz; value is found, increment its intensity by + the intensity of the &mzi; pair; - + - + - Else, if the &mz; value is not found, add the current - &mzi; pair to the result spectrum; + Else, if the &mz; value is not found, add the current + &mzi; pair to the result spectrum; - + - + - Iterate over all the remaining &mzi; pairs of the current - spectrum and redo these steps. + Iterate over all the remaining &mzi; pairs of the current + spectrum and redo these steps. @@ -189,34 +210,34 @@ Iterate over all the 198 remaining spectra of the dataset - and do the steps above for each single iterated spectrum. + and do the steps above for each single iterated spectrum. - + - + - + - At the end of the two nested loops above, the combined spectrum is -still a single spectrum that represents—summatively—all the -200 spectra. This whole process is very computing-intensive, in particular -if: + At the end of the two nested loops above, the combined spectrum is + still a single spectrum that represents—summatively—all the + 200 spectra. This whole process is very computing-intensive, in particular + if: - + - + - The &mz; range is large: there are lots of points in - each spectrum, which means that for each new &mzi; pair we need - to iterate in the long list of &mz; values that make the - result spectrum; + The &mz; range is large: there are lots of points in + each spectrum, which means that for each new &mzi; pair we need + to iterate in the long list of &mz; values that make the + result spectrum; - + - + - The resolving power of the mass spectrometer is high: there - are many points per &mz; range unit. + The resolving power of the mass spectrometer is high: there + are many points per &mz; range unit. @@ -248,7 +269,7 @@ absorb UV light but do not either desorb/desolvate or ionize, or both.. For each retention time (RT) a TIC value is computed by summing the intensities of all the &mzi; pairs detected at that specific -RT. + RT. How is this total ion current chromatogram computed? This is an iterative process: from the first spectrum (retention time value @@ -258,7 +279,7 @@ computation ends up with a map that relates each RT value with the corresponding TIC value. The TIC chromatogram is nothing but a plot of the TIC values as a function of RT values. In that sense, it is indeed a -chromatogram. + chromatogram. &mineXp2; works exactly in this way. When mass spectrometry data are loaded from a file, the TIC chromatogram is computed and displayed. This TIC @@ -274,14 +295,14 @@ Integrating data from the TIC chromatogram to a single mass - spectrum; + spectrum; - + - + - Integrating data from the TIC chromatogram to a single drift - spectrum; + Integrating data from the TIC chromatogram to a single drift + spectrum; @@ -294,7 +315,7 @@ that the TIC chromatogram be reconstituted from there; or selecting a region of a drift spectrum and asking that the TIC chromatogram be reconstituted from there also. Finally, integrations may, of course, be performed from a mass - spectrum to a drift spectrum, and reverse. + spectrum to a drift spectrum, and reverse. @@ -314,21 +335,21 @@ What is the drift time of the ions below this mass - peak? + peak? - + - + - What are all the drift times of all the analytes going - through the mobility cell for a given retention time range? + What are all the drift times of all the analytes going + through the mobility cell for a given retention time range? - + - + - What are all the ions that are responsible for this - shoulder in the drift spectrum? + What are all the ions that are responsible for this + shoulder in the drift spectrum? @@ -343,62 +364,62 @@ What computation does actually &mineXp2; do when a mass spectrum is computed starting from a TIC chromatogram region, say between retention time RT minute 7 and - RT minute 8.5? + RT minute 8.5? - + - + + + List all the mass spectra that were acquired between RT 7 + and RT 8.5. In this spectral set, there + might be many hundreds of spectra that match this criterion, if we + think that, in ion mobility mass spectrometry, + ≈ 200 spectra are acquired and stored individually + every second (I mean it, every 1 s time lapse); + + + + - List all the mass spectra that were acquired between RT 7 - and RT 8.5. In this spectral set, there - might be many hundreds of spectra that match this criterion, if we - think that, in ion mobility mass spectrometry, - ≈ 200 spectra are acquired and stored individually - every second (I mean it, every 1 s time lapse); - - - - - - Allocate a new empty spectrum—the - combined spectrum—and - copy into it without modification the first spectrum of the - spectral set; + Allocate a new empty spectrum—the + combined spectrum—and + copy into it without modification the first spectrum of the + spectral set; Go to the next spectrum of the spectral - set and iterate into each &mzi; pair: + set and iterate into each &mzi; pair: - + - + - Check if the &mz; value of the iterated pair is - already present in the combined spectrum. If so, increment the - combined spectrum's &mzi; pair's intensity value by the - intensity of the iterated &mzi; pair's intensity. If not, simply - copy the iterated &mzi; pair in the combined spectrum; + Check if the &mz; value of the iterated pair is + already present in the combined spectrum. If so, increment the + combined spectrum's &mzi; pair's intensity value by the + intensity of the iterated &mzi; pair's intensity. If not, simply + copy the iterated &mzi; pair in the combined spectrum; - + - + - Iterate over all the remaining &mzi; pairs and - perform the same action as above. + Iterate over all the remaining &mzi; pairs and + perform the same action as above. - + - + - + - + - Iterate over all the remaining spectra of the spectral set and - perform step number . + Iterate over all the remaining spectra of the spectral set and + perform step number . @@ -415,28 +436,28 @@ What computation does &mineXp2; actually do when a drift spectrum is computed starting from a given TIC chromatogram region, say between retention time RT minute 7 and - RT minute 8.5? + RT minute 8.5? - What is a drift spectrum? A drift spectrum (mobilogram) is a - plot where the cumulated ion current of the detected ions is plotted - against the drift time at which they were detected. Let's see how - that computation is handled in &mineXp2;: + What is a drift spectrum? A drift spectrum (mobilogram) is a + plot where the cumulated ion current of the detected ions is plotted + against the drift time at which they were detected. Let's see how + that computation is handled in &mineXp2;: - + - + - Create a map to store all the (drift time, intensity) pairs - that are to be computed below, the (dt,i) map; + Create a map to store all the (drift time, intensity) pairs + that are to be computed below, the (dt,i) map; - + - + - List all the mass spectra that were acquired between - RT 7 and RT 8.5. The obtained list of mass spectra is - called the spectral - set; + List all the mass spectra that were acquired between + RT 7 and RT 8.5. The obtained list of mass spectra is + called the spectral + set; @@ -447,38 +468,38 @@ that spectrum). Get the drift time value at which this mass spectrum was acquired. We thus have a value pair: (dt, i), that is, for drift time dt, the intensity of the - total ion current is i; + total ion current is i; - At this point, we need to do a short digression: we saw - earlier that, at the time of this writing, one of the - commercial instruments on which the author of these lines does - his experiments stores 200 spectra each second. These - 200 spectra actually correspond to the way the drift - cycle is divided into 200 bin (time bins). That means - that in the retention time range [7–8.5], there are - (1.5*60) complete drift cycles. And thus there are (1.5*60) - spectra with drift time x, the same amount of spectra - with drift time y, and so on for the reminaing - 198 time bins. Of course, a large number of these - spectra might be almost empty, but these spectra are there and - we need to cope with them. - -The paragraph above must thus lead to one interrogation about -the current (dt,i) pair: —Has the current -dt value be seen before, during the previous iterations in -this loop?. If not, then create the (dt, i) -pair and add it to the (dt,i) map; if yes, get the -dt element in the map and increment its -intensity value by the TIC value computed above; + At this point, we need to do a short digression: we saw + earlier that, at the time of this writing, one of the + commercial instruments on which the author of these lines does + his experiments stores 200 spectra each second. These + 200 spectra actually correspond to the way the drift + cycle is divided into 200 bin (time bins). That means + that in the retention time range [7–8.5], there are + (1.5*60) complete drift cycles. And thus there are (1.5*60) + spectra with drift time x, the same amount of spectra + with drift time y, and so on for the reminaing + 198 time bins. Of course, a large number of these + spectra might be almost empty, but these spectra are there and + we need to cope with them. + + The paragraph above must thus lead to one interrogation about + the current (dt,i) pair: —Has the current + dt value be seen before, during the previous iterations in + this loop?. If not, then create the (dt, i) + pair and add it to the (dt,i) map; if yes, get the + dt element in the map and increment its + intensity value by the TIC value computed above; Iterate over all the remaining spectra of the spectral set and - perform step number . + perform step number . - + @@ -488,10 +509,10 @@ relates a given drift time with a TIC value. This can be understood this way: —For each drift time value, what is the accumulated ion current of all the ions having that specific - drift time?. + drift time?. -At this point, &mineXp2; displays the drift spectrum -(mobilogram). + At this point, &mineXp2; displays the drift spectrum + (mobilogram). @@ -504,13 +525,13 @@ Whenever the computer has multiple threads available for the integrations to be performed using parallel execution, &mineXp2; manages to use all these available threads. It is possible to limit the number of threads used for - the integration computations as described in , . + the integration computations as described in , . - + - + @@ -521,302 +542,302 @@ - The installation material is available at . + The installation material is available at . - + - + - Installation on MS Windows and macOS systems + Installation on MS Windows and macOS systems - + - The installation of the software is extremely easy on the MS-Windows and - macOS platforms. In both cases, the installation programs are standard and - require no explanation. + The installation of the software is extremely easy on the MS-Windows and + macOS platforms. In both cases, the installation programs are standard and + require no explanation. - + - + - + - Installation on Debian- and Ubuntu-based systems + Installation on Debian- and Ubuntu-based systems - + - The installation on Debian- and Ubuntu-based GNU/Linux platforms is - also extremely easy (even more than in the above situations). - &mineXp2; is indeed packaged and released in the official - distribution repositories of these distributions and the only command - to run to install it is: + The installation on Debian- and Ubuntu-based GNU/Linux platforms is + also extremely easy (even more than in the above situations). + &mineXp2; is indeed packaged and released in the official + distribution repositories of these distributions and the only command + to run to install it is: - - - + - $ + - The prompt character might be - % in some shells, like - zsh. + $ - sudo apt install <package_name>RETURN + The prompt character might be + % in some shells, like + zsh. - + sudo apt install <package_name>RETURN - + - In the command above, the typical package_name is - in the form minexpert2 for the program package and - minexpert2-doc for the user manual package. + - + In the command above, the typical package_name is + in the form minexpert2 for the program package and + minexpert2-doc for the user manual package. - + - Once the package has been installed the program shows up in the - Science menu. It can also be launched from the shell - using the following command: + - + Once the package has been installed the program shows up in the + Science menu. It can also be launched from the shell + using the following command: - + - $ minexpert2RETURN + - + $ minexpert2RETURN - + - + - If the Debian system onto which the program is to be installed is older - than testing, that is, older than Buster - (Debian 10), then using the AppImage program bundle might - be a solution. See below for the method to run &mineXp2; as an AppImage - bundle. + - + If the Debian system onto which the program is to be installed is older + than testing, that is, older than Buster + (Debian 10), then using the AppImage program bundle might + be a solution. See below for the method to run &mineXp2; as an AppImage + bundle. - + - + - + - Installation with an AppImage software bundle + - + Installation with an AppImage software bundle - The AppImage software bundle format is a format - that allows one to easily run a software program on any GNU/Linux-based - distribution. From the : + -
+ The AppImage software bundle format is a format + that allows one to easily run a software program on any GNU/Linux-based + distribution. From the : - Simon Peter +
- + Simon Peter - The key idea of the AppImage format is one app = one file. Every - AppImage contains an app and all the files the app needs to run. In - other words, each AppImage has no dependencies other than what is - included in the targeted base operating system(s). + - + The key idea of the AppImage format is one app = one file. Every + AppImage contains an app and all the files the app needs to run. In + other words, each AppImage has no dependencies other than what is + included in the targeted base operating system(s). -
+ - +
- + - There are AppImage software bundles for the various &mineXp2; versions - that are available for download. As of writing, the software bundle has - been tested on Centos version 8.3.2011 - and on Fedora version 22. These are - pretty old distribution versions and thus &mineXp2; should also run on - more recent versions of these computing platforms. The AppImage bundle - of &mineXp2; was created on a rather current Debian version: the - testing Debian 11-to-be - distribution. + - + There are AppImage software bundles for the various &mineXp2; versions + that are available for download. As of writing, the software bundle has + been tested on Centos version 8.3.2011 + and on Fedora version 22. These are + pretty old distribution versions and thus &mineXp2; should also run on + more recent versions of these computing platforms. The AppImage bundle + of &mineXp2; was created on a rather current Debian version: the + testing Debian 11-to-be + distribution. - + - In order to run the &mineXp2; software AppImage bundle, download the - latest version (like - mineXpert2-0.7.4-x86_64.AppImage). Once the file - has been downloaded to the desired directory, change to that directory - and change the permissions to make it executable: + - + In order to run the &mineXp2; software AppImage bundle, download the + latest version (like + mineXpert2-0.7.4-x86_64.AppImage). Once the file + has been downloaded to the desired directory, change to that directory + and change the permissions to make it executable: - + - $ chmod a+x - mineXpert2-0.7.4-x86_64.AppImageRETURN + - + $ chmod a+x + mineXpert2-0.7.4-x86_64.AppImageRETURN - + - Finally, execute the file that has become a normal program: + - + Finally, execute the file that has become a normal program: - + - $ - ./mineXpert2-0.7.4-x86_64.AppImageRETURN + - + $ + ./mineXpert2-0.7.4-x86_64.AppImageRETURN - +
- + - If the program complains about a locale not being found, please, modify - the command line to read: + - + If the program complains about a locale not being found, please, modify + the command line to read: - + - $ - LC_ALL="C" ./mineXpert2-0.7.4-x86_64.AppImageRETURN + - + $ + LC_ALL="C" ./mineXpert2-0.7.4-x86_64.AppImageRETURN - + -
+ - +
- + - Building the software from source + - + Building the software from source - The &mineXp2; software build is under the control of the - CMake build system. There are a number of - dependencies to install prior to trying to build the software, as - described below. + - + The &mineXp2; software build is under the control of the + CMake build system. There are a number of + dependencies to install prior to trying to build the software, as + described below. - + - The dependencies required to build &minexp2; + - + The dependencies required to build &minexp2; - The dependencies to be installed are listed here with package names - matching the packages that are in Debian/Ubuntu. In - other RPM-based software, most often the package names are similar, albeit - with some slight differences. + - + The dependencies to be installed are listed here with package names + matching the packages that are in Debian/Ubuntu. In + other RPM-based software, most often the package names are similar, albeit + with some slight differences. - Dependencies + - + Dependencies - The build system + - - cmake - + The build system - + + cmake + - + - Conversion of svg files to - png files + - - graphicsmagick-imagemagick-compat - + Conversion of svg files to + png files - + + graphicsmagick-imagemagick-compat + - + - For the parallel computations + - - libgomp1 - + For the parallel computations - + + libgomp1 + - + - For the isotopic cluster calculations + - - libisospec++-dev - + For the isotopic cluster calculations - + + libisospec++-dev + - + - For all the raw mass calculations like the data model, the mass - spectral combinations… + - libpappsomspp-dev, libpappsomspp-widget-dev - + For all the raw mass calculations like the data model, the mass + spectral combinations… - + libpappsomspp-dev, libpappsomspp-widget-dev + - + - For all the plotting + - - libqcustomplot-dev - + For all the plotting - + + libqcustomplot-dev + - + - For the C++ objects (GUI and non-GUI) + - qtbase5-dev, libqt5svg5-dev, - qttools5-dev-tools, qtchooser + For the C++ objects (GUI and non-GUI) - + qtbase5-dev, libqt5svg5-dev, + qttools5-dev-tools, qtchooser - + - For the man page + - - docbook-to-man - + For the man page - + + docbook-to-man + - + - For the documentation (optional, with - as a flag to the call of - cmake, see below.) + - daps, libjeuclid-core-java, -libjeuclid-fop-java, docbook-mathml, libjs-jquery, libjs-highlight.js, -libjs-mathjax, fonts-mathjax, fonts-mathjax-extras, texlive-fonts-extra, -fonts-ebgaramond-extra + For the documentation (optional, with + as a flag to the call of + cmake, see below.) + + daps, libjeuclid-core-java, + libjeuclid-fop-java, docbook-mathml, libjs-jquery, libjs-highlight.js, + libjs-mathjax, fonts-mathjax, fonts-mathjax-extras, texlive-fonts-extra, + fonts-ebgaramond-extra - + @@ -840,15 +861,15 @@ Using git The rather convoluted command below only downloads the branch of - interest. The whole git repos is very large… + interest. The whole git repos is very large… - + - $ git clone - https://gitlab.com/msxpertsuite/minexpert2.git --branch master/7.3.0-1 - --single-branch minexpert2-7.3.0 + $ git clone + https://gitlab.com/msxpertsuite/minexpert2.git --branch master/7.3.0-1 + --single-branch minexpert2-7.3.0 - + @@ -859,24 +880,24 @@ wget - https://gitlab.com/msxpertsuite/minexpert2/-/archive/7.3.0/minexpert2-7.3.0.tar.gz + https://gitlab.com/msxpertsuite/minexpert2/-/archive/7.3.0/minexpert2-7.3.0.tar.gz - + - + - Untar the tarball, which creates the - minexpert2-7.3.0 directory: + Untar the tarball, which creates the + minexpert2-7.3.0 directory: - + - + - tar xvzf minexpert2-7.3.0.tar.gz + tar xvzf minexpert2-7.3.0.tar.gz - + - + diff -Nru minexpert2-7.4.1/doc/user-manual/xml/graphical-user-interface.xml minexpert2-8.1.1/doc/user-manual/xml/graphical-user-interface.xml --- minexpert2-7.4.1/doc/user-manual/xml/graphical-user-interface.xml 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/doc/user-manual/xml/graphical-user-interface.xml 2021-04-26 11:28:25.000000000 +0000 @@ -410,22 +410,22 @@ - + - - Preferences - Set max. thread count - : - - Set the maximum number of execution threads that mass - spectral integrations can use. Note that the program - starts to be really efficient with a number of threads at - least equal to 4 (see ). + + Preferences + Set max. thread count + : + + Set the maximum number of execution threads that mass + spectral integrations can use. Note that the program + starts to be really efficient with a number of threads at + least equal to 4 (see ). - + - + Do not mistake thread for core or processor. When @@ -459,152 +459,152 @@ - + - + - + - + - + - - Help - - + + Help + + - This menu's items show help about the program itself and also - about the Qt libraries that were used to build it. These informations - are essential in case the user wants to make a bug report. + This menu's items show help about the program itself and also + about the Qt libraries that were used to build it. These informations + are essential in case the user wants to make a bug report. - + - + - + - + - + - The Loaded MS Run Data Sets + The Loaded MS Run Data Sets - + -information + information -dissemination + dissemination -oral + oral - + - + - Each time a new MS run data set is loaded from disk or from clipboard, - a corresponding MS run data set item is added to - the Open MS run data sets dialog window (see - ). + Each time a new MS run data set is loaded from disk or from clipboard, + a corresponding MS run data set item is added to + the Open MS run data sets dialog window (see + ). - + -
+
- The open MS run data sets + The open MS run data sets - + - + - - + + - + - + - Each time a new MS run data set is loaded, a corresponding item is - added to the list widget. The drop-down menu lists a number of actions - that can be performed with these items. + Each time a new MS run data set is loaded, a corresponding item is + added to the list widget. The drop-down menu lists a number of actions + that can be performed with these items. - + - + - + -
+
- + - One of the most useful menu items available from the drop-down menu of is the Show - MS run data set table view item. That menu item triggers the - display of a window containing a table view, like in a spreadsheet, that shows - the data of each scan contained in the MS run data set loaded from file. This - window is described in the following section (see ). + One of the most useful menu items available from the drop-down menu of is the Show + MS run data set table view item. That menu item triggers the + display of a window containing a table view, like in a spreadsheet, that shows + the data of each scan contained in the MS run data set loaded from file. This + window is described in the following section (see ). - + -
+
- + - Mass Spectral Data Listing in a Table View + Mass Spectral Data Listing in a Table View - + - From the Open MS run data sets dialog window, it is - possible to select one list widget item corresponding to the data set of - interest and select the Show MS run data set table - view menu item that opens the MS run data set table - view window shown in . + From the Open MS run data sets dialog window, it is + possible to select one list widget item corresponding to the data set of + interest and select the Show MS run data set table + view menu item that opens the MS run data set table + view window shown in . - + -
+
- The table view-based scrutiny of one MS run data set + The table view-based scrutiny of one MS run data set - + - + + + + - - + - - - + - Each MS run data set might be scrutinized through the use of this table - view. Each filtering criterion has a number of data insertion modalities, - described in the text. In this example, the user has set a number of values - in the Filtering options group box but has not yet - executed the filtering, so the full mass spectral data set is listed in the - table view. + Each MS run data set might be scrutinized through the use of this table + view. Each filtering criterion has a number of data insertion modalities, + described in the text. In this example, the user has set a number of values + in the Filtering options group box but has not yet + executed the filtering, so the full mass spectral data set is listed in the + table view. - + - + - +
@@ -775,7 +775,8 @@ - start-end: like before, but the match is inclusive. + start--end: like before, but the match is + inclusive. Mind the double-dash that delimits the values of the range. @@ -1589,7 +1590,7 @@ fragmentation specification setting dialog window ( at ). - + @@ -1977,62 +1978,89 @@ Set Z axis scale to log10: Recompute all - the intensities by calculating thew intensity as the log10 of the + the intensities by calculating the new intensity as the log10 of the original intensity. - + - + When the log10 scale is applied to the intensities of the previous color + map plot, where almost no signal was visible, then the signal is made + perfectly visible." - + - Reset Z axis scale to original: Reset the - intensities of the color map to the original values that the color map - had when it was first created. +
- + Color map plot widget main menu - + + + + + + + - + - When the log10 scale is applied to the intensities of the previous color - map plot, where almost no signal was visible, then the signal is made - perfectly visible." + - + The switch to a log10 scale for the intensities might reveal a + lot of missing signal when the intensities are used in a linear + scale. The drawback is that noise can be hugely enhanced. See + below for a way to reduce that noise. -
+ - Color map plot widget main menu - + - - - - - - + - +
- - The switch to a log10 scale for the intensities might reveal a lot - of missing signal when the intensities are used in a linear scale. + - + + - + Low pass-filter Z axis data: The value that + is entered in the input box that is shown is a + percentage of the maximum intensity over the + whole map. The function first computes a threshold using the formula + threshold = percentage * max_int / 100. + All the cells having an intensity value above that threshold have + their value set to that threshold value. All other cells are + unchanged. This function is used to reduce the dynamic range of the + map and potentially enhance features of interest. -
+ -
+ + + + + + + High pass-filter Z axis data: The value + that is entered in the input box that is shown is a + percentage of the maximum intensity over the + whole map. The function first computes a threshold using the formula + threshold = percentage * max_int / 100. + All the cells having an intensity value below that threshold have + their value set to that threshold value. All other cells are + unchanged. This function is typically used for removing noise. + + + + + + diff -Nru minexpert2-7.4.1/doc/user-manual/xml/mass-data-integrations.xml minexpert2-8.1.1/doc/user-manual/xml/mass-data-integrations.xml --- minexpert2-7.4.1/doc/user-manual/xml/mass-data-integrations.xml 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/doc/user-manual/xml/mass-data-integrations.xml 2021-04-26 11:28:25.000000000 +0000 @@ -981,7 +981,7 @@ The same mechanics is at work in the other plot widget windows. For - example, to trigger the integration of any kind of plot to a + example, to trigger the integration of any kind of plot to an intensity = f(dt,&mz;) color map, simply check the &integrate-to-dt-mz-check-button; button and drag the mouse over the plot region of interest. @@ -1105,6 +1105,288 @@ + + + + Integrations Originating in Color Map Plots + + + + There are two different kinds of plots: the trace plots and + the color map plots. TIC chromatograms, mass spectra and + drift spectra are trace plots. Color map plots plot intensity values as + colors for pairs of data, like mass spectra as a function of retention times + or drift times, or retention times as a function of drift times. + + + + + + When an integration starts from a trace plot, the integration region + selection (with a right-button mouse drag operation) of a given plot range + (over the X axis) can be performed without drawing a rectangle over the + region of interest. Indeed, only the X axis is the criterion for the + selection of the region of interest. When an integration starts from a color + map plot, the second dimension (the Y axis) has a meaning for the selection + of the region of interest. In color map plots, the selection region has to + be bi-dimensional, that is, not a horizontal line, but a real rectangle over + both the X and the Y axes. + + + + + + By default, the rectangle that is drawn upon mouse dragging is a real + rectangle, that is, a four-square-corner polygon. There are a number of + situations, however, where the user might want to select a non-rectangle + region, like if the rectangle were skewed. This is illustrated in + + + + + + Drawing a skewed selection rectangle is a two-step process. One first draws + the base of the rectangle, as usual, with a horizontal-only mouse drag + movement (see ). + When the base of the rectangle has the right width, the user presses the + S keyboard key. Pressing that keyboard key triggers the + definition of the width of the skewed selection rectangle, that gets stored + in memory. + + + + +
+ + Integrations from a color map plot using a skewed selection rectangle (first step) + + + + + + + + + + + + + + + + The first step in the definition of a skewed selection rectangle is to + right-button-drag the mouse along the X axis in order to draw a + selection line that has the final skewed rectangle width. Once the + width is properly defined, the user presses the S + keyboard key, which stores the rectangle width in memory. + + + + + + + +
+ + + + + When the mouse drag operation draws the actual two-dimensional polygon (by + dragging the mouse cursor also along the Y axis), the user maintains + the Alt keyboard key pressed. Maintaing that key pressed + has the effect of switching the drawing of a conventional four-square-corner + selection rectangle into a skewed selection rectangle (see ). + + + + +
+ + Integrations from a color map plot using a skewed selection rectangle (last step) + + + + + + + + + + + + + + + + The last step in the definition of a skewed selection rectangle is to + drag the right mouse button over a bi-dimensional space (that is, also + along the Y axis) while maintaining the Alt + modifier key pressed. The rectangle that is drawn is now skewed, in + contrast to a normal square-corner rectangle. + + + + + + + +
+ + + + + When the mouse right-button is released, the integration computation is + started that involves checking if the points that are processed are indeed + contained inside the skewed selection rectangle. The result is shown in + . + + + + +
+ + Integrations from a color map plot using a skewed selection rectangle (first step) + + + + + + + + + + + + + + + + The result of a skewed selection rectangle-based integration is + inherently of the shape of the selection. + + + + + + + +
+ +
+ + + + + Noise Reduction in Color Map Plots + + + + The signal obtained in ion mobility–mass spectrometry experiments may + be of a very wide dynamics, which hamper proper visualization of details. + One solution is to run a Z axis scale (the axis holding intensity values) + conversion from linear scale to log10 scale (see ). While this + has the benefit of highlighting details, it also has the drawback of + potently enhancing noise. As of version 8.1.0, &mineXp2; provides means to + signal-to-noise ratio tweaking as detailed below. + + + + + + There are two different approaches to signal-to-noise ratio enhancement: + + + + + + + + + + Low pass-filter Z axis data: The value that is + entered in the spin box widget is a percentage of the + maximum intensity over the whole map. The function first computes a + threshold using the formula + threshold = percentage * max_int / 100. All + the cells having an intensity value above that threshold have their value + set to that threshold value. All other cells are unchanged. This function + is used to reduce the dynamic range of the map and potentially enhance + features of interest. + + + + + + + + + + High pass-filter Z axis data: The value + that is entered in the spin box widget is a + percentage of the maximum intensity over the + whole map. The function first computes a threshold using the formula + threshold = percentage * max_int / 100. + All the cells having an intensity value below that threshold have + their value set to that threshold value. All other cells are + unchanged. + + + + + + This function is typically used for removing noise. Indeed, by setting + the percentage value to 5, for example, all the cells having a pretty + low intensity value (that is, below 5 % of the maximum intensity + value in the whole map data) will be set to that value. An example is + provided in . + + + + + + + +
+ + Example of signal-to-noise ratio enhancement + + + + + + + + + + + + + + + + + + The top left vignette shows the colormap as it is computed. The top right + vignette show that colormap after a log10 recomputation has been + performed. The remaining vignettes correspond to the application of a + high pass filter with percentage values increasing from 10 to 40 in + 10 % increments. + + + + + + +
+ + +
+ diff -Nru minexpert2-7.4.1/doc/user-manual/xml/revision-history.xml minexpert2-8.1.1/doc/user-manual/xml/revision-history.xml --- minexpert2-7.4.1/doc/user-manual/xml/revision-history.xml 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/doc/user-manual/xml/revision-history.xml 2021-04-26 11:28:25.000000000 +0000 @@ -14,6 +14,90 @@ + + 8.1.0 + 21 April 2021 + fr + + + + + + + + Update the user manual with the description of the new color map filters used to enhance the signal-to-noise ratio. + + + + + + + + + + + + 8.0.1 + 24 march 2021 + fr + + + + + + + + Update the user manual with a more explicit data set to illustrate the new skewed + selection polygon. + + + + + + Mention the bibliographic reference to the newly accepted article + about &mineXp2; in the Generalities chapter. + + + + + + + + + + + + 8.0.0 + 23 march 2021 + fr + + + + + + + + Update the user manual with a section pertaining to the new skewed + selection polygon. That feature was asked months ago by a user of + &mineXp2; and could finally be implemented these last weeks. + + + + + + Mention the bibliographic reference to the newly accepted article + about &mineXp2; in the Generalities chapter. + + + + + + + + + + + 7.4.0 2 january 2021 fr @@ -32,6 +116,7 @@ + 7.4.0 december 2020 fr diff -Nru minexpert2-7.4.1/doc/user-manual/xml/user-manual-version-entity.ent minexpert2-8.1.1/doc/user-manual/xml/user-manual-version-entity.ent --- minexpert2-7.4.1/doc/user-manual/xml/user-manual-version-entity.ent 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/doc/user-manual/xml/user-manual-version-entity.ent 2021-04-26 11:28:25.000000000 +0000 @@ -1,2 +1,2 @@ - + diff -Nru minexpert2-7.4.1/images/addresses_backup.svg minexpert2-8.1.1/images/addresses_backup.svg --- minexpert2-7.4.1/images/addresses_backup.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/addresses_backup.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - msxpertsuite-maintainer@msxpertsuite.org - msxpertsuite-bugs@msxpertsuite.org - msxpertsuite-webmaster@msxpertsuite.org - msxpertsuite-request@msxpertsuite.org - - diff -Nru minexpert2-7.4.1/images/addresses.svg minexpert2-8.1.1/images/addresses.svg --- minexpert2-7.4.1/images/addresses.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/addresses.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,225 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - maintainer@msxpertsuite.org - bugs@msxpertsuite.org - webmaster@msxpertsuite.org - request@msxpertsuite.org - announce@msxpertsuite.org - git-commits@msxpertsuite.org - = general mailing list about msXpertSuite - = announcements to all msXpertSuite users - = feature requests for msXpertSuite developers - = report bugs found in msXpertSuite software - = documents the git activity in msXpertSuite software - = about the msxpertsuite.org website - - diff -Nru minexpert2-7.4.1/images/erase-trace-and-create-new-one.svg minexpert2-8.1.1/images/erase-trace-and-create-new-one.svg --- minexpert2-7.4.1/images/erase-trace-and-create-new-one.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/erase-trace-and-create-new-one.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - diff -Nru minexpert2-7.4.1/images/greenled.svg minexpert2-8.1.1/images/greenled.svg --- minexpert2-7.4.1/images/greenled.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/greenled.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/images/icons/32x32/html-file-icon-32x32.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/images/icons/32x32/html-file-icon-32x32.png differ Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/images/icons/32x32/minexpert2-icon-32x32.tiff and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/images/icons/32x32/minexpert2-icon-32x32.tiff differ diff -Nru minexpert2-7.4.1/images/icons/32x32/minexpert2-icon-32x32.xpm minexpert2-8.1.1/images/icons/32x32/minexpert2-icon-32x32.xpm --- minexpert2-7.4.1/images/icons/32x32/minexpert2-icon-32x32.xpm 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/icons/32x32/minexpert2-icon-32x32.xpm 1970-01-01 00:00:00.000000000 +0000 @@ -1,671 +0,0 @@ -/* XPM */ -static char * massxpert_icon_32_xpm[] = { -"32 32 636 2", -" c None", -". c #25B060", -"+ c #2BB163", -"@ c #2BAE61", -"# c #40AF72", -"$ c #0DA550", -"% c #41A76C", -"& c #259F56", -"* c #06A949", -"= c #3EAB6A", -"- c #28AB5C", -"; c #06A547", -"> c #17994B", -", c #059D45", -"' c #1AA856", -") c #49A972", -"! c #13A657", -"~ c #99B6A6", -"{ c #9BA69E", -"] c #B7BEB9", -"^ c #32985E", -"/ c #05A847", -"( c #10A249", -"_ c #05A044", -": c #86AC96", -"< c #BAC0BC", -"[ c #A3B3A8", -"} c #1C9751", -"| c #27A55A", -"1 c #22A55B", -"2 c #4BA172", -"3 c #6B746E", -"4 c #272928", -"5 c #848A86", -"6 c #8BA999", -"7 c #03A545", -"8 c #00A63F", -"9 c #459565", -"0 c #49514A", -"a c #373B38", -"b c #989F99", -"c c #7BA38B", -"d c #16A252", -"e c #0FA44E", -"f c #7CA58F", -"g c #444945", -"h c #3E4043", -"i c #4F534B", -"j c #90A296", -"k c #11A051", -"l c #00A341", -"m c #658675", -"n c #1B1E1B", -"o c #585D59", -"p c #656B63", -"q c #ADB3AC", -"r c #1D9E56", -"s c #2B9B57", -"t c #2F9657", -"u c #0AA24A", -"v c #95A9A0", -"w c #747777", -"x c #666E79", -"y c #555652", -"z c #9FB3A6", -"A c #139E53", -"B c #039E41", -"C c #859F94", -"D c #43464A", -"E c #7C7F90", -"F c #767570", -"G c #B3B5AF", -"H c #2E9E61", -"I c #20994F", -"J c #21934B", -"K c #03A247", -"L c #8EA69B", -"M c #BAC2C0", -"N c #B8BFC0", -"O c #BBC1BF", -"P c #89A795", -"Q c #0AA14A", -"R c #03A03F", -"S c #7FA092", -"T c #B3B9B9", -"U c #A6ABB0", -"V c #B9BCBB", -"W c #AAAEA5", -"X c #249B58", -"Y c #1D974B", -"Z c #1D9148", -"` c #00A444", -" . c #61987A", -".. c #AEB9B6", -"+. c #B7C1BE", -"@. c #B1BFB9", -"#. c #569473", -"$. c #01A543", -"%. c #00A43E", -"&. c #589176", -"*. c #B0BDB9", -"=. c #BAC3C0", -"-. c #B6BAB7", -";. c #90A08F", -">. c #0E9C4A", -",. c #109442", -"'. c #148E41", -"). c #00A140", -"!. c #239557", -"~. c #80A393", -"{. c #9CB4AB", -"]. c #81A795", -"^. c #208E53", -"/. c #01A23E", -"(. c #248955", -"_. c #8BAD9F", -":. c #A6B7B1", -"<. c #99AA9E", -"[. c #4D8E63", -"}. c #019F3D", -"|. c #0A913D", -"1. c #098E3B", -"2. c #019C3E", -"3. c #05A249", -"4. c #218D54", -"5. c #3E956A", -"6. c #28965C", -"7. c #12A04E", -"8. c #07A244", -"9. c #0DA34C", -"0. c #189D52", -"a. c #40916A", -"b. c #4F906F", -"c. c #398355", -"d. c #0B9641", -"e. c #009A37", -"f. c #068F39", -"g. c #65A481", -"h. c #359F64", -"i. c #23A05A", -"j. c #27A25D", -"k. c #17A152", -"l. c #0BA049", -"m. c #019D3C", -"n. c #00A03B", -"o. c #00A23B", -"p. c #01A23C", -"q. c #05A141", -"r. c #1AA053", -"s. c #239A56", -"t. c #079B42", -"u. c #0F9E48", -"v. c #159A4C", -"w. c #19954C", -"x. c #3D9560", -"y. c #5EA980", -"z. c #3CA469", -"A. c #25A159", -"B. c #1FA056", -"C. c #1CA154", -"D. c #059E44", -"E. c #019F40", -"F. c #00A23D", -"G. c #00A33B", -"H. c #00A43C", -"I. c #00A43D", -"J. c #00A33C", -"K. c #04A03E", -"L. c #1CA152", -"M. c #29A15C", -"N. c #32A061", -"O. c #31A060", -"P. c #329E61", -"Q. c #3A9C64", -"R. c #59A075", -"S. c #69A885", -"T. c #36A465", -"U. c #0CA04B", -"V. c #049F43", -"W. c #049D43", -"X. c #049D44", -"Y. c #029E43", -"Z. c #019F42", -"`. c #00A141", -" + c #00A13A", -".+ c #009E39", -"++ c #109E46", -"@+ c #269F5A", -"#+ c #279E5B", -"$+ c #2A9E5B", -"%+ c #2C9F5E", -"&+ c #359E62", -"*+ c #4C9F6E", -"=+ c #5EA57E", -"-+ c #1AA153", -";+ c #01A143", -">+ c #01A043", -",+ c #039E43", -"'+ c #039D42", -")+ c #039C42", -"!+ c #029E42", -"~+ c #01A344", -"{+ c #00A33A", -"]+ c #00A23C", -"^+ c #00A13B", -"/+ c #00A03A", -"(+ c #009D38", -"_+ c #009A36", -":+ c #06993B", -"<+ c #1F9C53", -"[+ c #1A9B4E", -"}+ c #029738", -"|+ c #0B9A41", -"1+ c #1F9D52", -"2+ c #3A9C63", -"3+ c #609F79", -"4+ c #61A47E", -"5+ c #16A051", -"6+ c #03A245", -"7+ c #02A445", -"8+ c #03A246", -"9+ c #029D41", -"0+ c #009836", -"a+ c #009937", -"b+ c #019E41", -"c+ c #02A045", -"d+ c #03A347", -"e+ c #00A23F", -"f+ c #00A039", -"g+ c #00A139", -"h+ c #009F38", -"i+ c #009D37", -"j+ c #009734", -"k+ c #019434", -"l+ c #009533", -"m+ c #09993E", -"n+ c #2A9A57", -"o+ c #599971", -"p+ c #74A389", -"q+ c #1B9A4E", -"r+ c #03A147", -"s+ c #05A449", -"t+ c #08A44A", -"u+ c #07A249", -"v+ c #009735", -"w+ c #009531", -"x+ c #009731", -"y+ c #009B39", -"z+ c #04A047", -"A+ c #04A248", -"B+ c #01A242", -"C+ c #009F36", -"D+ c #009F37", -"E+ c #009E35", -"F+ c #009E36", -"G+ c #009C36", -"H+ c #009935", -"I+ c #009633", -"J+ c #009432", -"K+ c #009231", -"L+ c #009332", -"M+ c #009936", -"N+ c #059538", -"O+ c #2B9554", -"P+ c #459968", -"Q+ c #019735", -"R+ c #08A249", -"S+ c #09A44B", -"T+ c #1EA85C", -"U+ c #08943D", -"V+ c #008E2D", -"W+ c #00922F", -"X+ c #00952F", -"Y+ c #04A048", -"Z+ c #04A147", -"`+ c #02A144", -" @ c #029F3C", -".@ c #069F44", -"+@ c #039E3E", -"@@ c #019D37", -"#@ c #009C33", -"$@ c #009C34", -"%@ c #009934", -"&@ c #009331", -"*@ c #009230", -"=@ c #008F2F", -"-@ c #04943B", -";@ c #019634", -">@ c #009333", -",@ c #09903A", -"'@ c #398E57", -")@ c #158E41", -"!@ c #08A14A", -"~@ c #03A142", -"{@ c #51B584", -"]@ c #048833", -"^@ c #007725", -"/@ c #008929", -"(@ c #00912C", -"_@ c #009835", -":@ c #069E47", -"<@ c #049C43", -"[@ c #219F59", -"}@ c #279F5D", -"|@ c #1B9C51", -"1@ c #069A43", -"2@ c #059B3E", -"3@ c #099D40", -"4@ c #029937", -"5@ c #019432", -"6@ c #009131", -"7@ c #008C2D", -"8@ c #007D24", -"9@ c #098436", -"0@ c #30A262", -"a@ c #089539", -"b@ c #008C30", -"c@ c #1C8942", -"d@ c #66987A", -"e@ c #038A2F", -"f@ c #019636", -"g@ c #0C9F49", -"h@ c #089E41", -"i@ c #3AAF70", -"j@ c #009637", -"k@ c #017D2D", -"l@ c #006319", -"m@ c #00711B", -"n@ c #007D22", -"o@ c #008125", -"p@ c #007E23", -"q@ c #00781E", -"r@ c #006D1A", -"s@ c #006A18", -"t@ c #006C19", -"u@ c #00751D", -"v@ c #007F21", -"w@ c #008626", -"x@ c #018829", -"y@ c #038427", -"z@ c #017920", -"A@ c #006517", -"B@ c #046721", -"C@ c #179349", -"D@ c #49AC79", -"E@ c #339D55", -"F@ c #0A9139", -"G@ c #028A2F", -"H@ c #0B8534", -"I@ c #418355", -"J@ c #4F9068", -"K@ c #008729", -"L@ c #009434", -"M@ c #019939", -"N@ c #009838", -"O@ c #099240", -"P@ c #016322", -"Q@ c #004D17", -"R@ c #004E13", -"S@ c #005012", -"T@ c #004911", -"U@ c #023D10", -"V@ c #043810", -"W@ c #033D10", -"X@ c #004A11", -"Y@ c #005512", -"Z@ c #005A13", -"`@ c #005913", -" # c #005411", -".# c #004811", -"+# c #015319", -"@# c #1A8D4B", -"## c #038A32", -"$# c #119444", -"%# c #068F31", -"&# c #0B8F38", -"*# c #168B39", -"=# c #057F2A", -"-# c #357D4A", -";# c #488C62", -"># c #008327", -",# c #008D2C", -"'# c #00932E", -")# c #019835", -"!# c #009632", -"~# c #008E32", -"{# c #018F35", -"]# c #006523", -"^# c #004C15", -"/# c #003E10", -"(# c #003A10", -"_# c #08250E", -":# c #1D1811", -"<# c #3C3434", -"[# c #292320", -"}# c #0E1F0E", -"|# c #02340F", -"1# c #003C10", -"2# c #004614", -"3# c #01551B", -"4# c #058730", -"5# c #008531", -"6# c #008326", -"7# c #008828", -"8# c #008827", -"9# c #01862A", -"0# c #0C8634", -"a# c #037B27", -"b# c #317945", -"c# c #4C8A64", -"d# c #008A27", -"e# c #008E29", -"f# c #00912D", -"g# c #01963B", -"h# c #008D2F", -"i# c #009738", -"j# c #018834", -"k# c #017E2C", -"l# c #007422", -"m# c #006921", -"n# c #291E14", -"o# c #5E0D14", -"p# c #74131F", -"q# c #680D16", -"r# c #540B10", -"s# c #0F3B17", -"t# c #005B1A", -"u# c #00681E", -"v# c #007427", -"w# c #0A903A", -"x# c #00842B", -"y# c #00852A", -"z# c #00872A", -"A# c #008223", -"B# c #008024", -"C# c #007B23", -"D# c #007321", -"E# c #317443", -"F# c #558868", -"G# c #007421", -"H# c #008325", -"I# c #008B29", -"J# c #008D2A", -"K# c #00912F", -"L# c #008F31", -"M# c #008F2B", -"N# c #009B38", -"O# c #018838", -"P# c #008B2D", -"Q# c #00892A", -"R# c #18481D", -"S# c #5E0910", -"T# c #710D13", -"U# c #730B12", -"V# c #5D0D0F", -"W# c #047325", -"X# c #008526", -"Y# c #00822A", -"Z# c #017F26", -"`# c #089334", -" $ c #048831", -".$ c #008228", -"+$ c #007D21", -"@$ c #007A20", -"#$ c #016E1E", -"$$ c #376F44", -"%$ c #0A6C27", -"&$ c #007921", -"*$ c #008224", -"=$ c #008A28", -"-$ c #009530", -";$ c #018835", -">$ c #027D28", -",$ c #352819", -"'$ c #5A0F12", -")$ c #550F10", -"!$ c #1F421A", -"~$ c #008527", -"{$ c #008528", -"]$ c #01812B", -"^$ c #038E2A", -"/$ c #0F923A", -"($ c #007F23", -"_$ c #007A1F", -":$ c #00771E", -"<$ c #00741C", -"[$ c #006F1B", -"}$ c #04651E", -"|$ c #406C46", -"1$ c #327246", -"2$ c #006C1C", -"3$ c #008123", -"4$ c #008426", -"5$ c #008628", -"6$ c #008525", -"7$ c #008A26", -"8$ c #009A31", -"9$ c #019231", -"0$ c #05893B", -"a$ c #008B33", -"b$ c #008229", -"c$ c #036D24", -"d$ c #037023", -"e$ c #008429", -"f$ c #00862E", -"g$ c #01842D", -"h$ c #008D27", -"i$ c #0D983B", -"j$ c #008021", -"k$ c #007A1E", -"l$ c #007B21", -"m$ c #00701A", -"n$ c #006B19", -"o$ c #105A21", -"p$ c #065C1E", -"q$ c #006D1D", -"r$ c #007721", -"s$ c #007D23", -"t$ c #008023", -"u$ c #007E22", -"v$ c #007C21", -"w$ c #008122", -"x$ c #008B26", -"y$ c #009931", -"z$ c #008F2C", -"A$ c #008830", -"B$ c #008631", -"C$ c #008630", -"D$ c #008732", -"E$ c #008530", -"F$ c #008D28", -"G$ c #00952E", -"H$ c #008422", -"I$ c #00771D", -"J$ c #00761D", -"K$ c #00731C", -"L$ c #006E1A", -"M$ c #006718", -"N$ c #006115", -"O$ c #005314", -"P$ c #24572D", -"Q$ c #336343", -"R$ c #015617", -"S$ c #00691B", -"T$ c #00711D", -"U$ c #00781F", -"V$ c #00721C", -"W$ c #007C1F", -"X$ c #008623", -"Y$ c #009532", -"Z$ c #029233", -"`$ c #008A2C", -" % c #008829", -".% c #00922C", -"+% c #008120", -"@% c #00731B", -"#% c #006F1A", -"$% c #00701B", -"%% c #006C1A", -"&% c #006417", -"*% c #005A14", -"=% c #004C13", -"-% c #16461F", -";% c #275233", -">% c #024D16", -",% c #005F18", -"'% c #006A1B", -")% c #006E1C", -"!% c #00691A", -"~% c #006819", -"{% c #006D1B", -"]% c #007B1E", -"^% c #04882D", -"/% c #09923C", -"(% c #0B9540", -"_% c #07943B", -":% c #029032", -"<% c #00761B", -"[% c #006B18", -"}% c #006716", -"|% c #006416", -"1% c #005F16", -"2% c #005113", -"3% c #024112", -"4% c #163D1C", -"5% c #1D4225", -"6% c #093B16", -"7% c #014814", -"8% c #005616", -"9% c #005715", -"0% c #005214", -"a% c #005714", -"b% c #006016", -"c% c #006A19", -"d% c #00721B", -"e% c #006E19", -"f% c #006616", -"g% c #006014", -"h% c #005412", -"i% c #005613", -"j% c #004F13", -"k% c #014112", -"l% c #073212", -"m% c #203A22", -"n% c #133119", -"o% c #0B3215", -"p% c #033B12", -"q% c #013E12", -"r% c #003E12", -"s% c #004512", -"t% c #005814", -"u% c #005912", -"v% c #005812", -"w% c #005711", -"x% c #005111", -"y% c #014110", -"z% c #023C11", -"A% c #033910", -"B% c #063210", -"C% c #123016", -"D% c #223722", -"E% c #122F18", -"F% c #043412", -"G% c #013C11", -"H% c #003C11", -"I% c #003D11", -"J% c #004010", -"K% c #004210", -"L% c #004110", -"M% c #00380F", -"N% c #01350F", -"O% c #013610", -"P% c #03310F", -"Q% c #112A14", -"R% c #003B10", -"S% c #003910", -" . + @ ", -" # $ % & * = - ; > , ' ", -" ) ! ~ { ] ^ / ( _ : < [ } | ", -" 1 2 3 4 5 6 7 8 9 0 a b c d ", -" e f g h i j k l m n o p q r s ", -" t u v w x y z A B C D E F G H I ", -" J K L M N O P Q R S T U V W X Y ", -" Z ` ...+.@.#.$.%.&.*.=.-.;.>.,. ", -" '.).!.~.{.].^././.(._.:.<.[.}.|. ", -" 1.2.3.4.5.6.7.8.9.0.a.b.c.d.e.f. ", -" g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x. ", -" y.z.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R. ", -" S.T.U.V.W.X.Y.Z.`.F.G.H.J.J. +.+++@+#+$+%+&+*+ ", -" =+-+;+>+,+'+)+!+>+~+F.{+]+]+^+/+(+_+:+<+[+}+|+1+2+3+ ", -" 4+5+6+7+8+9+0+a+b+c+d+e+f+g+g+f+h+i+_+j+k+k+l+0+0+m+n+o+ ", -" p+q+r+s+t+u+v+w+x+y+z+A+B+C+D+E+E+F+G+H+I+J+K+L+v+M+j+N+O+ ", -" P+Q+R+S+T+U+V+W+X+M+Y+Z+`+ @.@+@@@#@$@%@I+&@*@=@-@;@I+>@,@'@ ", -" )@j+!@~@{@]@^@/@(@_@:@2.<@[@}@|@1@2@3@4@5@6@7@8@9@0@a@6@b@c@ ", -"d@e@f@g@h@i@j@k@l@m@n@o@p@q@r@s@t@u@v@w@x@y@z@A@B@C@D@E@F@G@H@I@", -"J@K@L@M@e.N@&@O@P@Q@R@S@S@T@U@V@W@X@Y@Z@`@ #.#+#@###$#%#&#*#=#-#", -";#>#,#'#)#!#(@~#{#]#^#/#(#_#:#<#[#}#|#1#1#2#3#4#5#6#7#8#9#0#a#b#", -"c#8@d#e#f#j@g#h#i#j#k#l#m#n#o#p#q#r#s#t#u#v#p@w#x#y#z#A#B#C#D#E#", -"F#G#H#8#I#J#K#L#M#N#O#P#Q#R#S#T#U#V#W#X#Y#Z#`# $.$p@p@+$@$u@#$$$", -" %$&$*$w@Q#=$/@=$-$I+;$7@>$,$'$)$!$~${$]$^$/$($p@n@_$:$<$[$}$|$", -" 1$2$&$3$4$5$4$6$7$8$9$0$a$b$c$d$e$f$g$h$i$j$k$l$q@<$m$n$A@o$ ", -" p$q$r$s$t$u$v$w$x$y$z$A$B$C$D$E$y#F$G$H$I$J$:$K$L$M$N$O$P$ ", -" Q$R$S$T$&$U$V$J$W$X$Y$Z$`$z#z# %z$.%+%@%#%#%$%%%&%*%=%-% ", -" ;%>%,%'%)%!%~%{%V$]%^%/%(%_%:%6$<%[%}%|%A@A@1%2%3%4% ", -" 5%6%7%8%9%0%a%b%A@c%$%V$d%e%f%g%Z@Y@h%i%j%k%l%m% ", -" n%o%p%q%r%s%2%t%Z@u%v%w%x%X@y%z%A%B%C%D% ", -" E%F%G%H%I%J%K%K%L%/#M%N%O%P%Q% ", -" H%R%S% "}; Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/images/icons/32x32/pdf-file-icon-32x32.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/images/icons/32x32/pdf-file-icon-32x32.png differ diff -Nru minexpert2-7.4.1/images/icons/svg/help-information-icon.svg minexpert2-8.1.1/images/icons/svg/help-information-icon.svg --- minexpert2-7.4.1/images/icons/svg/help-information-icon.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/icons/svg/help-information-icon.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ - - - PDF file icon - - - - - - - - - - image/svg+xml - - PDF file icon - 08/10/2018 - - - Adobe Systems - - - - - CMetalCore - - - Fuente del texto "PDF": -Franklin Gothic Medium Cond - - - - - - - - - - - - - - - - - - - - - - diff -Nru minexpert2-7.4.1/images/icons/svg/help-qt-information-icon.svg minexpert2-8.1.1/images/icons/svg/help-qt-information-icon.svg --- minexpert2-7.4.1/images/icons/svg/help-qt-information-icon.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/icons/svg/help-qt-information-icon.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ - - - PDF file icon - - - - - - - - - - image/svg+xml - - PDF file icon - 08/10/2018 - - - Adobe Systems - - - - - CMetalCore - - - Fuente del texto "PDF": -Franklin Gothic Medium Cond - - - - - - - - - - - - - - - - - - - - - - diff -Nru minexpert2-7.4.1/images/icons/svg/html-file-icon.svg minexpert2-8.1.1/images/icons/svg/html-file-icon.svg --- minexpert2-7.4.1/images/icons/svg/html-file-icon.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/icons/svg/html-file-icon.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,179 +0,0 @@ - - - PDF file icon - - - - - - - - - - image/svg+xml - - PDF file icon - 08/10/2018 - - - Adobe Systems - - - - - CMetalCore - - - Fuente del texto "PDF": -Franklin Gothic Medium Cond - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru minexpert2-7.4.1/images/icons/svg/pdf-file-icon.svg minexpert2-8.1.1/images/icons/svg/pdf-file-icon.svg --- minexpert2-7.4.1/images/icons/svg/pdf-file-icon.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/icons/svg/pdf-file-icon.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,151 +0,0 @@ - - - PDF file icon - - - - - - - - - - image/svg+xml - - PDF file icon - 08/10/2018 - - - Adobe Systems - - - - - CMetalCore - - - Fuente del texto "PDF": -Franklin Gothic Medium Cond - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru minexpert2-7.4.1/images/lock-xy-ranges.svg minexpert2-8.1.1/images/lock-xy-ranges.svg --- minexpert2-7.4.1/images/lock-xy-ranges.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/lock-xy-ranges.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,457 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru minexpert2-7.4.1/images/logo.svg minexpert2-8.1.1/images/logo.svg --- minexpert2-7.4.1/images/logo.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/logo.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,260 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - Simulating - Analyzing - TM - and - Flying Species - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru minexpert2-7.4.1/images/mobile-phone-like-menu-button.svg minexpert2-8.1.1/images/mobile-phone-like-menu-button.svg --- minexpert2-7.4.1/images/mobile-phone-like-menu-button.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/mobile-phone-like-menu-button.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff -Nru minexpert2-7.4.1/images/ms-level.svg minexpert2-8.1.1/images/ms-level.svg --- minexpert2-7.4.1/images/ms-level.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/ms-level.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - 2 - - - - 1 - - - - 3 - - - diff -Nru minexpert2-7.4.1/images/plot-widget-help.svg minexpert2-8.1.1/images/plot-widget-help.svg --- minexpert2-7.4.1/images/plot-widget-help.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/plot-widget-help.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,451 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ? - diff -Nru minexpert2-7.4.1/images/red-cross-cancel.svg minexpert2-8.1.1/images/red-cross-cancel.svg --- minexpert2-7.4.1/images/red-cross-cancel.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/red-cross-cancel.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - diff -Nru minexpert2-7.4.1/images/redled.svg minexpert2-8.1.1/images/redled.svg --- minexpert2-7.4.1/images/redled.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/redled.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - diff -Nru minexpert2-7.4.1/images/smileys.svg minexpert2-8.1.1/images/smileys.svg --- minexpert2-7.4.1/images/smileys.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/smileys.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - Binary files /tmp/tmpgv6tck5n/IygAPIIXDF/minexpert2-7.4.1/images/splashscreen.png and /tmp/tmpgv6tck5n/YoBKRUe0VJ/minexpert2-8.1.1/images/splashscreen.png differ diff -Nru minexpert2-7.4.1/images/splashscreen.svg minexpert2-8.1.1/images/splashscreen.svg --- minexpert2-7.4.1/images/splashscreen.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/splashscreen.svg 2021-04-26 11:28:25.000000000 +0000 @@ -161,6 +161,6 @@ id="tspan831" x="392.0386" y="984.63959" - style="stroke-width:0.39535946px">version 7.4.1 + style="stroke-width:0.39535946px">version 8.0.3 diff -Nru minexpert2-7.4.1/images/svg/add-isotope.svg minexpert2-8.1.1/images/svg/add-isotope.svg --- minexpert2-7.4.1/images/svg/add-isotope.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/add-isotope.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,68 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/addresses_backup.svg minexpert2-8.1.1/images/svg/addresses_backup.svg --- minexpert2-7.4.1/images/svg/addresses_backup.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/addresses_backup.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,109 @@ + + + + + + + + + + image/svg+xml + + + + + + msxpertsuite-maintainer@msxpertsuite.org + msxpertsuite-bugs@msxpertsuite.org + msxpertsuite-webmaster@msxpertsuite.org + msxpertsuite-request@msxpertsuite.org + + diff -Nru minexpert2-7.4.1/images/svg/addresses.svg minexpert2-8.1.1/images/svg/addresses.svg --- minexpert2-7.4.1/images/svg/addresses.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/addresses.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,225 @@ + + + + + + + + + + image/svg+xml + + + + + + maintainer@msxpertsuite.org + bugs@msxpertsuite.org + webmaster@msxpertsuite.org + request@msxpertsuite.org + announce@msxpertsuite.org + git-commits@msxpertsuite.org + = general mailing list about msXpertSuite + = announcements to all msXpertSuite users + = feature requests for msXpertSuite developers + = report bugs found in msXpertSuite software + = documents the git activity in msXpertSuite software + = about the msxpertsuite.org website + + diff -Nru minexpert2-7.4.1/images/svg/all-trace-plot-widget-icons.svg minexpert2-8.1.1/images/svg/all-trace-plot-widget-icons.svg --- minexpert2-7.4.1/images/svg/all-trace-plot-widget-icons.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/all-trace-plot-widget-icons.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,1311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MZ + + + + + DT + + + + + RT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MZ + + DT + + + + + MZ + + RT + + + + + INT + + + + + DT + + RT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Openclipart + + + + 2010-10-06T22:33:25 + Push pin icon + https://openclipart.org/detail/89059/push-pin-icon-by-jhnri4 + + + jhnri4 + + + + + icon + needle + post + push pin + pushpin + red + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/close-trace-plot-widget.svg minexpert2-8.1.1/images/svg/close-trace-plot-widget.svg --- minexpert2-7.4.1/images/svg/close-trace-plot-widget.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/close-trace-plot-widget.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,80 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/duplicate-trace.svg minexpert2-8.1.1/images/svg/duplicate-trace.svg --- minexpert2-7.4.1/images/svg/duplicate-trace.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/duplicate-trace.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,114 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/erase-trace-and-create-new-one.svg minexpert2-8.1.1/images/svg/erase-trace-and-create-new-one.svg --- minexpert2-7.4.1/images/svg/erase-trace-and-create-new-one.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/erase-trace-and-create-new-one.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,116 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/greenled.svg minexpert2-8.1.1/images/svg/greenled.svg --- minexpert2-7.4.1/images/svg/greenled.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/greenled.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/help-information-icon.svg minexpert2-8.1.1/images/svg/help-information-icon.svg --- minexpert2-7.4.1/images/svg/help-information-icon.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/help-information-icon.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,136 @@ + + + PDF file icon + + + + + + + + + + image/svg+xml + + PDF file icon + 08/10/2018 + + + Adobe Systems + + + + + CMetalCore + + + Fuente del texto "PDF": +Franklin Gothic Medium Cond + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/help-qt-information-icon.svg minexpert2-8.1.1/images/svg/help-qt-information-icon.svg --- minexpert2-7.4.1/images/svg/help-qt-information-icon.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/help-qt-information-icon.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,136 @@ + + + PDF file icon + + + + + + + + + + image/svg+xml + + PDF file icon + 08/10/2018 + + + Adobe Systems + + + + + CMetalCore + + + Fuente del texto "PDF": +Franklin Gothic Medium Cond + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/html-file-icon.svg minexpert2-8.1.1/images/svg/html-file-icon.svg --- minexpert2-7.4.1/images/svg/html-file-icon.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/html-file-icon.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,179 @@ + + + PDF file icon + + + + + + + + + + image/svg+xml + + PDF file icon + 08/10/2018 + + + Adobe Systems + + + + + CMetalCore + + + Fuente del texto "PDF": +Franklin Gothic Medium Cond + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/integrate-to-dt-mz.svg minexpert2-8.1.1/images/svg/integrate-to-dt-mz.svg --- minexpert2-7.4.1/images/svg/integrate-to-dt-mz.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/integrate-to-dt-mz.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + MZ + DT + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/integrate-to-dt-rt.svg minexpert2-8.1.1/images/svg/integrate-to-dt-rt.svg --- minexpert2-7.4.1/images/svg/integrate-to-dt-rt.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/integrate-to-dt-rt.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + DT + RT + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/integrate-to-dt.svg minexpert2-8.1.1/images/svg/integrate-to-dt.svg --- minexpert2-7.4.1/images/svg/integrate-to-dt.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/integrate-to-dt.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,115 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + DT + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/integrate-to-int.svg minexpert2-8.1.1/images/svg/integrate-to-int.svg --- minexpert2-7.4.1/images/svg/integrate-to-int.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/integrate-to-int.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,116 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + INT + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/integrate-to-mz-rt.svg minexpert2-8.1.1/images/svg/integrate-to-mz-rt.svg --- minexpert2-7.4.1/images/svg/integrate-to-mz-rt.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/integrate-to-mz-rt.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,139 @@ + + + + + + + + image/svg+xml + + + + + + + + MZ + RT + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/integrate-to-mz.svg minexpert2-8.1.1/images/svg/integrate-to-mz.svg --- minexpert2-7.4.1/images/svg/integrate-to-mz.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/integrate-to-mz.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,104 @@ + + + + + + + + image/svg+xml + + + + + + + + + MZ + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/integrate-to-rt.svg minexpert2-8.1.1/images/svg/integrate-to-rt.svg --- minexpert2-7.4.1/images/svg/integrate-to-rt.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/integrate-to-rt.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,104 @@ + + + + + + + + image/svg+xml + + + + + + + + + RT + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/keep-trace-and-create-new-one.svg minexpert2-8.1.1/images/svg/keep-trace-and-create-new-one.svg --- minexpert2-7.4.1/images/svg/keep-trace-and-create-new-one.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/keep-trace-and-create-new-one.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,100 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/keep-trace-and-minus-combine-new-one.svg minexpert2-8.1.1/images/svg/keep-trace-and-minus-combine-new-one.svg --- minexpert2-7.4.1/images/svg/keep-trace-and-minus-combine-new-one.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/keep-trace-and-minus-combine-new-one.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,138 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/keep-trace-and-plus-combine-new-one.svg minexpert2-8.1.1/images/svg/keep-trace-and-plus-combine-new-one.svg --- minexpert2-7.4.1/images/svg/keep-trace-and-plus-combine-new-one.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/keep-trace-and-plus-combine-new-one.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,143 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/lock-x-range.svg minexpert2-8.1.1/images/svg/lock-x-range.svg --- minexpert2-7.4.1/images/svg/lock-x-range.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/lock-x-range.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,286 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/lock-xy-ranges.svg minexpert2-8.1.1/images/svg/lock-xy-ranges.svg --- minexpert2-7.4.1/images/svg/lock-xy-ranges.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/lock-xy-ranges.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,457 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/lock-y-range.svg minexpert2-8.1.1/images/svg/lock-y-range.svg --- minexpert2-7.4.1/images/svg/lock-y-range.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/lock-y-range.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,343 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/logo.svg minexpert2-8.1.1/images/svg/logo.svg --- minexpert2-7.4.1/images/svg/logo.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/logo.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,260 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + Simulating + Analyzing + TM + and + Flying Species + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/mobile-phone-like-menu-button.svg minexpert2-8.1.1/images/svg/mobile-phone-like-menu-button.svg --- minexpert2-7.4.1/images/svg/mobile-phone-like-menu-button.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/mobile-phone-like-menu-button.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,97 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/ms-level-1.svg minexpert2-8.1.1/images/svg/ms-level-1.svg --- minexpert2-7.4.1/images/svg/ms-level-1.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/ms-level-1.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,93 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + 1 + + + diff -Nru minexpert2-7.4.1/images/svg/ms-level-2.svg minexpert2-8.1.1/images/svg/ms-level-2.svg --- minexpert2-7.4.1/images/svg/ms-level-2.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/ms-level-2.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,95 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + 2 + + + diff -Nru minexpert2-7.4.1/images/svg/ms-level-3.svg minexpert2-8.1.1/images/svg/ms-level-3.svg --- minexpert2-7.4.1/images/svg/ms-level-3.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/ms-level-3.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,95 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + 3 + + + diff -Nru minexpert2-7.4.1/images/svg/ms-level.svg minexpert2-8.1.1/images/svg/ms-level.svg --- minexpert2-7.4.1/images/svg/ms-level.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/ms-level.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,118 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + 2 + + 1 + + 3 + + diff -Nru minexpert2-7.4.1/images/svg/new-trace-in-new-plot-widget.svg minexpert2-8.1.1/images/svg/new-trace-in-new-plot-widget.svg --- minexpert2-7.4.1/images/svg/new-trace-in-new-plot-widget.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/new-trace-in-new-plot-widget.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,104 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/pdf-file-icon.svg minexpert2-8.1.1/images/svg/pdf-file-icon.svg --- minexpert2-7.4.1/images/svg/pdf-file-icon.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/pdf-file-icon.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,151 @@ + + + PDF file icon + + + + + + + + + + image/svg+xml + + PDF file icon + 08/10/2018 + + + Adobe Systems + + + + + CMetalCore + + + Fuente del texto "PDF": +Franklin Gothic Medium Cond + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/plot-widget-help.svg minexpert2-8.1.1/images/svg/plot-widget-help.svg --- minexpert2-7.4.1/images/svg/plot-widget-help.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/plot-widget-help.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,451 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ? + diff -Nru minexpert2-7.4.1/images/svg/pushpin-green-off.svg minexpert2-8.1.1/images/svg/pushpin-green-off.svg --- minexpert2-7.4.1/images/svg/pushpin-green-off.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/pushpin-green-off.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/pushpin-green-on.svg minexpert2-8.1.1/images/svg/pushpin-green-on.svg --- minexpert2-7.4.1/images/svg/pushpin-green-on.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/pushpin-green-on.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,96 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/pushpin-grey-off.svg minexpert2-8.1.1/images/svg/pushpin-grey-off.svg --- minexpert2-7.4.1/images/svg/pushpin-grey-off.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/pushpin-grey-off.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,86 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/pushpin-grey-on.svg minexpert2-8.1.1/images/svg/pushpin-grey-on.svg --- minexpert2-7.4.1/images/svg/pushpin-grey-on.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/pushpin-grey-on.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/pushpin-red-off.svg minexpert2-8.1.1/images/svg/pushpin-red-off.svg --- minexpert2-7.4.1/images/svg/pushpin-red-off.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/pushpin-red-off.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/pushpin-red-on.svg minexpert2-8.1.1/images/svg/pushpin-red-on.svg --- minexpert2-7.4.1/images/svg/pushpin-red-on.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/pushpin-red-on.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/red-cross-cancel.svg minexpert2-8.1.1/images/svg/red-cross-cancel.svg --- minexpert2-7.4.1/images/svg/red-cross-cancel.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/red-cross-cancel.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,63 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/redled.svg minexpert2-8.1.1/images/svg/redled.svg --- minexpert2-7.4.1/images/svg/redled.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/redled.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/remove-chemical-element.svg minexpert2-8.1.1/images/svg/remove-chemical-element.svg --- minexpert2-7.4.1/images/svg/remove-chemical-element.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/remove-chemical-element.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,68 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/remove-isotope.svg minexpert2-8.1.1/images/svg/remove-isotope.svg --- minexpert2-7.4.1/images/svg/remove-isotope.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/remove-isotope.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,68 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/smileys.svg minexpert2-8.1.1/images/svg/smileys.svg --- minexpert2-7.4.1/images/svg/smileys.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/smileys.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,154 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/splashscreen.svg minexpert2-8.1.1/images/svg/splashscreen.svg --- minexpert2-7.4.1/images/svg/splashscreen.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/splashscreen.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,166 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + msXpertSuite + "the expert massist'ssoftware suite" + Simulating and analyzingionized flying species + By Filippo Rusconi, Ph.D.Research scientist at the CNRS, France + mineXpert2 + version 8.1.1 + + diff -Nru minexpert2-7.4.1/images/svg/trace-plot-widget-icons.svg minexpert2-8.1.1/images/svg/trace-plot-widget-icons.svg --- minexpert2-7.4.1/images/svg/trace-plot-widget-icons.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/trace-plot-widget-icons.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,1315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MZ + + + + + DT + + + + + RT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MZ + + DT + + + + + MZ + + RT + + + + + INT + + + + + DT + + RT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Openclipart + + + + 2010-10-06T22:33:25 + Push pin icon + https://openclipart.org/detail/89059/push-pin-icon-by-jhnri4 + + + jhnri4 + + + + + icon + needle + post + push pin + pushpin + red + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/transpose-xy-axes.svg minexpert2-8.1.1/images/svg/transpose-xy-axes.svg --- minexpert2-7.4.1/images/svg/transpose-xy-axes.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/transpose-xy-axes.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,273 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/svg/zoom-lens.svg minexpert2-8.1.1/images/svg/zoom-lens.svg --- minexpert2-7.4.1/images/svg/zoom-lens.svg 1970-01-01 00:00:00.000000000 +0000 +++ minexpert2-8.1.1/images/svg/zoom-lens.svg 2021-04-26 11:28:25.000000000 +0000 @@ -0,0 +1,87 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff -Nru minexpert2-7.4.1/images/trace-plot-widget-icons.svg minexpert2-8.1.1/images/trace-plot-widget-icons.svg --- minexpert2-7.4.1/images/trace-plot-widget-icons.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/trace-plot-widget-icons.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,1315 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MZ - - - - - DT - - - - - RT - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MZ - - DT - - - - - MZ - - RT - - - - - INT - - - - - DT - - RT - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - Openclipart - - - - 2010-10-06T22:33:25 - Push pin icon - https://openclipart.org/detail/89059/push-pin-icon-by-jhnri4 - - - jhnri4 - - - - - icon - needle - post - push pin - pushpin - red - - - - - - - - - - - diff -Nru minexpert2-7.4.1/images/transpose-xy-axes.svg minexpert2-8.1.1/images/transpose-xy-axes.svg --- minexpert2-7.4.1/images/transpose-xy-axes.svg 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/images/transpose-xy-axes.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,371 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru minexpert2-7.4.1/maintainer-scripts/upload-to-gitlab-repos.sh minexpert2-8.1.1/maintainer-scripts/upload-to-gitlab-repos.sh --- minexpert2-7.4.1/maintainer-scripts/upload-to-gitlab-repos.sh 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/maintainer-scripts/upload-to-gitlab-repos.sh 2021-04-26 11:28:25.000000000 +0000 @@ -7,7 +7,8 @@ { cat << EOF Usage: - $0 --token (D5N5vfYRfeCWKnt3sZ2Y gitlab or XrjajV_pL_1tugzjdjs2 forgemia) --file --projectid (23431674 gitlab or 3236 forgemia) --version --repos + $0 [ --token (vs2FYr4VdYZhTx-Wg2Xt gitlab or XrjajV_pL_1tugzjdjs2 forgemia) ] [ --projectid (23431674 gitlab or 3236 forgemia) ] --file --version --repos + Note how --token and --projectid are optional if the tokens file is available for these values to be searched for using the --repos compulsory parameter. EOF } @@ -41,20 +42,24 @@ printf "Repos: ${repos}\n" + +# Extract the token from the tokens file using a grep|sed command combination reposurl="" -token="" +reposurl=$(grep "^reposurl ${repos}" ~/devel/minexpert2/tokens/tokens | sed "s/reposurl ${repos}: //") -if [ ${repos} = "gitlab" ] +if [ -z "${reposurl}" ] then - token="D5N5vfYRfeCWKnt3sZ2Y" - reposurl="https://gitlab.com/api/v4/projects" + print "Please, fill in properly the tokens file, could not retrieve the repos url for repos ${repos}." + usage + exit 1 fi -if [ ${repos} = "forgemia" ] -then - token="K6Q1KhykFUr8bNEiVyx9" - reposurl="https://forgemia.inra.fr/api/v4/projects" -fi +printf "The repos url is: ${reposurl}\n" + + +# Extract the token from the tokens file using a grep|sed command combination +token="" +token=$(grep "^token ${repos}" ~/devel/minexpert2/tokens/tokens | sed "s/token ${repos}: //") if [ ! -z "$opts[--token]" ] then @@ -63,15 +68,8 @@ projectid="" -if [ ${repos} = "gitlab" ] -then - projectid="23431674" -fi - -if [ ${repos} = "forgemia" ] -then - projectid="3238" -fi +# Extract the projectid from the tokens file using a grep|sed command combination +projectid=$(grep "^projectid ${repos}" ~/devel/minexpert2/tokens/tokens | sed "s/projectid ${repos}: //") if [ ! -z "$opts[--projectid]" ] then diff -Nru minexpert2-7.4.1/minexpert2.qrc minexpert2-8.1.1/minexpert2.qrc --- minexpert2-7.4.1/minexpert2.qrc 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/minexpert2.qrc 2021-04-26 11:28:25.000000000 +0000 @@ -1,11 +1,9 @@ -images/icons/svg/help-information-icon.svg -images/icons/svg/help-qt-information-icon.svg -images/icons/svg/pdf-file-icon.svg -images/icons/32x32/pdf-file-icon-32x32.png -images/icons/svg/html-file-icon.svg -images/icons/32x32/html-file-icon-32x32.png +images/svg/help-information-icon.svg +images/svg/help-qt-information-icon.svg +images/svg/pdf-file-icon.svg +images/svg/html-file-icon.svg images/icons/32x32/minexpert2.png doc/history.html images/copy.png @@ -19,43 +17,38 @@ images/splashscreen.png images/smile-bad.png images/smile-fine.png -images/lock-x-range.png -images/lock-y-range.png -images/lock-xy-ranges.png -images/plot-widget-help.png -images/transpose-xy-axes.png -images/red-cross-cancel.png -images/ms-level-1.png -images/ms-level-2.png -images/ms-level-3.png -images/grey-pushpin-on-16x16.png -images/grey-pushpin-off-16x16.png -images/green-pushpin-on-16x16.png -images/green-pushpin-off-16x16.png -images/red-pushpin-on-16x16.png -images/red-pushpin-off-16x16.png -images/close-trace-plot-widget.png -images/mobile-phone-like-menu-button.svg -images/zoom-lens-32x32.png -images/integrate-to-mz-pushbutton.png -images/integrate-to-rt-pushbutton.png -images/integrate-to-dt-pushbutton.png -images/integrate-to-dt-mz-pushbutton-32x32.png -images/integrate-to-dt-rt-pushbutton-32x32.png -images/integrate-to-mz-pushbutton-32x32.png -images/integrate-to-rt-pushbutton-32x32.png -images/integrate-to-int-pushbutton-32x32.png -images/integrate-to-rt-mz-pushbutton-32x32.png -images/integrate-to-dt-pushbutton-32x32.png -images/keep-trace-and-combine-new-one.png -images/keep-trace-and-create-new-one.png -images/erase-trace-and-create-new-one.png -images/new-trace-in-new-plot-widget.png -images/keep-trace-and-minus-combine-new-one-32x32.png -images/keep-trace-and-plus-combine-new-one-32x32.png -images/keep-trace-and-create-new-one-32x32.png -images/erase-trace-and-create-new-one-32x32.png -images/new-trace-in-new-plot-widget-32x32.png -images/duplicate-trace-pushbutton-32x32.png +images/svg/remove-chemical-element.svg +images/svg/add-isotope.svg +images/svg/remove-isotope.svg +images/svg/lock-x-range.svg +images/svg/lock-y-range.svg +images/svg/transpose-xy-axes.svg +images/svg/plot-widget-help.svg +images/svg/red-cross-cancel.svg +images/svg/ms-level-1.svg +images/svg/ms-level-2.svg +images/svg/ms-level-3.svg +images/svg/pushpin-grey-on.svg +images/svg/pushpin-grey-off.svg +images/svg/pushpin-green-on.svg +images/svg/pushpin-green-off.svg +images/svg/pushpin-red-on.svg +images/svg/pushpin-red-off.svg +images/svg/close-trace-plot-widget.svg +images/svg/mobile-phone-like-menu-button.svg +images/svg/zoom-lens.svg +images/svg/integrate-to-dt.svg +images/svg/integrate-to-mz.svg +images/svg/integrate-to-rt.svg +images/svg/integrate-to-int.svg +images/svg/integrate-to-dt-mz.svg +images/svg/integrate-to-dt-rt.svg +images/svg/integrate-to-mz-rt.svg +images/svg/new-trace-in-new-plot-widget.svg +images/svg/keep-trace-and-minus-combine-new-one.svg +images/svg/keep-trace-and-plus-combine-new-one.svg +images/svg/keep-trace-and-create-new-one.svg +images/svg/erase-trace-and-create-new-one.svg +images/svg/duplicate-trace.svg diff -Nru minexpert2-7.4.1/src/CMakeLists.txt minexpert2-8.1.1/src/CMakeLists.txt --- minexpert2-7.4.1/src/CMakeLists.txt 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/CMakeLists.txt 2021-04-26 11:28:25.000000000 +0000 @@ -32,21 +32,21 @@ # # The various integrators that use BaseMsRunDataSetTreeNodeVisitor. nongui/MsRunDataSetTreeMassDataIntegratorToRt.cpp - nongui/MsRunDataSetTreeMassDataIntegratorToMz.cpp - nongui/MsRunDataSetTreeMassDataIntegratorToDt.cpp - nongui/MsRunDataSetTreeMassDataIntegratorToDtRtMz.cpp - nongui/MsRunDataSetTreeMassDataIntegratorToTicInt.cpp + #nongui/MsRunDataSetTreeMassDataIntegratorToMz.cpp + #nongui/MsRunDataSetTreeMassDataIntegratorToDt.cpp + #nongui/MsRunDataSetTreeMassDataIntegratorToDtRtMz.cpp + #nongui/MsRunDataSetTreeMassDataIntegratorToTicInt.cpp # # The various MsRunDataSetTreeNodeVisitor classes. nongui/BaseMsRunDataSetTreeNodeVisitor.cpp nongui/MsRunStatisticsTreeNodeVisitor.cpp nongui/TicChromTreeNodeCombinerVisitor.cpp - nongui/IntensityTreeNodeCombinerVisitor.cpp - nongui/RtDtMzColorMapsTreeNodeCombinerVisitor.cpp - nongui/RtDtColorMapTreeNodeCombinerVisitor.cpp - nongui/TraceTreeNodeCombinerVisitor.cpp - nongui/MassSpectrumTreeNodeCombinerVisitor.cpp - nongui/DriftSpectrumTreeNodeCombinerVisitor.cpp + #nongui/IntensityTreeNodeCombinerVisitor.cpp + #nongui/RtDtMzColorMapsTreeNodeCombinerVisitor.cpp + #nongui/RtDtColorMapTreeNodeCombinerVisitor.cpp + #nongui/TraceTreeNodeCombinerVisitor.cpp + #nongui/MassSpectrumTreeNodeCombinerVisitor.cpp + #nongui/DriftSpectrumTreeNodeCombinerVisitor.cpp nongui/MultiTreeNodeCombinerVisitor.cpp # # The various integrators that use QualifiedMassSpectrumVector. @@ -61,7 +61,6 @@ # The classes that handle the processing flow nongui/ProcessingFlow.cpp nongui/ProcessingStep.cpp - nongui/ProcessingSpec.cpp nongui/ProcessingType.cpp # # The classes that handle the parameters for the various integrations and the diff -Nru minexpert2-7.4.1/src/gui/AboutDlg.cpp minexpert2-8.1.1/src/gui/AboutDlg.cpp --- minexpert2-7.4.1/src/gui/AboutDlg.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/AboutDlg.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -81,7 +81,7 @@ makeUserManualCommandLinkConnections(); m_ui.copyrightLabel->setText( - "msXpertSuite Copyright 2016-2020 by Filippo Rusconi"); + "msXpertSuite Copyright 2016-2021 by Filippo Rusconi"); m_ui.gplTextEdit->setText(gpl); setApplicationFeaturesText(); diff -Nru minexpert2-7.4.1/src/gui/Application.cpp minexpert2-8.1.1/src/gui/Application.cpp --- minexpert2-7.4.1/src/gui/Application.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/Application.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -77,11 +77,26 @@ QByteArray localMsg = msg.toLocal8Bit(); const char *file = context.file ? context.file : ""; const char *function = context.function ? context.function : ""; + + // The file char arrray contains the full path to the file name. + // We want to only have the basename of the file. + + QString file_path(file); + QFileInfo file_info(file_path); + QString file_name = file_info.fileName(); + const QByteArray file_name_char_array = file_name.toUtf8(); + char file_name_c_array[200]; + file_name_c_array[qMin(99, file_name_char_array.size())] = '\0'; + std::copy(file_name_char_array.constBegin(), + file_name_char_array.constBegin() + + qMin(99, file_name_char_array.size()), + file_name_c_array); + switch(type) { case QtDebugMsg: fprintf(stderr, - "Debug: %s@%u -- %s() %s\n", + "\t\t\tDebug: %s:%u\n\t\t%s\n%s\n", file, context.line, function, @@ -89,35 +104,35 @@ break; case QtInfoMsg: fprintf(stderr, - "Info: %s (%s:%u, %s)\n", - localMsg.constData(), + "\t\t\tInfo: %s:%u\n\t\t%s\n%s\n", file, context.line, - function); + function, + localMsg.constData()); break; case QtWarningMsg: fprintf(stderr, - "Warning: %s (%s:%u, %s)\n", - localMsg.constData(), + "\t\t\tWarning %s:%u\n\t\t%s\n%s\n", file, context.line, - function); + function, + localMsg.constData()); break; case QtCriticalMsg: fprintf(stderr, - "Critical: %s (%s:%u, %s)\n", - localMsg.constData(), + "\t\t\tCritical %s:%u\n\t\t%s\n%s\n", file, context.line, - function); + function, + localMsg.constData()); break; case QtFatalMsg: fprintf(stderr, - "Fatal: %s (%s:%u, %s)\n", - localMsg.constData(), + "\t\t\tFatal: %s:%u\n\t\t%s\n%s\n", file, context.line, - function); + function, + localMsg.constData()); break; } } @@ -151,7 +166,7 @@ setWindowIcon(icon); // Set the debugging message formatting pattern. - // qSetMessagePattern(QString("Debug: %{file}@%{line}-%{function}(): + // qSetMessagePattern(QString("Debug: %{file}:%{line}-%{function}(): // %{message}")); qInstallMessageHandler(myMessageOutputFormat); diff -Nru minexpert2-7.4.1/src/gui/BaseColorMapPlotCompositeWidget.cpp minexpert2-8.1.1/src/gui/BaseColorMapPlotCompositeWidget.cpp --- minexpert2-7.4.1/src/gui/BaseColorMapPlotCompositeWidget.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/BaseColorMapPlotCompositeWidget.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -1,7 +1,7 @@ /* BEGIN software license * * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- +:* ----------------------------------------------- * Copyright (C) 2009--2020 Filippo Rusconi * * http://www.msxpertsuite.org @@ -36,6 +36,8 @@ /////////////////////// Qt includes #include +#include + /////////////////////// QCustomPlot @@ -86,7 +88,7 @@ void BaseColorMapPlotCompositeWidget::createMainMenu() { - //qDebug() << "ENTER"; + // qDebug() << "ENTER"; // First create the base class menu. BasePlotCompositeWidget::createMainMenu(); @@ -95,6 +97,8 @@ // integrations. We do not support the stuffing more than one color map into a // color map plot, contrary to what we do with graphs. + mp_mainMenu->addSeparator(); + // An now append new ColorMap-specific menu // The axes transposition. @@ -107,6 +111,8 @@ mp_mainMenu->addSeparator(); + mp_mainMenu->addAction(transpose_axes_p); + QMenu *z_axis_scales_menu_p = mp_mainMenu->addMenu("Z axis scales"); // The z axis scale (log10 or linear). @@ -120,17 +126,85 @@ z_axis_scales_menu_p->addAction(z_axis_scale_to_log10_p); - // The z axis scale (log10 or linear). - QAction *z_axis_scale_to_original_p = - new QAction("Reset Z axis scale to original", this); - z_axis_scale_to_original_p->setStatusTip(tr("Reset Z axis scale to original")); - connect(z_axis_scale_to_original_p, &QAction::triggered, [this]() { - static_cast(mp_plotWidget) - ->zAxisScaleResetToOriginal(); + + // The low pass filter over the z axis. + QAction *double_spin_box_action_p = + new QAction("Low pass-filter Z axis data", this); + double_spin_box_action_p->setStatusTip(tr("Low pass-filter Z axis data")); + double_spin_box_action_p->setToolTip( + "Enter the percentage (%) of the highest intensity (i) in the map"); + + connect(double_spin_box_action_p, &QAction::triggered, [this]() { + bool ok = false; + + double percentage = QInputDialog::getDouble( + this, + "Low pass filter the color map's intensities", + "Enter the threshold as the percentage (%) \n" + "of the highest intensity (i) in the map.\n" + "\n" + "The threshold (th) is computed as th = i * % / 100.\n" + "\n" + "The intensity values below th are kept unchanged.\n" + "\n" + "The intensity values above th are replaced with the th value.", + 90, + 0, + 100, + 1, + &ok); + + if(ok) + static_cast(mp_plotWidget) + ->zAxisFilterLowPassPercentage(percentage); }); - z_axis_scales_menu_p->addAction(z_axis_scale_to_original_p); + z_axis_scales_menu_p->addAction(double_spin_box_action_p); + + + // The high pass filter over the z axis. + double_spin_box_action_p = new QAction("High pass-filter Z axis data", this); + double_spin_box_action_p->setStatusTip(tr("High pass-filter Z axis data")); + double_spin_box_action_p->setToolTip( + "Enter the percentage (%) of the highest intensity (i) in the map"); + + connect(double_spin_box_action_p, &QAction::triggered, [this]() { + bool ok = false; + + double percentage = QInputDialog::getDouble( + this, + "High pass filter the color map's intensities", + "Enter the threshold as the percentage (%) \n" + "of the highest intensity (i) in the map.\n" + "\n" + "The threshold (th) is computed as th = i * % / 100.\n" + "\n" + "The intensity values above th are kept unchanged.\n" + "\n" + "The intensity values below th are replaced with the th value.", + 10, + 0, + 100, + 1, + &ok); + + if(ok) + static_cast(mp_plotWidget) + ->zAxisFilterHighPassPercentage(percentage); + }); + + z_axis_scales_menu_p->addAction(double_spin_box_action_p); + + // The z axis scale (log10 or linear, that is, original). + QAction *z_axis_data_to_original_p = + new QAction("Reset Z axis data to original", this); + z_axis_data_to_original_p->setStatusTip(tr("Reset Z axis data to original")); + connect(z_axis_data_to_original_p, &QAction::triggered, [this]() { + static_cast(mp_plotWidget) + ->zAxisDataResetToOriginal(); + }); + z_axis_scales_menu_p->addAction(z_axis_data_to_original_p); disconnect(m_ui.mainMenuPushButton, &QPushButton::clicked, @@ -144,25 +218,25 @@ this, &BaseColorMapPlotCompositeWidget::mainMenuPushButtonClicked); - //qDebug() << "EXIT"; + // qDebug() << "EXIT"; } void BaseColorMapPlotCompositeWidget::mainMenuPushButtonClicked() { - //qDebug() << "ENTER"; + // qDebug() << "ENTER"; //// Create the contextual menu that will show when the button is clicked (see //// below). createMainMenu(); - //qDebug() << "Done creating menu, now showing it."; + // qDebug() << "Done creating menu, now showing it."; m_ui.mainMenuPushButton->showMenu(); - //qDebug() << "EXIT"; + // qDebug() << "EXIT"; } diff -Nru minexpert2-7.4.1/src/gui/BaseColorMapPlotCompositeWidget.hpp minexpert2-8.1.1/src/gui/BaseColorMapPlotCompositeWidget.hpp --- minexpert2-7.4.1/src/gui/BaseColorMapPlotCompositeWidget.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/BaseColorMapPlotCompositeWidget.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -65,6 +65,45 @@ class MsFragmentationSpecDlg; class MzIntegrationParamsDlg; +// The QWidgetAction strategy has too many problems, +// in particular on macOS. +//class DoubleSpinBoxLabelAction : public QWidgetAction +//{ + //public: + //DoubleSpinBoxLabelAction(QWidget *parent_p, + //const QString &label, + //const QString &tooltip) + //: QWidgetAction(parent_p) + //{ + //QWidget *widget_p = new QWidget(parent_p); + //QHBoxLayout *layout_p = new QHBoxLayout(); + //mp_label = new QLabel(label); + //mp_label->setToolTip(tooltip); + //layout_p->addWidget(mp_label); + //mp_spinBox = new QDoubleSpinBox(parent_p); + //layout_p->addWidget(mp_spinBox); + //widget_p->setLayout(layout_p); + + //setDefaultWidget(widget_p); + //} + + //QDoubleSpinBox * + //getSpinBox() + //{ + //return mp_spinBox; + //} + + //QLabel * + //getLabel() + //{ + //return mp_label; + //} + + //private: + //QDoubleSpinBox *mp_spinBox = nullptr; + //QLabel *mp_label = nullptr; +//}; + // The BaseColorMapPlotCompositeWidget class is aimed at receiving QCPGraph_s, // not QCPColorMap_s. This class implements all the basic features related to @@ -78,10 +117,9 @@ friend class BaseColorMapPlotWnd; public: - explicit BaseColorMapPlotCompositeWidget( - QWidget *parent, - const QString &x_axis_label, - const QString &y_axis_label); + explicit BaseColorMapPlotCompositeWidget(QWidget *parent, + const QString &x_axis_label, + const QString &y_axis_label); virtual ~BaseColorMapPlotCompositeWidget(); @@ -95,8 +133,8 @@ const ProcessingFlow &processing_flow, const QColor &color); - pappso::DataKind xAxisKind() const; - pappso::DataKind yAxisKind() const; + pappso::DataKind xAxisKind() const; + pappso::DataKind yAxisKind() const; public slots: diff -Nru minexpert2-7.4.1/src/gui/BaseColorMapPlotWnd.cpp minexpert2-8.1.1/src/gui/BaseColorMapPlotWnd.cpp --- minexpert2-7.4.1/src/gui/BaseColorMapPlotWnd.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/BaseColorMapPlotWnd.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -81,7 +81,7 @@ // This tool bar button will trigger the transpose axes operation on all the // plot widget that are pinned-down. - const QIcon transposeAxesIcon = QIcon(":/images/transpose-xy-axes.png"); + const QIcon transposeAxesIcon = QIcon(":/images/svg/transpose-xy-axes.svg"); mp_transposeAxesAct = new QAction( transposeAxesIcon, tr("Transpose axes for pinned-down plot widgets"), this); mp_transposeAxesAct->setStatusTip( @@ -265,7 +265,7 @@ void -BaseColorMapPlotWnd::integrateToRtMz(QCPAbstractPlottable *parent_plottable_p, +BaseColorMapPlotWnd::integrateToMzRt(QCPAbstractPlottable *parent_plottable_p, const ProcessingFlow &processing_flow) { // qDebug(); @@ -282,13 +282,13 @@ //"color map plot with processing flow:" //<< processing_flow.toString(); - mp_programWindow->integrateToRtMz( + mp_programWindow->integrateToMzRt( parent_plottable_p, nullptr, processing_flow); } void -BaseColorMapPlotWnd::integrateToRtDt(QCPAbstractPlottable *parent_plottable_p, +BaseColorMapPlotWnd::integrateToDtRt(QCPAbstractPlottable *parent_plottable_p, const ProcessingFlow &processing_flow) { // qDebug(); @@ -300,7 +300,7 @@ // handles their own data. So we just relay this call to the main program // window that will in turn relay it to the mass spec plot window. - mp_programWindow->integrateToRtDt( + mp_programWindow->integrateToDtRt( parent_plottable_p, nullptr, processing_flow); } diff -Nru minexpert2-7.4.1/src/gui/BaseColorMapPlotWnd.hpp minexpert2-8.1.1/src/gui/BaseColorMapPlotWnd.hpp --- minexpert2-7.4.1/src/gui/BaseColorMapPlotWnd.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/BaseColorMapPlotWnd.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -104,10 +104,10 @@ virtual void integrateToRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); - virtual void integrateToRtMz(QCPAbstractPlottable *plottable_p, + virtual void integrateToMzRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); - virtual void integrateToRtDt(QCPAbstractPlottable *plottable_p, + virtual void integrateToDtRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); public slots: diff -Nru minexpert2-7.4.1/src/gui/BasePlotCompositeWidget.cpp minexpert2-8.1.1/src/gui/BasePlotCompositeWidget.cpp --- minexpert2-7.4.1/src/gui/BasePlotCompositeWidget.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/BasePlotCompositeWidget.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -172,7 +172,7 @@ // Create the menu push button. const QIcon main_menu_icon = - QIcon(":/images/mobile-phone-like-menu-button.svg"); + QIcon(":/images/svg/mobile-phone-like-menu-button.svg"); m_ui.mainMenuPushButton->setIcon(main_menu_icon); m_ui.mainMenuPushButton->setToolTip("Plot widget menu (Ctrl+P, M)"); m_ui.mainMenuPushButton->setShortcut(QKeySequence("Ctrl+P, M")); @@ -462,23 +462,61 @@ { // A measurement was performed, inform the user. + // There are several situations: + // + // 1. The selection polygon is 1D, we only care of the X axis segment + // coordinates and delta. + // + // 2. The selection polygon is 2D, we should care of both the X axis segment + // coordinates and of the Y axis segment coordinates, also show both deltas. + // Note that we want to provide the [x -- x] x axis range in sorted order, // but the data in the context are not sorted. So craft a QCPRange object // that will automagically sort the values. Then use it to craft the // message. - QCPRange sorted_range(context.xRegionRangeStart, context.xRegionRangeEnd); +#if 0 + + // This was the previous version that only cared of X axis movements, but + // with the selection polygon we now want to show the full extent of the data: + // X axis and Y axis. + QCPRange sorted_range(context.m_xRegionRangeStart, context.m_xRegionRangeEnd); QString message = QString("[%1--%2]") .arg(sorted_range.lower, 0, 'f', 3) .arg(sorted_range.upper, 0, 'f', 3); if(with_delta) - message.append(QString(" - delta: %1").arg(context.xDelta, 0, 'f', 3)); + message.append(QString(" - delta: %1").arg(context.m_xDelta, 0, 'f', 3)); // qDebug() << message; m_ui.statusLineEdit->setText(message); +#endif + + + // First describe the selection polygon. + + QString text = context.m_selectionPolygon.toShort4PointsString(); + + // Now describe the x|y delta. + + double start; + double end; + + // We always want the X delta. + context.m_selectionPolygon.rangeX(start, end); + text += QString(" -- xDelta: %1").arg(end - start, 0, 'f', 3); + + // We want the Y delta only if the polygon is 2D. + if(context.m_selectionPolygon.is2D() && with_delta) + { + //qDebug() << "Selection polygon is 2D"; + context.m_selectionPolygon.rangeY(start, end); + text += QString(" -- yDelta: %1").arg(end - start, 0, 'f', 3); + } + + m_ui.statusLineEdit->setText(text); } @@ -488,9 +526,9 @@ { // qDebug() << "The context" << context.toString(); - m_plotWidgetPressedKeyCode = context.pressedKeyCode; + m_plotWidgetPressedKeyCode = context.m_pressedKeyCode; - if(context.pressedKeyCode == Qt::Key_Space) + if(context.m_pressedKeyCode == Qt::Key_Space) { // qDebug(); craftAnalysisStanza(context); @@ -502,7 +540,7 @@ BasePlotCompositeWidget::plotWidgetKeyReleaseEvent( const pappso::BasePlotContext &context) { - m_plotWidgetReleasedKeyCode = context.releasedKeyCode; + m_plotWidgetReleasedKeyCode = context.m_releasedKeyCode; // qDebug() << "Released key:" << m_plotWidgetReleasedKeyCode; } @@ -513,13 +551,13 @@ { // qDebug(); - // if(context.lastPressedMouseButtonsUponRelease == Qt::NoButton) + // if(context.m_lastPressedMouseButtonsUponRelease == Qt::NoButton) // qDebug() << "no button"; - // if(context.lastPressedMouseButtonsUponRelease == Qt::LeftButton) + // if(context.m_lastPressedMouseButtonsUponRelease == Qt::LeftButton) // qDebug() << "left button"; - // if(context.lastPressedMouseButtonsUponRelease == Qt::RightButton) + // if(context.m_lastPressedMouseButtonsUponRelease == Qt::RightButton) //{ // qDebug() << "right button with context:" << context.toString(); //} @@ -527,7 +565,7 @@ // Now check what keyboard key was being pressed while the mouse // operation was going on. - // int pressed_key_code = context.pressedKeyCode; + // int pressed_key_code = context.m_pressedKeyCode; // qDebug() << "pressed_key_code:" << pressed_key_code; } @@ -576,25 +614,20 @@ // Each graph has its own ProcessingFlow, and the association is in the // plottableProcessingFlowMap. - ProcessingFlow processing_flow; - - auto result = std::find_if( - m_plottableProcessingFlowMap.begin(), - m_plottableProcessingFlowMap.end(), - [plottable_p]( - const std::pair &item) { - return item.first == plottable_p; - }); + std::map::const_iterator it; - if(result != m_plottableProcessingFlowMap.end()) + for(it = m_plottableProcessingFlowMap.begin(); + it != m_plottableProcessingFlowMap.end(); + ++it) { - // qDebug().noquote() << "Found the processing flow for graph:" - //<< result->second.toString(); - - return result->second; + if(it->first == plottable_p) + { + return it->second; + break; + } } - else - qFatal("Cannot be that graph has no processing flow associated to it."); + + qFatal("Cannot be that graph has no processing flow associated to it."); return ProcessingFlow(); } @@ -763,18 +796,19 @@ MsFragmentationSpec ms_fragmentation_spec; - // Ask that only specs having a valid MsFragmentationSpec instance be - // returned (true boolean below) + // Ask that only steps having a valid MsFragmentationSpec instance be + // returned (true boolean below). Only of interest are step with the + // destination matching MZ. + + std::vector processing_steps = + processing_flow.stepsMatchingDestType(ProcessingType("MZ"), true); - std::vector processing_specs = - processing_step_p->allProcessingSpecsMatching(ProcessingType("ANY_TO_MZ"), - true); // qDebug() << "The number of processing specs that match processing // type " //"\"ANY_TO_MZ\" is:" //<< processing_specs.size(); - if(!processing_specs.size()) + if(!processing_steps.size()) { // Not a single spec had a valid ms fragmentation spec. Last resort: // get the default one from the flow. @@ -789,11 +823,11 @@ } else { - // There was/were indeed spec instances with a valid ms + // There was/were indeed step instances with a valid ms // fragmentation spec. Arbitrarily select the last one. - ProcessingSpec *processing_spec_p = processing_specs.back(); - ms_fragmentation_spec = processing_spec_p->getMsFragmentationSpec(); + processing_step_p = processing_steps.back(); + ms_fragmentation_spec = processing_step_p->getMsFragmentationSpec(); } // We can finally use it to configure the dialog window. @@ -860,7 +894,7 @@ // Set the default ms frag spec. processing_flow_p->setDefaultMsFragmentationSpec(ms_fragmentation_spec); - qDebug() << "Now setting the MS level to the spin box."; + //qDebug() << "Now setting the MS level to the spin box."; // Change the MS level value in the spinbox. // But we need to disconnect the spin box' value changed signal, because @@ -868,9 +902,9 @@ // frag spec's ms level again. disconnect(m_ui.msLevelSpinBox, - QOverload::of(&QSpinBox::valueChanged), - this, - &BasePlotCompositeWidget::msLevelValueChanged); + QOverload::of(&QSpinBox::valueChanged), + this, + &BasePlotCompositeWidget::msLevelValueChanged); m_ui.msLevelSpinBox->setValue(ms_fragmentation_spec.getMsLevel()); @@ -879,8 +913,6 @@ QOverload::of(&QSpinBox::valueChanged), this, &BasePlotCompositeWidget::msLevelValueChanged); - - } @@ -890,7 +922,7 @@ // The user has selected a new MS level value, we need to ensure that this // value is record in the MsFragmentationSpec. - qDebug() << "Value: " << value; + //qDebug() << "Value: " << value; QCPAbstractPlottable *source_plottable_p = plottableToBeUsedAsIntegrationSource(); @@ -1161,7 +1193,7 @@ // We need to know what kind of data we are handling so that we can select the // proper format. - pappso::DataKind data_kind = context.dataKind; + pappso::DataKind data_kind = context.m_dataKind; // qDebug() << "data_kind:" << static_cast(data_kind); @@ -1281,13 +1313,13 @@ // plot widget. Let that handling to the derived class. if(curChar == 'x') { - stanza += QString("%1").arg(context.xDelta, 0, 'g', 6); + stanza += QString("%1").arg(context.m_xDelta, 0, 'g', 6); prevChar = ' '; continue; } if(curChar == 'y') { - stanza += QString("%1").arg(context.yDelta, 0, 'g', 6); + stanza += QString("%1").arg(context.m_yDelta, 0, 'g', 6); prevChar = ' '; continue; @@ -1302,14 +1334,15 @@ } if(curChar == 'b') { - stanza += QString("%1").arg(context.xRegionRangeStart, 0, 'f', 3); + stanza += + QString("%1").arg(context.m_xRegionRangeStart, 0, 'f', 3); prevChar = ' '; continue; } if(curChar == 'e') { - stanza += QString("%1").arg(context.xRegionRangeEnd, 0, 'f', 3); + stanza += QString("%1").arg(context.m_xRegionRangeEnd, 0, 'f', 3); prevChar = ' '; continue; diff -Nru minexpert2-7.4.1/src/gui/BasePlotWnd.cpp minexpert2-8.1.1/src/gui/BasePlotWnd.cpp --- minexpert2-7.4.1/src/gui/BasePlotWnd.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/BasePlotWnd.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -143,6 +143,16 @@ { setWindowTitle(QString("mineXpert2 - %1").arg(m_title)); + // This attribute make sure that the main window of the program is destroyed + // when it is closed. Effectively stopping the program. + setAttribute(Qt::WA_DeleteOnClose); + + // The default window icon. + QString pixmap_file_name = ":/images/icons/32x32/minexpert2.png"; + QPixmap icon_pixmap(pixmap_file_name); + QIcon icon(icon_pixmap); + setWindowIcon(icon); + // This will take care of the main menu that sits in the first button of the // tool bar. setupToolBar(); @@ -218,8 +228,9 @@ // The tool bar non-menu buttons - const QIcon xRangeIcon = QIcon(":/images/lock-x-range.png"); - mp_lockXRangeAct = new QAction(xRangeIcon, tr("Lock X range (Ctrl+L, X)"), this); + const QIcon xRangeIcon = QIcon(":/images/svg/lock-x-range.svg"); + mp_lockXRangeAct = + new QAction(xRangeIcon, tr("Lock X range (Ctrl+L, X)"), this); mp_lockXRangeAct->setCheckable(true); mp_lockXRangeAct->setShortcut(QKeySequence("Ctrl+L, X")); mp_lockXRangeAct->setStatusTip(tr("Lock X range")); @@ -229,8 +240,9 @@ mp_toolBar->addAction(mp_lockXRangeAct); - const QIcon yRangeIcon = QIcon(":/images/lock-y-range.png"); - mp_lockYRangeAct = new QAction(yRangeIcon, tr("Lock Y range (Ctrl+L, Y)"), this); + const QIcon yRangeIcon = QIcon(":/images/svg/lock-y-range.svg"); + mp_lockYRangeAct = + new QAction(yRangeIcon, tr("Lock Y range (Ctrl+L, Y)"), this); mp_lockYRangeAct->setCheckable(true); mp_lockYRangeAct->setShortcut(QKeySequence("Ctrl+L, Y")); mp_lockYRangeAct->setStatusTip(tr("Lock Y range")); @@ -253,7 +265,7 @@ mp_mainMenu = new QMenu(this); const QIcon main_menu_icon = - QIcon(":/images/mobile-phone-like-menu-button.svg"); + QIcon(":/images/svg/mobile-phone-like-menu-button.svg"); mp_mainMenuPushButton = new QPushButton(main_menu_icon, QString(""), this); mp_mainMenuPushButton->setToolTip("Plot widget menu (Ctrl+W, M)"); mp_mainMenuPushButton->setShortcut(QKeySequence("Ctrl+W, M")); @@ -270,8 +282,8 @@ // We want to be able to set the mz integ params for all the plot widgets in // the window in one go. - QAction *new_act_p = - new QAction("Set m/z &integration params for all pinned-down widgets", this); + QAction *new_act_p = new QAction( + "Set m/z &integration params for all pinned-down widgets", this); new_act_p->setShortcut(QKeySequence("Ctrl+I, P")); connect(new_act_p, &QAction::triggered, [this]() { @@ -379,8 +391,10 @@ QMenu *remove_plot_widgets_menu_p = new QMenu("Remove plot &widgets..."); mp_plotWidgetManagementMenu->addMenu(remove_plot_widgets_menu_p); - QAction *remove_pinned_plot_widgets_p = new QAction(tr("&Remove pinned-down plot widgets"), this); - remove_pinned_plot_widgets_p->setStatusTip(tr("Remove pinned-down plot widgets")); + QAction *remove_pinned_plot_widgets_p = + new QAction(tr("&Remove pinned-down plot widgets"), this); + remove_pinned_plot_widgets_p->setStatusTip( + tr("Remove pinned-down plot widgets")); remove_pinned_plot_widgets_p->setShortcut(QKeySequence("Ctrl+R, P")); connect(remove_pinned_plot_widgets_p, &QAction::triggered, [this]() { @@ -396,16 +410,19 @@ new QAction(tr("Remove pinned-down plot widgets and &descendants"), this); remove_pinned_plot_widgets_descendants_p->setStatusTip( tr("Remove pinned-down plot widgets and descendants")); - remove_pinned_plot_widgets_descendants_p->setShortcut(QKeySequence("Ctrl+R, Ctrl+P, D")); + remove_pinned_plot_widgets_descendants_p->setShortcut( + QKeySequence("Ctrl+R, Ctrl+P, D")); - connect(remove_pinned_plot_widgets_descendants_p, &QAction::triggered, [this]() { - std::vector widget_list = pinnedDownWidgets(); + connect( + remove_pinned_plot_widgets_descendants_p, &QAction::triggered, [this]() { + std::vector widget_list = pinnedDownWidgets(); - for(auto &&widget_p : widget_list) - plotCompositeWidgetDestructionRequested(widget_p); - }); + for(auto &&widget_p : widget_list) + plotCompositeWidgetDestructionRequested(widget_p); + }); - remove_plot_widgets_menu_p->addAction(remove_pinned_plot_widgets_descendants_p); + remove_plot_widgets_menu_p->addAction( + remove_pinned_plot_widgets_descendants_p); remove_plot_widgets_menu_p->addSeparator(); @@ -422,7 +439,8 @@ remove_plot_widgets_menu_p->addAction(mp_removeEmptyPlotWidgetsAct); - mp_removeAllPlotWidgetsAct = new QAction(tr("Remove &all plot widgets"), this); + mp_removeAllPlotWidgetsAct = + new QAction(tr("Remove &all plot widgets"), this); mp_removeAllPlotWidgetsAct->setStatusTip(tr("Remove all plot widgets")); mp_removeAllPlotWidgetsAct->setShortcut(QKeySequence("Ctrl+R, A")); @@ -440,7 +458,8 @@ new QAction(tr("Remove all plot widgets and d&escendants"), this); mp_removeAllPlotWidgetsAndDescendantsAct->setStatusTip( tr("Remove all plot widgets and descendants")); - mp_removeAllPlotWidgetsAndDescendantsAct->setShortcut(QKeySequence("Ctrl+R, Ctrl+A, D")); + mp_removeAllPlotWidgetsAndDescendantsAct->setShortcut( + QKeySequence("Ctrl+R, Ctrl+A, D")); connect( mp_removeAllPlotWidgetsAndDescendantsAct, &QAction::triggered, [this]() { @@ -872,7 +891,8 @@ new QualifiedMassSpectrumVectorMassDataIntegratorToTicInt( ms_run_data_set_csp, processing_flow, qualified_mass_spectra_sp); - mass_data_integrator_p->setMaxThreadUseCount(mp_programWindow->getMaxThreadUseCount()); + mass_data_integrator_p->setMaxThreadUseCount( + mp_programWindow->getMaxThreadUseCount()); // Ensure the mass data integrator messages are used. @@ -1209,16 +1229,16 @@ int which_plot_axis = 0; if(m_isLockedXRange) - which_plot_axis |= static_cast(pappso::PlotAxis::x_axis); + which_plot_axis |= static_cast(pappso::Axis::x); if(m_isLockedYRange) - which_plot_axis |= static_cast(pappso::PlotAxis::y_axis); + which_plot_axis |= static_cast(pappso::Axis::y); if(!which_plot_axis) return; - QCPRange x_axis_range(context.xRange.lower, context.xRange.upper); - QCPRange y_axis_range(context.yRange.lower, context.yRange.upper); + QCPRange x_axis_range(context.m_xRange.lower, context.m_xRange.upper); + QCPRange y_axis_range(context.m_yRange.lower, context.m_yRange.upper); QList widget_list = findChildren("plotCompositeWidget"); @@ -1237,9 +1257,7 @@ } widget_p->mp_plotWidget->replotWithAxesRanges( - x_axis_range, - y_axis_range, - static_cast(which_plot_axis)); + x_axis_range, y_axis_range, static_cast(which_plot_axis)); } } @@ -1293,49 +1311,74 @@ // If the vector is not empty, then we return its size without modification. if(qualified_mass_spectra_sp->size()) - return qualified_mass_spectra_sp->size(); - - // Now, we know we can fill in the vector. + { + qDebug() << "The vector of qualified spectra is not empty. Returning " + "with no modification."; - // We get a processing flow from which we extract the innermost rt and dt - // ranges. We use those ranges for selecting the most restricted set of - // qualified mass spectra so as to speed up the integrations. + return qualified_mass_spectra_sp->size(); + } - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); + // Now, we know we can fill in the vector. But try to limit as much as + // possible the number of spectra to add. We do that by only pushing into the + // vector the spectra that have rt (and dt, if mobility data) values matching + // the innermost rt (and dt) ranges. + + std::pair range_pair; + + // We choose RT_TO_ANY that matches in the widest possible manner all the + // previous integrations that started with a rt-involving selection (both + // mono- and two-dimensional, either from the ms run table view or any + // trace/color map plot). - bool integration_rt = processing_flow.innermostRtRange(start_rt, end_rt); + bool integration = + processing_flow.innermostRange("ANY_RT", range_pair); - if(!integration_rt) + if(!integration) qFatal("Programming error."); - // std::size_t added_rt_mass_spectra = - ms_run_data_set_csp->getMsRunDataSetTreeCstSPtr() - ->addDataSetQualMassSpectraInsideDtRtRange( - start_rt, end_rt, *qualified_mass_spectra_sp, pappso::DataKind::rt); - - // qDebug() << "Added RT mass spectra:" << added_rt_mass_spectra; + qDebug() << "Filling-in mass spectra for RT range: " << range_pair.first + << "-" << range_pair.second; - // Now see if we can remove some mass spectra on the basis of DT values. + std::size_t added_rt_mass_spectra = + ms_run_data_set_csp->getMsRunDataSetTreeCstSPtr() + ->addDataSetQualMassSpectraInsideDtRtRange(range_pair.first, + range_pair.second, + *qualified_mass_spectra_sp, + pappso::DataKind::rt); - double start_dt = std::numeric_limits::infinity(); - double end_dt = std::numeric_limits::infinity(); + qDebug() << "Added RT mass spectra:" << added_rt_mass_spectra; - bool integration_dt = processing_flow.innermostDtRange(start_dt, end_dt); + // Now see if we can remove some mass spectra on the basis of DT values. - if(integration_dt) + // We choose ANY_DT that matches in the widest possible manner all the + // previous integrations that started with a dt-involving selection (both + // mono- and two-dimensionale). + integration = + processing_flow.innermostRange("ANY_DT", range_pair); + + // Here, it is not an error not to have any DT integration because not all + // the mass spectral acquisitions involved ion mobility. + if(integration) { - // qDebug() << "Detected DT integration"; + qDebug() + << "Detected DT integration, removing mass spectra outside DT range: " + << range_pair.first << "-" << range_pair.second; + + std::size_t removed_mass_spectra = + ms_run_data_set_csp->getMsRunDataSetTreeCstSPtr() + ->removeDataSetQualMassSpectraOutsideDtRtRange( + range_pair.first, + range_pair.second, + *qualified_mass_spectra_sp, + pappso::DataKind::dt); - // std::size_t removed_mass_spectra = - ms_run_data_set_csp->getMsRunDataSetTreeCstSPtr() - ->removeDataSetQualMassSpectraOutsideDtRtRange( - start_dt, end_dt, *qualified_mass_spectra_sp, pappso::DataKind::dt); - - // qDebug() << "Removed mass spectra on basis of DT:" - //<< removed_mass_spectra; + qDebug() << "Number of mass spectra removed on the basis of DT:" + << removed_mass_spectra; } + // At this point we need to really check which of the remaining spectra are + // inside of the selection polygon. + return qualified_mass_spectra_sp->size(); } diff -Nru minexpert2-7.4.1/src/gui/BaseTracePlotCompositeWidget.cpp minexpert2-8.1.1/src/gui/BaseTracePlotCompositeWidget.cpp --- minexpert2-7.4.1/src/gui/BaseTracePlotCompositeWidget.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/BaseTracePlotCompositeWidget.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -93,10 +93,10 @@ // tricky to handle because it is not possible to know if it is checed or not. const QIcon plus_combine_icon = - QIcon(":/images/keep-trace-and-plus-combine-new-one-32x32.png"); + QIcon(":/images/svg/keep-trace-and-plus-combine-new-one.svg"); const QIcon minus_combine_icon = - QIcon(":/images/keep-trace-and-minus-combine-new-one-32x32.png"); + QIcon(":/images/svg/keep-trace-and-minus-combine-new-one.svg"); m_ui.combinationsComboBox->insertItem( -1, minus_combine_icon, "", static_cast(TraceCombinationSign::MINUS)); @@ -487,11 +487,11 @@ BasePlotCompositeWidget::plotWidgetKeyPressEvent(context); - m_plotWidgetPressedKeyCode = context.pressedKeyCode; + m_plotWidgetPressedKeyCode = context.m_pressedKeyCode; // qDebug() << "The context" << context.toString(); - if(context.pressedKeyCode == Qt::Key_Space) + if(context.m_pressedKeyCode == Qt::Key_Space) { // At the moment, in this class we have nothing very specific to do. But // we could reparse the m_analysisStanza string and fill-in any remaining @@ -531,8 +531,8 @@ if(mp_plotWidget) { QPointF mouseCursorPos( - mp_plotWidget->xAxis->coordToPixel(context.currentDragPoint.x()), - mp_plotWidget->xAxis->coordToPixel(context.currentDragPoint.y())); + mp_plotWidget->xAxis->coordToPixel(context.m_currentDragPoint.x()), + mp_plotWidget->xAxis->coordToPixel(context.m_currentDragPoint.y())); QMouseEvent *mouse_event_p = new QMouseEvent(QEvent::MouseButtonPress, mouseCursorPos, diff -Nru minexpert2-7.4.1/src/gui/DriftSpecMassSpecColorMapPlotCompositeWidget.cpp minexpert2-8.1.1/src/gui/DriftSpecMassSpecColorMapPlotCompositeWidget.cpp --- minexpert2-7.4.1/src/gui/DriftSpecMassSpecColorMapPlotCompositeWidget.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/DriftSpecMassSpecColorMapPlotCompositeWidget.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -175,29 +175,57 @@ DriftSpecMassSpecColorMapPlotCompositeWidget::integrationRequested( const pappso::BasePlotContext &context) { - // qDebug().noquote() << "context:" << context.toString(); + qDebug().noquote() << "context:" << context.toString(); // We are getting that signal from a plot widget that operates as a - // drift spec / mass spec color map plot widget. + // drift spec / mass spec color map plot widget. By essence, the selected + // region needs to be two-dimensional, so the selection polygon needs to be + // so. + + // Check if the selection polygon contain meaninful data. We are in a colormap + // plot widget, so the selection polygon cannot be in the form of a + // mono-dimensional polygon. - // Remember that the xregion start and end are not sorted. - double x_range_start = - std::min(context.xRegionRangeStart, context.xRegionRangeEnd); - double x_range_end = - std::max(context.xRegionRangeStart, context.xRegionRangeEnd); + if(!context.m_selectionPolygon.is2D()) + { + qDebug() << "The selection polygon cannot be mono-dimensional when " + "selecting for integration from color map"; + return; + } + else + { + if(context.m_selectionPolygon.isRectangle()) + qDebug() << "The selection polygon is rectangle."; + else + qDebug() << "The selection polygon is oblique (skewed)."; + } + + // Sanity check. + + // Immediately check if the selection range makes sense. For example, having + // both the start/end values in the negative values does not mean anything + // with respect to drift spec vs mass spectrum data! + + double x_range_start; + double x_range_end; + + context.m_selectionPolygon.rangeX(x_range_start, x_range_end); + + qDebug() << "X axis range:" << x_range_start << "-" << x_range_end; if(x_range_start < 0 && x_range_end < 0) return; - double y_range_start = - std::min(context.yRegionRangeStart, context.yRegionRangeEnd); - double y_range_end = - std::max(context.yRegionRangeStart, context.yRegionRangeEnd); + double y_range_start; + double y_range_end; + + context.m_selectionPolygon.rangeY(y_range_start, y_range_end); + + qDebug() << "Y axis range:" << y_range_start << "-" << y_range_end; if(y_range_start < 0 && y_range_end < 0) return; - // We need check which destination button is currently checked. // The widget does not handle the integrations. There are the @@ -211,7 +239,6 @@ // selected is the right one. If there are more than one traces selected, then // we cannot do anything. Display an error message. - // The QCustomPlot-based widget might contain more than one graph, and we // need to know on what graph the user is willing to perform the // integration. @@ -243,26 +270,10 @@ // qDebug() << ms_run_data_set_csp->getMsRunDataSetStats().toString(); - // Now we need to add a new step in that processing flow so that we document - // this new integration that we are performing. + // Create a processing step to document the specifics of this new integration. ProcessingStep *processing_step_p = new ProcessingStep(); - // The step has a multi-map of pairs that each relate a processing type with a - // processing spec. So we need to document a new pair type/spec, let's start - // with the spec that documents the range of the data we are willing to - // integrate, that is, the selected region of the graph. - - // The ProcessingSpec has the range start/end values, an optional ms - // fragmentation specification and a date time that is set automatically at - // construction time. - - // Allocate a new spec that will hold the DT dimension range. - ProcessingSpec *dt_processing_spec_p = new ProcessingSpec(); - - // And another one for the MZ dimension range. - ProcessingSpec *mz_processing_spec_p = new ProcessingSpec(); - // If the user had set ms fragmentation specifications, all these are listed // in the various ProcessingSpec instances, so we do not loose any. However, // the user is entitled to define any new ms fragmentation specifications @@ -280,7 +291,7 @@ // flow " "is valid, using it:" //<< ms_fragmentation_spec.toString(); - mz_processing_spec_p->setMsFragmentationSpec(ms_fragmentation_spec); + processing_step_p->setMsFragmentationSpec(ms_fragmentation_spec); } else { @@ -290,99 +301,118 @@ // Now define the graph ranges for the integration operation. - // Remember that the region start and end are not sorted. Also, the colormap - // can have its axes transposed, so we need to ensure that we use the proper - // axis for mz and the proper axis for the other dimension (rt or dt). - - if(static_cast(mp_plotWidget) - ->xAxisDataKind() == pappso::DataKind::dt) - { - dt_processing_spec_p->setRange(x_range_start, x_range_end); - mz_processing_spec_p->setRange(y_range_start, y_range_end); - - qDebug() << "x axis data kind is dt" - << "dt range:" << x_range_start << "-" << x_range_end - << "mz range:" << y_range_start << "-" << y_range_end; + // Sanity check. + + pappso::DataKind x_axis_data_kind = + static_cast(mp_plotWidget) + ->xAxisDataKind(); + pappso::DataKind y_axis_data_kind = + static_cast(mp_plotWidget) + ->yAxisDataKind(); + + if(x_axis_data_kind == pappso::DataKind::dt) + qDebug() << "X axis: dt"; + else if(x_axis_data_kind == pappso::DataKind::mz) + qDebug() << "X axis: mz"; + + if(x_axis_data_kind == pappso::DataKind::dt && + y_axis_data_kind != pappso::DataKind::mz) + { + qFatal("Programming error."); } - else + else if(x_axis_data_kind == pappso::DataKind::mz && + y_axis_data_kind != pappso::DataKind::dt) { - dt_processing_spec_p->setRange(y_range_start, y_range_end); - mz_processing_spec_p->setRange(x_range_start, x_range_end); + qFatal("Programming error."); + } - qDebug() << "x axis data kind is mz" - << "dt range:" << y_range_start << "-" << y_range_end - << "mz range:" << x_range_start << "-" << x_range_end; + // The colormap can have its axes transposed, so we need to ensure that we + // document the axis/data-kind relation properly. Note that we want the + // processing step to be documented according to the alpha numerical ordering. + // So, if we are working in a DT_RT colormap, then, x axis needs to be DT and + // y axis needs to be RT. + + // Make a local copy of the selection polygon because we might need to + // transpose it. + + pappso::SelectionPolygon local_selection_polygon = context.m_selectionPolygon; + + if(x_axis_data_kind == pappso::DataKind::mz) + { + // We have to transpose the selection rectangle so that x:MZ and y:RT. + local_selection_polygon = local_selection_polygon.transpose(); } + // else + // No need to tranpose, we deal with data in the right x:MZ y:RT. + + qDebug() << "The selection polygon:" << local_selection_polygon.toString(); + + // Now we know we have the right selection polygon for x:MZ and y:RT. + + processing_step_p->setDataKind(pappso::Axis::x, pappso::DataKind::dt); + processing_step_p->setDataKind(pappso::Axis::y, pappso::DataKind::mz); + + + // And now actually set the selection polygon to the step. + + processing_step_p->setSelectionPolygon(local_selection_polygon); + + // qDebug() << "Selection polygon as set to the step:" + //<< processing_step_p->getSelectionPolygon().toString(); + + // We must say what is the data source processing type. + processing_step_p->setSrcProcessingType(pappso::Axis::x, "DT"); + processing_step_p->setSrcProcessingType(pappso::Axis::y, "MZ"); + + // Now we need to document not the source but the destination. What kind of + // integration are we about to perform? if(m_ui.integrateToRtPushButton->isChecked()) { - // qDebug() << "Integration to XIC chromatogram."; + qDebug() << "Integrating to XIC chromatogram."; // We need to set two specs to the step. - processing_step_p->newSpec(ProcessingType("DT_MZ_DT_TO_RT"), - dt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("DT_MZ_MZ_TO_RT"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("RT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) ->integrateToRt(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtDtPushButton->isChecked()) + else if(m_ui.integrateToDtRtPushButton->isChecked()) { - // qDebug() << "Integration to XIC chromatogram. / drift spectrum color - // map"; - - // We need to set two specs to the step. + qDebug() << "Integrating to dt / rt color map."; - processing_step_p->newSpec(ProcessingType("DT_MZ_DT_TO_RT_DT"), - dt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("DT_MZ_MZ_TO_RT_DT"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("DT_RT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) - ->integrateToRtDt(plottable_p, local_processing_flow); + ->integrateToDtRt(plottable_p, local_processing_flow); } + // Handle all the integrations to MZ in one place else if(m_ui.integrateToMzPushButton->isChecked() || m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { if(m_ui.integrateToMzPushButton->isChecked()) { - // qDebug() << "Integrating to mass spectrum."; - - // We need to set two specs to the step. + qDebug() << "Integrating to mass spectrum."; - processing_step_p->newSpec(ProcessingType("DT_MZ_DT_TO_MZ"), - dt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("DT_MZ_MZ_TO_MZ"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("MZ"); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { - // qDebug() << "Integrating to rt / m/z color map."; - - // We need to set two specs to the step. + qDebug() << "Integrating to rt / m/z color map."; - processing_step_p->newSpec(ProcessingType("DT_MZ_DT_TO_RT_MZ"), - dt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("DT_MZ_MZ_TO_RT_MZ"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("MZ_RT"); } else if(m_ui.integrateToDtMzPushButton->isChecked()) { - // qDebug() << "Integrating to dt / m/z color map."; + qDebug() << "Integrating to dt / m/z color map."; - // We need to set two specs to the step. - - processing_step_p->newSpec(ProcessingType("DT_MZ_DT_TO_DT_MZ"), - dt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("DT_MZ_MZ_TO_DT_MZ"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("DT_MZ"); } // At this point we need to define how the mass data integrator will @@ -425,7 +455,7 @@ // Note that we cannot integrate mass spectra with a high resolution // here. We need to reduce the resolution to integer resolution. if(m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { mz_integration_params.setBinningType(pappso::BinningType::NONE); mz_integration_params.setDecimalPlaces(0); @@ -456,22 +486,17 @@ static_cast(mp_parentWnd) ->integrateToDtMz(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { static_cast(mp_parentWnd) - ->integrateToRtMz(plottable_p, local_processing_flow); + ->integrateToMzRt(plottable_p, local_processing_flow); } } else if(m_ui.integrateToDtPushButton->isChecked()) { - // qDebug() << "Integrating to drift spectrum."; - - // We need to set two specs to the step. + qDebug() << "Integrating to drift spectrum."; - processing_step_p->newSpec(ProcessingType("DT_MZ_DT_TO_DT"), - dt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("DT_MZ_MZ_TO_DT"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("DT"); local_processing_flow.push_back(processing_step_p); @@ -480,14 +505,9 @@ } else if(m_ui.integrateToIntPushButton->isChecked()) { - // qDebug() << "Integrating to TIC intensity."; - - // We need to set two specs to the step. + qDebug() << "Integrating to TIC intensity."; - processing_step_p->newSpec(ProcessingType("DT_MZ_DT_TO_INT"), - dt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("DT_MZ_MZ_TO_INT"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("INT"); local_processing_flow.push_back(processing_step_p); diff -Nru minexpert2-7.4.1/src/gui/DriftSpecMassSpecColorMapWnd.cpp minexpert2-8.1.1/src/gui/DriftSpecMassSpecColorMapWnd.cpp --- minexpert2-7.4.1/src/gui/DriftSpecMassSpecColorMapWnd.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/DriftSpecMassSpecColorMapWnd.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -111,8 +111,6 @@ qualified_mass_spectra_sp, const ProcessingFlow &processing_flow) { - // qDebug(); - // qDebug().noquote() << "Integrating to dt | mz with processing flow:" //<< processing_flow.toString(); @@ -123,28 +121,39 @@ if(ms_run_data_set_csp == nullptr) qFatal("Cannot be that the pointer is nullptr."); - // We will try to limit the number of mass spectra to iterate through with the - // integration visitor. - - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); + // FIXME: BEGIN Sanity check that might be removed when the program is stabilized. + std::pair range_pair; - bool integration_rt = processing_flow.innermostRtRange(start_rt, end_rt); + bool integration_rt = processing_flow.innermostRange("ANY_RT", range_pair); if(!integration_rt) qFatal("Programming error."); - // First prepare a vector of QualifiedMassSpectrumCstSPtr + qDebug() << qSetRealNumberPrecision(10) << "Innermost RT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + + bool integration_dt = processing_flow.innermostRange("ANY_DT", range_pair); + + if(integration_dt) + qDebug() << qSetRealNumberPrecision(10) << "Innermost DT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + // FIXME: END Sanity check that might be removed when the program is stabilized. + + // First prepare a vector of QualifiedMassSpectrumCstSPtr. If the + // qualified_mass_spectra_sp is not empty, the + // fillInQualifiedMassSpectraVector() function below does not change the + // vector and returns its size. std::size_t qualified_mass_spectra_count = fillInQualifiedMassSpectraVector( ms_run_data_set_csp, qualified_mass_spectra_sp, processing_flow); + qDebug() + << "The number of selected mass spectra on the basis of rough RT/DT values:" + << qualified_mass_spectra_count; + if(!qualified_mass_spectra_count) return; - // qDebug() << "The number of remaining mass spectra:" - //<< qualified_mass_spectra_count; - // Now start the actual integration work. // Allocate a mass data integrator to integrate the data. @@ -154,7 +163,8 @@ new QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz( ms_run_data_set_csp, processing_flow, qualified_mass_spectra_sp); - mass_data_integrator_p->setMaxThreadUseCount(mp_programWindow->getMaxThreadUseCount()); + mass_data_integrator_p->setMaxThreadUseCount( + mp_programWindow->getMaxThreadUseCount()); // Ensure the mass data integrator messages are used. @@ -169,21 +179,17 @@ MassDataIntegratorTask *mass_data_integrator_task_p = new MassDataIntegratorTask(); + qRegisterMetaType("std::size_t"); qRegisterMetaType("pappso::DataKind"); // This signal starts the computation in the MassDataIntegratorTask object. connect(this, - static_cast( - &DriftSpecMassSpecColorMapWnd::integrateToDtRtMzSignal), + &DriftSpecMassSpecColorMapWnd::integrateToDtRtMzSignal, mass_data_integrator_task_p, - static_cast(&MassDataIntegratorTask::integrateToDtRtMz), + &MassDataIntegratorTask::integrateToDtRtMz, // Fundamental for signals that travel across QThread instances... Qt::QueuedConnection); @@ -278,7 +284,7 @@ //"data integrator:" //<< mass_data_integrator_p; - emit integrateToDtRtMzSignal(mass_data_integrator_p, pappso::DataKind::dt); + emit integrateToDtRtMzSignal(mass_data_integrator_p); // We do not want to make signal/slot calls more than once. This is because // one user might well trigger more than one integration from this window to a @@ -291,15 +297,11 @@ this, - static_cast( - &DriftSpecMassSpecColorMapWnd::integrateToDtRtMzSignal), + &DriftSpecMassSpecColorMapWnd::integrateToDtRtMzSignal, mass_data_integrator_task_p, - static_cast(&MassDataIntegratorTask::integrateToDtRtMz)); + + &MassDataIntegratorTask::integrateToDtRtMz); } @@ -359,7 +361,9 @@ mass_data_integrator_to_rtdtmz_p->getColorMapMinKey(), mass_data_integrator_to_rtdtmz_p->getColorMapMaxKey(), mass_data_integrator_to_rtdtmz_p->getColorMapMinMz(), - mass_data_integrator_to_rtdtmz_p->getColorMapMaxMz()); + mass_data_integrator_to_rtdtmz_p->getColorMapMaxMz(), + /*the min Z value will be determined later*/ 0, + /*the max Z value will be determined later*/ 0); // qDebug() << "color_map_plot_config:" << color_map_plot_config.toString(); diff -Nru minexpert2-7.4.1/src/gui/DriftSpecMassSpecColorMapWnd.hpp minexpert2-8.1.1/src/gui/DriftSpecMassSpecColorMapWnd.hpp --- minexpert2-7.4.1/src/gui/DriftSpecMassSpecColorMapWnd.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/DriftSpecMassSpecColorMapWnd.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -93,8 +93,7 @@ void integrateToDtRtMzSignal(QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz - *mass_data_integrator_p, - pappso::DataKind); + *mass_data_integrator_p); protected: }; diff -Nru minexpert2-7.4.1/src/gui/DriftSpecTracePlotCompositeWidget.cpp minexpert2-8.1.1/src/gui/DriftSpecTracePlotCompositeWidget.cpp --- minexpert2-7.4.1/src/gui/DriftSpecTracePlotCompositeWidget.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/DriftSpecTracePlotCompositeWidget.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -170,8 +170,8 @@ // in the base class function. pappso::BasePlotContext local_context = context; - local_context.xRegionRangeStart = m_integrationRange.lower; - local_context.xRegionRangeEnd = m_integrationRange.upper; + local_context.m_xRegionRangeStart = m_integrationRange.lower; + local_context.m_xRegionRangeEnd = m_integrationRange.upper; if(m_isSinglePointIntegrationMode) integrationRequested(local_context); @@ -187,16 +187,34 @@ // The reference implementation is the TicXicChromTracePlotCompositeWidget // one. Look there for all the explanative comments. - // Immediately check if the selection range makes sense. For example, having - // both the start/end values in the negative values does not mean anything - // with respect to mass spectrum data! - - // Remember that the xregion start and end are not sorted. - double range_start = - std::min(context.xRegionRangeStart, context.xRegionRangeEnd); - double range_end = - std::max(context.xRegionRangeStart, context.xRegionRangeEnd); + // Make a local copy of the context because we may need to modify it. + pappso::BasePlotContext local_context = context; + + // Check if the selection polygon contain meaningful data. We are in trace + // plot widget, so the selection polygon might be in the form of a + // mono-dimensional polygon, although this is not mandatory. But we rely on + // the selection polygon to be of 1 or 2 dimension for some optimizations. So, + // if the polygon is 2D, convert it to 1D. + + if(local_context.m_selectionPolygon.is2D()) + qDebug() << "Odd situation where the selection polygon is two-dimensional " + "and the trace plot selection is mono-dimensional. Converting " + "it to a 1D selection polygon."; + + local_context.m_selectionPolygon.convertTo1D(); + + // Sanity check. + + // The user may select at the left of the x=0, but that does not make sense if + // the whole selected region is in the x axis negative space. + double range_start; + double range_end; + local_context.m_selectionPolygon.rangeX(range_start, range_end); + + qDebug() << "X axis range:" << range_start << "-" << range_end; + + // Having negative drift times does not make any sense. if(range_start < 0 && range_end < 0) return; @@ -216,7 +234,6 @@ // selected is the right one. If there are more than one traces selected, then // we cannot do anything. Display an error message. - // The QCustomPlot-based widget might contain more than one graph, and we // need to know on what graph the user is willing to perform the // integration. @@ -248,13 +265,10 @@ // qDebug() << ms_run_data_set_csp->getMsRunDataSetStats().toString(); - // Now we need to add a new step in that processing flow so that we document - // this new integration that we are performing. + // Create a processing step to document the specifics of this new integration. ProcessingStep *processing_step_p = new ProcessingStep(); - ProcessingSpec *processing_spec_p = new ProcessingSpec(); - MsFragmentationSpec ms_fragmentation_spec = local_processing_flow.getDefaultMsFragmentationSpec(); @@ -265,7 +279,7 @@ // flow " "is valid, using it:" //<< ms_fragmentation_spec.toString(); - processing_spec_p->setMsFragmentationSpec(ms_fragmentation_spec); + processing_step_p->setMsFragmentationSpec(ms_fragmentation_spec); } else { @@ -273,15 +287,21 @@ //"valid. Not using it."; } - // Now define the graph range for the integration operation. + processing_step_p->setSelectionPolygon(local_context.m_selectionPolygon); + + // We must say what is the data source processing type. + processing_step_p->setSrcProcessingType(pappso::Axis::x, "DT"); - processing_spec_p->setRange(range_start, range_end); + // It is essential that we document the relation between the axes and the + // corresponding data type. + processing_step_p->setDataKind(pappso::Axis::x, pappso::DataKind::dt); + processing_step_p->setDataKind(pappso::Axis::y, pappso::DataKind::unset); if(m_ui.integrateToRtPushButton->isChecked()) { // qDebug() << "Integrating to XIC chromatogram."; - processing_step_p->newSpec(ProcessingType("DT_TO_RT"), processing_spec_p); + processing_step_p->setDestProcessingType("RT"); local_processing_flow.push_back(processing_step_p); @@ -290,25 +310,25 @@ } else if(m_ui.integrateToMzPushButton->isChecked() || m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { if(m_ui.integrateToMzPushButton->isChecked()) { - qDebug() << "Integrating to mass spectrum."; - processing_step_p->newSpec(ProcessingType("DT_TO_MZ"), - processing_spec_p); + // qDebug() << "Integrating to mass spectrum."; + + processing_step_p->setDestProcessingType("MZ"); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { // qDebug() << "Integrating to rt|m/z color map."; - processing_step_p->newSpec(ProcessingType("DT_TO_RT_MZ"), - processing_spec_p); + + processing_step_p->setDestProcessingType("MZ_RT"); } else if(m_ui.integrateToDtMzPushButton->isChecked()) { // qDebug() << "Integrating to dt|m/z color map."; - processing_step_p->newSpec(ProcessingType("DT_TO_DT_MZ"), - processing_spec_p); + + processing_step_p->setDestProcessingType("DT_MZ"); } // At this point we need to define how the mass data integrator will @@ -329,8 +349,11 @@ // qDebug() //<< "The processing flow's default mz integ params are not valid."; - mz_integration_params = - *(local_processing_flow.mostRecentMzIntegrationParams()); + const pappso::MzIntegrationParams *mz_integration_params_p = + local_processing_flow.mostRecentMzIntegrationParams(); + + if(mz_integration_params_p != nullptr) + mz_integration_params = *mz_integration_params_p; } // If it is not valid, finally resort to the parameters that can be @@ -381,48 +404,40 @@ static_cast(mp_parentWnd) ->integrateToDtMz(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { static_cast(mp_parentWnd) - ->integrateToRtMz(plottable_p, local_processing_flow); + ->integrateToMzRt(plottable_p, local_processing_flow); } } else if(m_ui.integrateToDtPushButton->isChecked()) { // qDebug() << "Integrating to drift spectrum."; - processing_step_p->newSpec(ProcessingType("DT_TO_DT"), processing_spec_p); + processing_step_p->setDestProcessingType("DT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) ->integrateToDt(plottable_p, nullptr, local_processing_flow); } - else if(m_ui.integrateToRtDtPushButton->isChecked()) + else if(m_ui.integrateToDtRtPushButton->isChecked()) { // qDebug() << "Integrating to TIC|XIC chromatogram / drift spectrum // colormap."; - ProcessingSpec *spec_p = new ProcessingSpec(); - - processing_step_p->newSpec(ProcessingType("DT_TO_RT_DT"), spec_p); - - // We now need to specify the DT range. - - processing_step_p->newSpec(ProcessingType("DT_TO_ANY"), - processing_spec_p); + processing_step_p->setDestProcessingType("DT_RT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) - ->integrateToRtDt(plottable_p, local_processing_flow); + ->integrateToDtRt(plottable_p, local_processing_flow); } else if(m_ui.integrateToIntPushButton->isChecked()) { // qDebug() << "Integrating to TIC intensity."; - processing_step_p->newSpec(ProcessingType("DT_TO_INT"), - processing_spec_p); + processing_step_p->setDestProcessingType("INT"); local_processing_flow.push_back(processing_step_p); @@ -554,10 +569,10 @@ // qDebug() << "After filling-in by base class, the stanza is:" //<< m_analysisStanza; - m_plotWidgetPressedKeyCode = context.pressedKeyCode; + m_plotWidgetPressedKeyCode = context.m_pressedKeyCode; // Now handle here the mass specific data, like z, Mr, m/z. - if(context.pressedKeyCode == Qt::Key_Space) + if(context.m_pressedKeyCode == Qt::Key_Space) { QCPAbstractPlottable *plottable_p = plottableToBeUsedAsIntegrationSource(); @@ -594,7 +609,7 @@ mp_parentWnd->recordAnalysisStanza(stanza, plottable_p->pen().color()); } // End of - // if(context.baseContext.pressedKeyCode == Qt::Key_Space) + // if(context.m_baseContext.pressedKeyCode == Qt::Key_Space) } @@ -729,7 +744,7 @@ if(curChar == 'X') { stanza += QString("%1").arg( - context.lastCursorHoveredPoint.x(), 0, 'g', 6); + context.m_lastCursorHoveredPoint.x(), 0, 'g', 6); prevChar = ' '; continue; } @@ -740,7 +755,7 @@ // of the point at X. stanza += QString("%1").arg( static_cast(mp_plotWidget) - ->getYatX(context.lastCursorHoveredPoint.x(), + ->getYatX(context.m_lastCursorHoveredPoint.x(), static_cast(plottable_p)), 0, 'g', @@ -751,13 +766,13 @@ } if(curChar == 'x') { - stanza += QString("%1").arg(context.xDelta, 0, 'g', 6); + stanza += QString("%1").arg(context.m_xDelta, 0, 'g', 6); prevChar = ' '; continue; } if(curChar == 'y') { - stanza += QString("%1").arg(context.yDelta, 0, 'g', 6); + stanza += QString("%1").arg(context.m_yDelta, 0, 'g', 6); prevChar = ' '; continue; @@ -771,14 +786,15 @@ } if(curChar == 'b') { - stanza += QString("%1").arg(context.xRegionRangeStart, 0, 'f', 3); + stanza += + QString("%1").arg(context.m_xRegionRangeStart, 0, 'f', 3); prevChar = ' '; continue; } if(curChar == 'e') { - stanza += QString("%1").arg(context.xRegionRangeEnd, 0, 'f', 3); + stanza += QString("%1").arg(context.m_xRegionRangeEnd, 0, 'f', 3); prevChar = ' '; continue; diff -Nru minexpert2-7.4.1/src/gui/DriftSpecTracePlotWnd.cpp minexpert2-8.1.1/src/gui/DriftSpecTracePlotWnd.cpp --- minexpert2-7.4.1/src/gui/DriftSpecTracePlotWnd.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/DriftSpecTracePlotWnd.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -111,10 +111,8 @@ qualified_mass_spectra_sp, const ProcessingFlow &processing_flow) { - // qDebug(); - - // qDebug().noquote() << "Integrating to dt with processing flow:" - //<< processing_flow.toString(); + qDebug().noquote() << "Integrating to dt with processing flow:" + << processing_flow.toString(); // Get the ms run data set that for the graph we are going to base the // integration on. @@ -123,27 +121,44 @@ if(ms_run_data_set_csp == nullptr) qFatal("Cannot be that the pointer is nullptr."); - // We will try to limit the number of mass spectra to iterate through with the - // integration visitor. + // FIXME: BEGIN Sanity check that might be removed when the program is + // stabilized. + std::pair range_pair; - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); - - bool integration_rt = processing_flow.innermostRtRange(start_rt, end_rt); + bool integration_rt = processing_flow.innermostRange("ANY_RT", range_pair); if(!integration_rt) qFatal("Programming error."); - // First prepare a vector of QualifiedMassSpectrumCstSPtr + qDebug() << qSetRealNumberPrecision(10) << "Innermost RT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + + bool integration_dt = processing_flow.innermostRange("ANY_DT", range_pair); + + if(integration_dt) + qDebug() << qSetRealNumberPrecision(10) << "Innermost DT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + // FIXME: END Sanity check that might be removed when the program is + // stabilized. + + // First prepare a vector of QualifiedMassSpectrumCstSPtr. If the + // qualified_mass_spectra_sp is not empty, the + // fillInQualifiedMassSpectraVector() function below does not change the + // vector and returns its size. std::size_t qualified_mass_spectra_count = fillInQualifiedMassSpectraVector( ms_run_data_set_csp, qualified_mass_spectra_sp, processing_flow); + qDebug() + << "The number of selected mass spectra on the basis of rough RT/DT values:" + << qualified_mass_spectra_count; + if(!qualified_mass_spectra_count) return; - // qDebug() << "The number of remaining mass spectra:" - //<< qualified_mass_spectra_count; + // qDebug() << qSetRealNumberPrecision(10) << "Retention time of first + // spectrum:" + //<< qualified_mass_spectra_sp->front()->getRtInMinutes(); // Now start the actual integration work. @@ -153,7 +168,8 @@ new QualifiedMassSpectrumVectorMassDataIntegratorToDt( ms_run_data_set_csp, processing_flow, qualified_mass_spectra_sp); - mass_data_integrator_p->setMaxThreadUseCount(mp_programWindow->getMaxThreadUseCount()); + mass_data_integrator_p->setMaxThreadUseCount( + mp_programWindow->getMaxThreadUseCount()); // Ensure the mass data integrator messages are used. @@ -374,7 +390,7 @@ DriftSpecTracePlotWnd::integrateToRt(QCPAbstractPlottable *parent_plottable_p, const ProcessingFlow &processing_flow) { - // qDebug(); + qDebug(); if(parent_plottable_p == nullptr) qFatal("Cannot be that pointer is nullptr."); @@ -415,7 +431,7 @@ void -DriftSpecTracePlotWnd::integrateToRtMz(QCPAbstractPlottable *parent_plottable_p, +DriftSpecTracePlotWnd::integrateToMzRt(QCPAbstractPlottable *parent_plottable_p, const ProcessingFlow &processing_flow) { // qDebug(); @@ -423,13 +439,13 @@ if(parent_plottable_p == nullptr) qFatal("Cannot be that pointer is nullptr."); - mp_programWindow->integrateToRtMz( + mp_programWindow->integrateToMzRt( parent_plottable_p, nullptr, processing_flow); } void -DriftSpecTracePlotWnd::integrateToRtDt(QCPAbstractPlottable *parent_plottable_p, +DriftSpecTracePlotWnd::integrateToDtRt(QCPAbstractPlottable *parent_plottable_p, const ProcessingFlow &processing_flow) { // qDebug(); @@ -437,7 +453,7 @@ if(parent_plottable_p == nullptr) qFatal("Cannot be that pointer is nullptr."); - mp_programWindow->integrateToRtDt( + mp_programWindow->integrateToDtRt( parent_plottable_p, nullptr, processing_flow); } diff -Nru minexpert2-7.4.1/src/gui/DriftSpecTracePlotWnd.hpp minexpert2-8.1.1/src/gui/DriftSpecTracePlotWnd.hpp --- minexpert2-7.4.1/src/gui/DriftSpecTracePlotWnd.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/DriftSpecTracePlotWnd.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -83,9 +83,9 @@ const ProcessingFlow &processing_flow); void integrateToDtMz(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); - void integrateToRtMz(QCPAbstractPlottable *plottable_p, + void integrateToMzRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); - void integrateToRtDt(QCPAbstractPlottable *plottable_p, + void integrateToDtRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); public slots: diff -Nru minexpert2-7.4.1/src/gui/IsoSpecDlg.cpp minexpert2-8.1.1/src/gui/IsoSpecDlg.cpp --- minexpert2-7.4.1/src/gui/IsoSpecDlg.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/IsoSpecDlg.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -1124,10 +1124,10 @@ newIsotopeFrameGridLayout->addWidget(newIsotopeProbDoubleSpinBox, 0, 1, 1, 1); - QPushButton *plusIsotopePushButton = new QPushButton(newIsotopeFrame); - plusIsotopePushButton->setObjectName(QStringLiteral("plusIsotopePushButton")); + QPushButton *addIsotopePushButton = new QPushButton(newIsotopeFrame); + addIsotopePushButton->setObjectName(QStringLiteral("addIsotopePushButton")); - connect(plusIsotopePushButton, + connect(addIsotopePushButton, &QPushButton::clicked, this, &IsoSpecDlg::addIsotopeFrame); @@ -1137,33 +1137,33 @@ sizePolicy.setVerticalStretch(0); sizePolicy.setHeightForWidth( - plusIsotopePushButton->sizePolicy().hasHeightForWidth()); - plusIsotopePushButton->setSizePolicy(sizePolicy); + addIsotopePushButton->sizePolicy().hasHeightForWidth()); + addIsotopePushButton->setSizePolicy(sizePolicy); QIcon icon1; icon1.addFile( - QStringLiteral(":/images/plus.svg"), QSize(), QIcon::Normal, QIcon::Off); - plusIsotopePushButton->setIcon(icon1); + QStringLiteral(":/images/svg/add-isotope.svg"), QSize(), QIcon::Normal, QIcon::Off); + addIsotopePushButton->setIcon(icon1); - newIsotopeFrameGridLayout->addWidget(plusIsotopePushButton, 0, 2, 1, 1); + newIsotopeFrameGridLayout->addWidget(addIsotopePushButton, 0, 2, 1, 1); - QPushButton *minusIsotopePushButton = new QPushButton(isotopeFrame); - minusIsotopePushButton->setObjectName( - QStringLiteral("minusIsotopePushButton")); + QPushButton *removeIsotopePushButton = new QPushButton(isotopeFrame); + removeIsotopePushButton->setObjectName( + QStringLiteral("removeIsotopePushButton")); - connect(minusIsotopePushButton, + connect(removeIsotopePushButton, &QPushButton::clicked, this, &IsoSpecDlg::removeIsotopeFrame); sizePolicy.setHeightForWidth( - minusIsotopePushButton->sizePolicy().hasHeightForWidth()); - minusIsotopePushButton->setSizePolicy(sizePolicy); + removeIsotopePushButton->sizePolicy().hasHeightForWidth()); + removeIsotopePushButton->setSizePolicy(sizePolicy); QIcon icon; icon.addFile( - QStringLiteral(":/images/minus.svg"), QSize(), QIcon::Normal, QIcon::Off); - minusIsotopePushButton->setIcon(icon); + QStringLiteral(":/images/svg/remove-isotope.svg"), QSize(), QIcon::Normal, QIcon::Off); + removeIsotopePushButton->setIcon(icon); - newIsotopeFrameGridLayout->addWidget(minusIsotopePushButton, 0, 3, 1, 1); + newIsotopeFrameGridLayout->addWidget(removeIsotopePushButton, 0, 3, 1, 1); elementGroupVBoxLayout->addWidget(newIsotopeFrame); @@ -1255,7 +1255,7 @@ minusElementPushButton->setSizePolicy(sizePolicy); QIcon icon; icon.addFile( - QStringLiteral(":/images/minus.svg"), QSize(), QIcon::Normal, QIcon::Off); + QStringLiteral(":/images/svg/remove-chemical-element.svg"), QSize(), QIcon::Normal, QIcon::Off); minusElementPushButton->setIcon(icon); symbolLineEditHBoxLayout->addWidget(minusElementPushButton); @@ -1316,11 +1316,11 @@ isotopeFrameGridLayout->addWidget(isotopeProbDoubleSpinBox, 0, 1, 1, 1); - QPushButton *plusIsotopePushButton; - plusIsotopePushButton = new QPushButton(isotopeFrame); - plusIsotopePushButton->setObjectName(QStringLiteral("plusIsotopePushButton")); + QPushButton *addIsotopePushButton; + addIsotopePushButton = new QPushButton(isotopeFrame); + addIsotopePushButton->setObjectName(QStringLiteral("addIsotopePushButton")); - connect(plusIsotopePushButton, + connect(addIsotopePushButton, &QPushButton::clicked, this, &IsoSpecDlg::addIsotopeFrame); @@ -1329,34 +1329,34 @@ sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); sizePolicy.setHeightForWidth( - plusIsotopePushButton->sizePolicy().hasHeightForWidth()); - plusIsotopePushButton->setSizePolicy(sizePolicy); + addIsotopePushButton->sizePolicy().hasHeightForWidth()); + addIsotopePushButton->setSizePolicy(sizePolicy); QIcon icon1; icon1.addFile( - QStringLiteral(":/images/plus.svg"), QSize(), QIcon::Normal, QIcon::Off); - plusIsotopePushButton->setIcon(icon1); + QStringLiteral(":/images/svg/add-isotope.svg"), QSize(), QIcon::Normal, QIcon::Off); + addIsotopePushButton->setIcon(icon1); - isotopeFrameGridLayout->addWidget(plusIsotopePushButton, 0, 2, 1, 1); + isotopeFrameGridLayout->addWidget(addIsotopePushButton, 0, 2, 1, 1); - QPushButton *minusIsotopePushButton; - minusIsotopePushButton = new QPushButton(isotopeFrame); - minusIsotopePushButton->setObjectName( - QStringLiteral("minusIsotopePushButton")); + QPushButton *removeIsotopePushButton; + removeIsotopePushButton = new QPushButton(isotopeFrame); + removeIsotopePushButton->setObjectName( + QStringLiteral("removeIsotopePushButton")); - connect(minusIsotopePushButton, + connect(removeIsotopePushButton, &QPushButton::clicked, this, &IsoSpecDlg::removeIsotopeFrame); sizePolicy.setHeightForWidth( - minusIsotopePushButton->sizePolicy().hasHeightForWidth()); - minusIsotopePushButton->setSizePolicy(sizePolicy); + removeIsotopePushButton->sizePolicy().hasHeightForWidth()); + removeIsotopePushButton->setSizePolicy(sizePolicy); QIcon icon; icon.addFile( - QStringLiteral(":/images/minus.svg"), QSize(), QIcon::Normal, QIcon::Off); - minusIsotopePushButton->setIcon(icon); + QStringLiteral(":/images/svg/remove-isotope.svg"), QSize(), QIcon::Normal, QIcon::Off); + removeIsotopePushButton->setIcon(icon); - isotopeFrameGridLayout->addWidget(minusIsotopePushButton, 0, 3, 1, 1); + isotopeFrameGridLayout->addWidget(removeIsotopePushButton, 0, 3, 1, 1); QVBoxLayout *elementGroupVBoxLayout = static_cast(elementGroupBox->layout()); diff -Nru minexpert2-7.4.1/src/gui/MassSpecTracePlotCompositeWidget.cpp minexpert2-8.1.1/src/gui/MassSpecTracePlotCompositeWidget.cpp --- minexpert2-7.4.1/src/gui/MassSpecTracePlotCompositeWidget.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/MassSpecTracePlotCompositeWidget.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -52,6 +52,7 @@ #include #include #include +#include /////////////////////// Local includes @@ -204,7 +205,8 @@ "Set charge &minimal fractional part", dynamic_cast(this)); set_charge_minimal_fractional_part_action_p->setStatusTip( "Set the charge minimal fractional part (typically 0.99)"); - set_charge_minimal_fractional_part_action_p->setShortcut(QKeySequence("Ctrl+S, M")); + set_charge_minimal_fractional_part_action_p->setShortcut( + QKeySequence("Ctrl+S, M")); connect( set_charge_minimal_fractional_part_action_p, &QAction::triggered, [this]() { @@ -656,6 +658,7 @@ msg, source_plottable_p->pen().color()); } + void MassSpecTracePlotCompositeWidget::mainMenuPushButtonClicked() { @@ -686,15 +689,15 @@ // First call the base class that will fill-in the generic fields if the space // char was pressed. - BaseTracePlotCompositeWidget::plotWidgetKeyPressEvent(context.baseContext); + BaseTracePlotCompositeWidget::plotWidgetKeyPressEvent(context.m_baseContext); // qDebug() << "After filling-in by base class, the stanza is:" //<< m_analysisStanza; - m_plotWidgetPressedKeyCode = context.baseContext.pressedKeyCode; + m_plotWidgetPressedKeyCode = context.m_baseContext.m_pressedKeyCode; // Now handle here the mass specific data, like z, Mr, m/z. - if(context.baseContext.pressedKeyCode == Qt::Key_Space) + if(context.m_baseContext.m_pressedKeyCode == Qt::Key_Space) { QCPAbstractPlottable *plottable_p = plottableToBeUsedAsIntegrationSource(); @@ -733,7 +736,7 @@ mp_parentWnd->recordAnalysisStanza(stanza, plottable_p->pen().color()); } // End of - // if(context.baseContext.pressedKeyCode == Qt::Key_Space) + // if(context.m_baseContext.m_pressedKeyCode == Qt::Key_Space) } @@ -745,10 +748,10 @@ // The release event sets the local key code to 0 so that we know that no // keyboard key is being pressed *now*. - m_plotWidgetPressedKeyCode = context.pressedKeyCode; + m_plotWidgetPressedKeyCode = context.m_pressedKeyCode; // qDebug() << "The key:" << m_plotWidgetPressedKeyCode - //<< "the modifiers:" << context.keyboardModifiers; + //<< "the modifiers:" << context.m_keyboardModifiers; } @@ -764,26 +767,26 @@ // We want to append the deconvolution results to the status text. // QString new_text = // m_ui.statusLineEdit->text() + QString("-- z: %1 - m/z: %2 - Mr: %3") - //.arg(context.lastZ) - //.arg(context.lastMz) - //.arg(context.lastMr); + //.arg(context.m_lastZ) + //.arg(context.m_lastMz) + //.arg(context.m_lastMr); QString new_text = QString("[%1--%2] - delta: %3 -- z: %4 - m/z: %5 - Mr: %6") - .arg(std::min(context.baseContext.xRegionRangeStart, - context.baseContext.xRegionRangeEnd), + .arg(std::min(context.m_baseContext.m_xRegionRangeStart, + context.m_baseContext.m_xRegionRangeEnd), 0, 'f', 3) - .arg(std::max(context.baseContext.xRegionRangeStart, - context.baseContext.xRegionRangeEnd), + .arg(std::max(context.m_baseContext.m_xRegionRangeStart, + context.m_baseContext.m_xRegionRangeEnd), 0, 'f', 3) - .arg(fabs(context.baseContext.xDelta), 0, 'f', 3) - .arg(context.lastZ) - .arg(context.lastMz, 0, 'f', 3) - .arg(context.lastMr); + .arg(fabs(context.m_baseContext.m_xDelta), 0, 'f', 3) + .arg(context.m_lastZ) + .arg(context.m_lastMz, 0, 'f', 3) + .arg(context.m_lastMr); m_ui.statusLineEdit->setText(new_text); } @@ -795,7 +798,7 @@ { // We want to append the resolving power results to the status text. QString new_text = m_ui.statusLineEdit->text() + - QString("-- Rp: %1").arg(context.lastResolvingPower); + QString("-- Rp: %1").arg(context.m_lastResolvingPower); m_ui.statusLineEdit->setText(new_text); } @@ -824,8 +827,8 @@ // in the base class function. pappso::BasePlotContext local_context = context; - local_context.xRegionRangeStart = m_integrationRange.lower; - local_context.xRegionRangeEnd = m_integrationRange.upper; + local_context.m_xRegionRangeStart = m_integrationRange.lower; + local_context.m_xRegionRangeEnd = m_integrationRange.upper; if(m_isSinglePointIntegrationMode) integrationRequested(local_context); @@ -836,21 +839,39 @@ MassSpecTracePlotCompositeWidget::integrationRequested( const pappso::BasePlotContext &context) { - // qDebug().noquote() << "context:" << context.toString(); + qDebug().noquote() << "context:" << context.toString(); // The reference implementation is the TicXicChromTracePlotCompositeWidget // one. Look there for all the explanative comments. - // Immediately check if the selection range makes sense. For example, having - // both the start/end values in the negative values does not mean anything - // with respect to mass spectrum data! - - // Remember that the xregion start and end are not sorted. - double range_start = - std::min(context.xRegionRangeStart, context.xRegionRangeEnd); - double range_end = - std::max(context.xRegionRangeStart, context.xRegionRangeEnd); + // Make a local copy of the context because we may need to modify it. + pappso::BasePlotContext local_context = context; + + // Check if the selection polygon contain meaningful data. We are in trace + // plot widget, so the selection polygon might be in the form of a + // mono-dimensional polygon, although this is not mandatory. But we rely on + // the selection polygon to be of 1 or 2 dimension for some optimizations. So, + // if the polygon is 2D, convert it to 1D. + + if(local_context.m_selectionPolygon.is2D()) + qDebug() << "Odd situation where the selection polygon is two-dimensional " + "and the trace plot selection is mono-dimensional. Converting " + "it to a 1D selection polygon."; + + local_context.m_selectionPolygon.convertTo1D(); + + // Sanity check. + // The user may select at the left of the x=0, but that does not make sense if + // the whole selected region is in the x axis negative space. + double range_start; + double range_end; + + local_context.m_selectionPolygon.rangeX(range_start, range_end); + + qDebug() << "X axis range:" << range_start << "-" << range_end; + + // Having negative retention times does not make any sense. if(range_start < 0 && range_end < 0) return; @@ -868,7 +889,8 @@ return; } - // Create a local copy of the processing flow. + // Create a local copy of the processing flow so that we can modify it by + // adding the new processing step that describes what we are doing now. ProcessingFlow local_processing_flow = getProcessingFlowForPlottable(plottable_p); @@ -881,13 +903,10 @@ // qDebug() << ms_run_data_set_csp->getMsRunDataSetStats().toString(); - // Now we need to add a new step in that processing flow so that we document - // this new integration that we are performing. + // Create a processing step to document the specifics of this new integration. ProcessingStep *processing_step_p = new ProcessingStep(); - ProcessingSpec *processing_spec_p = new ProcessingSpec(); - MsFragmentationSpec ms_fragmentation_spec = local_processing_flow.getDefaultMsFragmentationSpec(); @@ -898,7 +917,7 @@ // flow " "is valid, using it : " //<< ms_fragmentation_spec.toString(); - processing_spec_p->setMsFragmentationSpec(ms_fragmentation_spec); + processing_step_p->setMsFragmentationSpec(ms_fragmentation_spec); } else { @@ -906,15 +925,24 @@ //"valid. Not using it."; } + // Now make sure we document the selection polygon. // Now define the graph range for the integration operation. - processing_spec_p->setRange(range_start, range_end); + processing_step_p->setSelectionPolygon(local_context.m_selectionPolygon); + + // We must say what is the data source processing type. + processing_step_p->setSrcProcessingType(pappso::Axis::x, "MZ"); + + // It is essential that we document the relation between the axes and the + // corresponding data type. + processing_step_p->setDataKind(pappso::Axis::x, pappso::DataKind::mz); + processing_step_p->setDataKind(pappso::Axis::y, pappso::DataKind::unset); if(m_ui.integrateToRtPushButton->isChecked()) { // qDebug() << "Integrating to XIC chromatogram."; - processing_step_p->newSpec(ProcessingType("MZ_TO_RT"), processing_spec_p); + processing_step_p->setDestProcessingType("RT"); local_processing_flow.push_back(processing_step_p); @@ -923,25 +951,22 @@ } else if(m_ui.integrateToMzPushButton->isChecked() || m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { if(m_ui.integrateToMzPushButton->isChecked()) { // qDebug() << "Integrating to mass spectrum."; - processing_step_p->newSpec(ProcessingType("MZ_TO_MZ"), - processing_spec_p); + processing_step_p->setDestProcessingType("MZ"); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { // qDebug() << "Integrating to rt|m/z color map."; - processing_step_p->newSpec(ProcessingType("MZ_TO_RT_MZ"), - processing_spec_p); + processing_step_p->setDestProcessingType("MZ_RT"); } else if(m_ui.integrateToDtMzPushButton->isChecked()) { // qDebug() << "Integrating to dt|m/z color map."; - processing_step_p->newSpec(ProcessingType("MZ_TO_DT_MZ"), - processing_spec_p); + processing_step_p->setDestProcessingType("DT_MZ"); } // At this point we need to define how the mass data integrator will @@ -962,8 +987,11 @@ // qDebug() //<< "The processing flow's default mz integ params are not valid."; - mz_integration_params = - *(local_processing_flow.mostRecentMzIntegrationParams()); + const pappso::MzIntegrationParams *mz_integration_params_p = + local_processing_flow.mostRecentMzIntegrationParams(); + + if(mz_integration_params_p != nullptr) + mz_integration_params = *mz_integration_params_p; } // If it is not valid, finally resort to the parameters that can be @@ -985,7 +1013,7 @@ // Note that we cannot integrate mass spectra with a high resolution // here. We need to reduce the resolution to integer resolution. if(m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { mz_integration_params.setBinningType(pappso::BinningType::NONE); mz_integration_params.setDecimalPlaces(0); @@ -1016,49 +1044,40 @@ static_cast(mp_parentWnd) ->integrateToDtMz(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { static_cast(mp_parentWnd) - ->integrateToRtMz(plottable_p, local_processing_flow); + ->integrateToMzRt(plottable_p, local_processing_flow); } } else if(m_ui.integrateToDtPushButton->isChecked()) { - // qDebug() << "Integrating to drift spectrum."; + qDebug() << "Integrating to drift spectrum."; - processing_step_p->newSpec(ProcessingType("MZ_TO_DT"), processing_spec_p); + processing_step_p->setDestProcessingType("DT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) ->integrateToDt(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtDtPushButton->isChecked()) + else if(m_ui.integrateToDtRtPushButton->isChecked()) { // qDebug() << "Integrating to TIC|XIC chromatogram / drift spectrum // colormap."; - - ProcessingSpec *spec_p = new ProcessingSpec(); - - processing_step_p->newSpec(ProcessingType("MZ_TO_RT_DT"), spec_p); - - // We now need to specify the MZ range. - - processing_step_p->newSpec(ProcessingType("MZ_TO_ANY"), - processing_spec_p); + processing_step_p->setDestProcessingType("DT_RT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) - ->integrateToRtDt(plottable_p, local_processing_flow); + ->integrateToDtRt(plottable_p, local_processing_flow); } else if(m_ui.integrateToIntPushButton->isChecked()) { // qDebug() << "Integrating to TIC intensity."; - processing_step_p->newSpec(ProcessingType("MZ_TO_INT"), - processing_spec_p); + processing_step_p->setDestProcessingType("INT"); local_processing_flow.push_back(processing_step_p); @@ -1162,7 +1181,8 @@ "integration " "params are not available in the processing flow."); - if(mz_integration_params_p->getBinningType() == pappso::BinningType::NONE) + if(mz_integration_params_p->getBinningType() == + pappso::BinningType::NONE) { pappso::TraceMinusCombiner trace_minus_combiner; pappso::TracePlusCombiner trace_plus_combiner; @@ -1595,14 +1615,17 @@ // If the deconvolution was successful, than lastMz is the right // value. Otherwise it is the lastCursorHoveredPoint. - if(context.lastMz != std::numeric_limits::min()) + if(context.m_lastMz != std::numeric_limits::min()) { - stanza += QString("%1").arg(context.lastMz, 0, 'g', 6); + stanza += QString("%1").arg(context.m_lastMz, 0, 'g', 6); } else { stanza += QString("%1").arg( - context.baseContext.lastCursorHoveredPoint.x(), 0, 'g', 6); + context.m_baseContext.m_lastCursorHoveredPoint.x(), + 0, + 'g', + 6); } prevChar = ' '; @@ -1614,12 +1637,12 @@ // not as an integration to INT, but simply as the y coordinate // of the point at X. - if(context.lastMz != std::numeric_limits::min()) + if(context.m_lastMz != std::numeric_limits::min()) { stanza += QString("%1").arg( static_cast( mp_plotWidget) - ->getYatX(context.lastMz, + ->getYatX(context.m_lastMz, static_cast(plottable_p)), 0, 'g', @@ -1630,8 +1653,9 @@ stanza += QString("%1").arg( static_cast( mp_plotWidget) - ->getYatX(context.baseContext.lastCursorHoveredPoint.x(), - static_cast(plottable_p)), + ->getYatX( + context.m_baseContext.m_lastCursorHoveredPoint.x(), + static_cast(plottable_p)), 0, 'g', 6); @@ -1643,7 +1667,7 @@ if(curChar == 'x') { stanza += - QString("%1").arg(context.baseContext.xDelta, 0, 'g', 6); + QString("%1").arg(context.m_baseContext.m_xDelta, 0, 'g', 6); prevChar = ' '; continue; } @@ -1656,14 +1680,14 @@ } if(curChar == 'z') { - stanza += QString("%1").arg(context.lastZ); + stanza += QString("%1").arg(context.m_lastZ); prevChar = ' '; continue; } if(curChar == 'M') { - stanza += QString("%1").arg(context.lastMr, 0, 'f', 6); + stanza += QString("%1").arg(context.m_lastMr, 0, 'f', 6); prevChar = ' '; continue; @@ -1678,7 +1702,7 @@ if(curChar == 'b') { stanza += QString("%1").arg( - context.baseContext.xRegionRangeStart, 0, 'f', 3); + context.m_baseContext.m_xRegionRangeStart, 0, 'f', 3); prevChar = ' '; continue; @@ -1686,7 +1710,7 @@ if(curChar == 'e') { stanza += QString("%1").arg( - context.baseContext.xRegionRangeEnd, 0, 'f', 3); + context.m_baseContext.m_xRegionRangeEnd, 0, 'f', 3); prevChar = ' '; continue; diff -Nru minexpert2-7.4.1/src/gui/MassSpecTracePlotWnd.cpp minexpert2-8.1.1/src/gui/MassSpecTracePlotWnd.cpp --- minexpert2-7.4.1/src/gui/MassSpecTracePlotWnd.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/MassSpecTracePlotWnd.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -183,297 +183,6 @@ } -#if 0 - - // Old version deemed to be removed. - void - MassSpecTracePlotWnd::integrateToMz(QCPAbstractPlottable *parent_plottable_p, - const ProcessingFlow &processing_flow) - { - - // qDebug().noquote() << "Integrating to mz with processing flow:" - //<< processing_flow.toString(); - -#if 0 - // NO BINNING - pappso::MzIntegrationParams mz_integration_params( - std::numeric_limits::max(), // smallest m/z - std::numeric_limits::min(), // greatest m/z - pappso::BinningType::NONE, - -1, // decimal_places - pappso::PrecisionFactory::getDaltonInstance(0.05), - false, // apply_mz_shift - 0.0, // mz_shift - true); // remove_zero_val_data_points -#endif -#if 0 - // ARBITRARY BINNING - pappso::MzIntegrationParams mz_integration_params( - std::numeric_limits::max(), - std::numeric_limits::min(), - pappso::BinningType::ARBITRARY, - -1, - // pappso::PrecisionFactory::getDaltonInstance(0.05), - pappso::PrecisionFactory::getDaltonInstance(0.1), - false, - 0.0, - true); -#endif - - // Get the ms run data set that for the graph we are going to base the - // integration on. - MsRunDataSetCstSPtr ms_run_data_set_csp = - processing_flow.getMsRunDataSetCstSPtr(); - if(ms_run_data_set_csp == nullptr) - qFatal("Cannot be that the pointer is nullptr."); - - // What integration parameters are we going to use ? Since we do integrate to - // a mass spectrum it is compulsory that the most recent step has valid mz - // integration params. - - // Set aside an object for later use. - const pappso::MzIntegrationParams *mz_integration_params_p = - processing_flow.mostRecentStep()->getMzIntegrationParamsPtr(); - - if(mz_integration_params_p == nullptr || !mz_integration_params_p->isValid()) - qFatal( - "Programming error. Cannot be that integration to m/z has no valid mz " - "integration parameters set."); - - // Allocate a mass data integrator to integrate the data. - - // Pass the integrator the flow we got as param and that describes in its most - // recent step the integration that it should perform. - MsRunDataSetTreeMassDataIntegratorToMz *mass_data_integrator_p = - new MsRunDataSetTreeMassDataIntegratorToMz(ms_run_data_set_csp, - processing_flow); - - // Ensure the mass data integrator messages are used. - - connect(mass_data_integrator_p, - &MassDataIntegrator::logTextToConsoleSignal, - mp_programWindow, - &ProgramWindow::logTextToConsole); - - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - - MassDataIntegratorTask *mass_data_integrator_task_p = - new MassDataIntegratorTask(); - - // This signal starts the computation in the MassDataIntegratorTask object. - connect(this, - - static_cast( - &MassSpecTracePlotWnd::integrateToMzSignal), - - mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::integrateToMz), - - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // Allocate the thread in which the integrator task will run. - QThread *thread_p = new QThread; - - // Move the task to the matching thread. - mass_data_integrator_task_p->moveToThread(thread_p); - thread_p->start(); - - // When the read task finishes, it sends a signal that we trap to go on with - // the plot widget creation stuff. - - // Since we allocated the QThread dynamically we need to be able to destroy it - // later, so make the connection. - - connect(mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - this, - [this, - thread_p, - mass_data_integrator_p, - parent_plottable_p, - mass_data_integrator_task_p]() { - // Do not forget that we have to delete the MassDataIntegratorTask - // allocated instance. - mass_data_integrator_task_p->deleteLater(); - // Once the task has been labelled to be deleted later, we can stop - // the thread and ask for it to also be deleted later. - thread_p->deleteLater(), thread_p->quit(); - thread_p->wait(); - this->finishedIntegratingToMz(mass_data_integrator_p, - parent_plottable_p); - }); - - - // Allocate a new TaskMonitorCompositeWidget that will receive all the - // integrator's signals and provide feedback to the user about the ongoing - // integration. - - TaskMonitorCompositeWidget *task_monitor_composite_widget_p = - mp_programWindow->getTaskMonitorWnd()->addTaskMonitorWidget(Qt::red); - - // Initialize the monitor composite widget's widgets and make all the - // connections mass data integrator <--> widget. - - task_monitor_composite_widget_p->setMsRunIdText( - ms_run_data_set_csp->getMsRunId()->getSampleName()); - task_monitor_composite_widget_p->setTaskDescriptionText( - "Integrating to mass spectrum"); - task_monitor_composite_widget_p->setProgressBarMinValue(0); - - // Make the connections - - // When the integrator task instance has finished working, it will send a - // signal that we trap to finally destroy (after a time lag of some seconds, - // the monitor widget. - - connect(mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - - task_monitor_composite_widget_p, - - &TaskMonitorCompositeWidget::taskFinished, - - Qt::QueuedConnection); - - - // If the user clicks the cancel button, relay the signal to the loader. - connect(task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::cancelTaskSignal, - mass_data_integrator_p, - &MassDataIntegrator::cancelOperation); - - // We need to register the meta type for std::size_t because otherwise it - // cannot be shipped though signals. - - qRegisterMetaType("std::size_t"); - - // Now make all the connections that will allow the integrator to provide - // dynamic feedback to the user via the task monitor widget. - task_monitor_composite_widget_p->makeMassDataIntegratorConnections( - mass_data_integrator_p); - - // qDebug() << "Going to emit integrateToMzSignal with mass data integrator:" - //<< mass_data_integrator_p; - - emit integrateToMzSignal(mass_data_integrator_p); - - // We do not want to make signal/slot calls more than once. This is because - // one user might well trigger more than one integration from this window to a - // mass spectrum. Thus we do not want that *this window be still connected to - // the specific mass_data_integrator_task_p when a new integration is - // triggered. We want the signal/slot pairs to be contained to specific - // objects. Each MassSpecTracePlotWnd::integrateToMz() call must be contained - // to a this/mass_data_integrator_task_p specific signal/slot pair. - disconnect(this, - - static_cast( - &MassSpecTracePlotWnd::integrateToMzSignal), - - mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::integrateToMz)); - } - - - // Old version - void - MassSpecTracePlotWnd::finishedIntegratingToMz( - MsRunDataSetTreeMassDataIntegratorToMz *mass_data_integrator_p, - QCPAbstractPlottable *parent_plottable_p) - { - - // This function is actually a slot that is called when the integration to mz - // is terminated in a QThread. - - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - - // We get back the integrator that was made to work in another thread. Now get - // the obtained data and work with them. - - // Store the MsRunDataSetSPtr for later use before deleting the integrattor. - - MsRunDataSetCstSPtr ms_run_data_set_csp = - mass_data_integrator_p->getMsRunDataSet(); - - pappso::Trace integrated_trace = - mass_data_integrator_p->getMapTrace().toTrace(); - // qDebug() << "mass spectrum trace size:" << integrated_trace.size(); - - if(!integrated_trace.size()) - { - qDebug() << "There is not a single point in the integrated trace."; - return; - } - - // Also, do not forget to copy the processing flow from the integrator. This - // processing flow will be set into the plot widget ! - - ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); - - // Sanity check - if(ms_run_data_set_csp != processing_flow.getMsRunDataSetCstSPtr()) - qFatal("Cannot be that the ms run data set pointers be different."); - - // Finally, do not forget that we need to delete the integrator now that the - // calculation is finished. - delete mass_data_integrator_p; - mass_data_integrator_p = nullptr; - - // At this point, we need to get a color for the plot. That color needs to be - // that of the parent. - QColor plot_color = parent_plottable_p->pen().color(); - - // We need to establish what widget is the destination of the integration. If - // one or more than a widget is/are pinned-down, then that/these should be the - // destinations. If no widget is pinned-down, then a new plot widget needs to - // be created. - - std::vector pinned_down_widgets = - pinnedDownWidgets(); - - if(pinned_down_widgets.size()) - { - for(auto &&pinned_down_widget : pinned_down_widgets) - static_cast(pinned_down_widget) - ->addTrace(integrated_trace, - static_cast(parent_plottable_p), - ms_run_data_set_csp, - ms_run_data_set_csp->getMsRunId()->getSampleName(), - processing_flow, - plot_color); - } - else - addTracePlot(integrated_trace, - ms_run_data_set_csp, - processing_flow, - plot_color, - static_cast(parent_plottable_p)); - - // At this point, if the window is really not visible, then show it, otherwise - // I was told that the user does not think that they can ask for the window to - // show up in the main program window. - - if(!isVisible()) - { - showWindow(); - } - } - -#endif - - void MassSpecTracePlotWnd::integrateToMz( QCPAbstractPlottable *parent_plottable_p, @@ -481,8 +190,8 @@ qualified_mass_spectra_sp, const ProcessingFlow &processing_flow) { - // qDebug().noquote() << "Integrating to mz with processing flow:" - //<< processing_flow.toString(); + qDebug().noquote() << "Integrating to mz with processing flow:" + << processing_flow.toString(); // Get the ms run data set that for the graph we are going to base the // integration on. @@ -491,6 +200,24 @@ if(ms_run_data_set_csp == nullptr) qFatal("Cannot be that the pointer is nullptr."); + // FIXME: BEGIN Sanity check that might be removed when the program is stabilized. + std::pair range_pair; + + bool integration_rt = processing_flow.innermostRange("ANY_RT", range_pair); + + if(!integration_rt) + qFatal("Programming error."); + + qDebug() << qSetRealNumberPrecision(10) << "Innermost RT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + + bool integration_dt = processing_flow.innermostRange("ANY_DT", range_pair); + + if(integration_dt) + qDebug() << qSetRealNumberPrecision(10) << "Innermost DT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + // FIXME: END Sanity check that might be removed when the program is stabilized. + // What integration parameters are we going to use ? Since we do integrate to // a mass spectrum it is compulsory that the most recent step has valid mz // integration params. @@ -504,17 +231,21 @@ "Programming error. Cannot be that integration to m/z has no valid mz " "integration parameters set."); - // First prepare a vector of QualifiedMassSpectrumCstSPtr + // First prepare a vector of QualifiedMassSpectrumCstSPtr. If the + // qualified_mass_spectra_sp is not empty, the + // fillInQualifiedMassSpectraVector() function below does not change the + // vector and returns its size. std::size_t qualified_mass_spectra_count = fillInQualifiedMassSpectraVector( ms_run_data_set_csp, qualified_mass_spectra_sp, processing_flow); + qDebug() + << "The number of selected mass spectra on the basis of rough RT/DT values:" + << qualified_mass_spectra_count; + if(!qualified_mass_spectra_count) return; - // qDebug() << "The number of remaining mass spectra:" - //<< qualified_mass_spectra_count; - // Now start the actual integration work. // Allocate a mass data integrator to integrate the data. @@ -523,7 +254,8 @@ new QualifiedMassSpectrumVectorMassDataIntegratorToMz( ms_run_data_set_csp, processing_flow, qualified_mass_spectra_sp); - mass_data_integrator_p->setMaxThreadUseCount(mp_programWindow->getMaxThreadUseCount()); + mass_data_integrator_p->setMaxThreadUseCount( + mp_programWindow->getMaxThreadUseCount()); // Ensure the mass data integrator messages are used. @@ -669,7 +401,7 @@ QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p, QCPAbstractPlottable *parent_plottable_p) { - // qDebug(); + qDebug(); // This function is actually a slot that is called when the integration to // mz is terminated in a QThread. @@ -770,13 +502,13 @@ void -MassSpecTracePlotWnd::integrateToRtMz(QCPAbstractPlottable *plottable_p, +MassSpecTracePlotWnd::integrateToMzRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow) { if(plottable_p == nullptr) qFatal("Cannot be that pointer is nullptr."); - mp_programWindow->integrateToRtMz(plottable_p, nullptr, processing_flow); + mp_programWindow->integrateToMzRt(plottable_p, nullptr, processing_flow); } @@ -792,13 +524,13 @@ void -MassSpecTracePlotWnd::integrateToRtDt(QCPAbstractPlottable *plottable_p, +MassSpecTracePlotWnd::integrateToDtRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow) { if(plottable_p == nullptr) qFatal("Cannot be that pointer is nullptr."); - mp_programWindow->integrateToRtDt(plottable_p, nullptr, processing_flow); + mp_programWindow->integrateToDtRt(plottable_p, nullptr, processing_flow); } diff -Nru minexpert2-7.4.1/src/gui/MassSpecTracePlotWnd.hpp minexpert2-8.1.1/src/gui/MassSpecTracePlotWnd.hpp --- minexpert2-7.4.1/src/gui/MassSpecTracePlotWnd.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/MassSpecTracePlotWnd.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -45,8 +45,6 @@ /////////////////////// Local includes #include "BaseTracePlotWnd.hpp" #include "MassSpecTracePlotCompositeWidget.hpp" -#include "../nongui/MsRunDataSetTreeMassDataIntegratorToMz.hpp" - #include "../nongui/QualifiedMassSpectrumVectorMassDataIntegratorToMz.hpp" namespace msxps @@ -85,7 +83,7 @@ void integrateToRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); - void integrateToRtMz(QCPAbstractPlottable *plottable_p, + void integrateToMzRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); void integrateToDt(QCPAbstractPlottable *plottable_p, @@ -94,7 +92,7 @@ void integrateToDtMz(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); - void integrateToRtDt(QCPAbstractPlottable *plottable_p, + void integrateToDtRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); void setMinimalChargeFractionalPartPinnedDownWidgets(double value); @@ -108,8 +106,6 @@ signals: - void integrateToMzSignal( - MsRunDataSetTreeMassDataIntegratorToMz *mass_data_integrator_p); void integrateToMzSignal( QualifiedMassSpectrumVectorMassDataIntegratorToMz *mass_data_integrator_p); diff -Nru minexpert2-7.4.1/src/gui/MsRunDataSetTableViewModel.cpp minexpert2-8.1.1/src/gui/MsRunDataSetTableViewModel.cpp --- minexpert2-7.4.1/src/gui/MsRunDataSetTableViewModel.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/MsRunDataSetTableViewModel.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -193,11 +193,11 @@ switch(ms_level_int) { case 1: - return QIcon(":/images/ms-level-1.png"); + return QIcon(":/images/svg/ms-level-1.svg"); case 2: - return QIcon(":/images/ms-level-2.png"); + return QIcon(":/images/svg/ms-level-2.svg"); case 3: - return QIcon(":/images/ms-level-3.png"); + return QIcon(":/images/svg/ms-level-3.svg"); default: return QVariant(); } diff -Nru minexpert2-7.4.1/src/gui/MsRunDataSetTableViewProxyModel.cpp minexpert2-8.1.1/src/gui/MsRunDataSetTableViewProxyModel.cpp --- minexpert2-7.4.1/src/gui/MsRunDataSetTableViewProxyModel.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/MsRunDataSetTableViewProxyModel.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -46,6 +46,7 @@ #include "MsRunDataSetTableViewModel.hpp" #include "MsRunDataSetTableViewProxyModel.hpp" #include "MsRunDataSetTableViewItem.hpp" +#include "../nongui/ProcessingStep.hpp" namespace msxps @@ -141,8 +142,8 @@ } - // Range of values pattern (xxx - yyy) - regexp.setPattern("^\\s*(\\d+)\\s*-\\s*(\\d+)\\s*$"); + // Range of values pattern (xxx -- yyy) + regexp.setPattern("^\\s*(\\d+)\\s*--\\s*(\\d+)\\s*$"); match = regexp.match(text); @@ -461,6 +462,8 @@ MsRunDataSetTableViewProxyModel::parseDoubleString(const QString &text, double accepted_lower_value) { + qDebug() << "text:" << text; + // The accepted syntax is like this: // // xxx @@ -542,9 +545,10 @@ } - // Range of values pattern (xxx - yyy) - regexp.setPattern("^\\s*" + sci_number + "\\s*-\\s*" + sci_number + "\\s*$"); + // Range of values pattern (xxx -- yyy) + regexp.setPattern("^\\s*" + sci_number + "\\s*--\\s*" + sci_number + "\\s*$"); + qDebug() << "testing range:" << regexp.pattern(); match = regexp.match(text); @@ -563,12 +567,16 @@ range_pair.second = upper_value_string.toDouble(&ok); if(!ok || range_pair.second < accepted_lower_value) - return std::pair(std::numeric_limits::max(), - std::numeric_limits::min()); + { + qDebug() << "Failed to convert or was below lower."; + + return std::pair(std::numeric_limits::max(), + std::numeric_limits::min()); + } // At this point we have the pair. - // qDebug() << "pair:" << range_pair; + qDebug() << "pair:" << range_pair; return range_pair; } @@ -627,7 +635,7 @@ // qDebug() << "text that matched:" << text; // By essence the upper value is max. - range_pair.second = std::numeric_limits::max(); + range_pair.second = std::numeric_limits::max(); // Get the string value. QString lower_value_string = match.captured(1); @@ -779,7 +787,7 @@ if(m_dtValuesPair.first == std::numeric_limits::max() || m_dtValuesPair.second == std::numeric_limits::min()) { - // qDebug(); + qDebug(); return false; } } @@ -858,52 +866,6 @@ bool -MsRunDataSetTableViewProxyModel::fillInProcessingFlow( - ProcessingFlow &processing_flow) -{ - bool was_correctly_filled_in = false; - - MsFragmentationSpec ms_fragmentation_spec; - - if(m_msLevel) - ms_fragmentation_spec.setMsLevel(m_msLevel); - - if(ms_fragmentation_spec.isValid()) - { - processing_flow.setDefaultMsFragmentationSpec(ms_fragmentation_spec); - was_correctly_filled_in = true; - } - - ProcessingStep *new_processing_step_p = new ProcessingStep; - - if(isValidFilterPair(m_rtValuesPair)) - { - ProcessingSpec *new_processing_spec_p = - new ProcessingSpec(m_rtValuesPair.first, m_rtValuesPair.second); - - new_processing_step_p->newSpec("RT_TO_ANY", new_processing_spec_p); - was_correctly_filled_in = true; - } - - if(isValidFilterPair(m_dtValuesPair)) - { - ProcessingSpec *new_processing_spec_p = - new ProcessingSpec(m_dtValuesPair.first, m_dtValuesPair.second); - - new_processing_step_p->newSpec("DT_TO_ANY", new_processing_spec_p); - was_correctly_filled_in = true; - } - - if(was_correctly_filled_in) - processing_flow.push_back(new_processing_step_p); - else - delete new_processing_step_p; - - return was_correctly_filled_in; -} - - -bool MsRunDataSetTableViewProxyModel::isValidFilterPair( const std::pair &pair) const { @@ -1102,8 +1064,7 @@ // If sep ';' does not match anywhere in the string, split() returns a // single-element list containing this string. - QStringList mz_value_string_list( - data.split(';', Qt::SkipEmptyParts)); + QStringList mz_value_string_list(data.split(';', Qt::SkipEmptyParts)); if(!mz_value_string_list.isEmpty()) { diff -Nru minexpert2-7.4.1/src/gui/MsRunDataSetTableViewProxyModel.hpp minexpert2-8.1.1/src/gui/MsRunDataSetTableViewProxyModel.hpp --- minexpert2-7.4.1/src/gui/MsRunDataSetTableViewProxyModel.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/MsRunDataSetTableViewProxyModel.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -72,8 +72,6 @@ void setPrecision(pappso::PrecisionPtr precision_p); - bool fillInProcessingFlow(ProcessingFlow &processing_flow); - protected: std::pair m_indicesPair; std::size_t m_msLevel = 0; diff -Nru minexpert2-7.4.1/src/gui/MsRunDataSetTableViewWnd.cpp minexpert2-8.1.1/src/gui/MsRunDataSetTableViewWnd.cpp --- minexpert2-7.4.1/src/gui/MsRunDataSetTableViewWnd.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/MsRunDataSetTableViewWnd.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -238,32 +238,32 @@ executeFilteringPushButtonClicked(); }); - connect(m_ui.integrateToMzPushButton, &QPushButton::clicked, [this]() { - integrateToMz(); + connect(m_ui.integrateToDtPushButton, &QPushButton::clicked, [this]() { + integrate("TO_DT"); }); - connect(m_ui.integrateToDtPushButton, &QPushButton::clicked, [this]() { - integrateToDt(); + connect(m_ui.integrateToMzPushButton, &QPushButton::clicked, [this]() { + integrate("TO_MZ"); }); connect(m_ui.integrateToRtPushButton, &QPushButton::clicked, [this]() { - integrateToRt(); + integrate("TO_RT"); }); connect(m_ui.integrateToIntPushButton, &QPushButton::clicked, [this]() { - integrateToTicIntensity(); + integrate("TO_INT"); }); connect(m_ui.integrateToDtMzPushButton, &QPushButton::clicked, [this]() { - integrateToDtMz(); + integrate("TO_DT_MZ"); }); - connect(m_ui.integrateToRtDtPushButton, &QPushButton::clicked, [this]() { - integrateToRtDt(); + connect(m_ui.integrateToDtRtPushButton, &QPushButton::clicked, [this]() { + integrate("TO_DT_RT"); }); - connect(m_ui.integrateToRtMzPushButton, &QPushButton::clicked, [this]() { - integrateToRtMz(); + connect(m_ui.integrateToMzRtPushButton, &QPushButton::clicked, [this]() { + integrate("TO_MZ_RT"); }); // When the filtering group box is unchecked, reset the filters and show @@ -303,80 +303,69 @@ void -MsRunDataSetTableViewWnd::createMainMenu() +MsRunDataSetTableViewWnd::show() { + readSettings(); - mp_mainMenu = new QMenu(this); - - const QIcon main_menu_icon = - QIcon(":/images/mobile-phone-like-menu-button.svg"); - mp_mainMenuPushButton = new QPushButton(main_menu_icon, QString(""), this); - - // When the main menu push button is clicked, the menu show up. - connect(mp_mainMenuPushButton, &QPushButton::clicked, [this]() { - mp_mainMenu->show(); - }); - - QAction *show_mz_integration_params_dlg_action_p = new QAction( - "Open m/z integration params dialog", dynamic_cast(this)); - show_mz_integration_params_dlg_action_p->setShortcut( - QKeySequence("Ctrl+O, I")); - show_mz_integration_params_dlg_action_p->setStatusTip( - "Open m/z integration params dialog"); - connect(show_mz_integration_params_dlg_action_p, - &QAction::triggered, - this, - &MsRunDataSetTableViewWnd::showMzIntegrationParamsDlg); - - mp_mainMenu->addAction(show_mz_integration_params_dlg_action_p); - - // The main menu is under the control of a push button. - mp_mainMenuPushButton->setMenu(mp_mainMenu); + QMainWindow::show(); } -bool -MsRunDataSetTableViewWnd::recordMsFragmentationSpec() +void +MsRunDataSetTableViewWnd::executeFilteringPushButtonClicked() { + // qDebug(); - MsFragmentationSpec ms_fragmentation_spec = - m_processingFlow.getDefaultMsFragmentationSpec(); + // We need to get all the strings from the various line edit widgets. + std::size_t ms_level = m_ui.msLevelSpinBox->value(); + QString indices = m_ui.indexLineEdit->text(); + QString rt_values = m_ui.retentionTimeLineEdit->text(); + QString dt_values = m_ui.driftTimeLineEdit->text(); + QString precursor_index_values = m_ui.precursorIndexLineEdit->text(); - ms_fragmentation_spec.setMsLevel(m_ui.msLevelSpinBox->value()); + QString precursor_mz_values = m_ui.precursorMzLineEdit->text(); + // qDebug() << "The precursor mz values in the table cell:" + //<< precursor_mz_values; - m_processingFlow.setDefaultMsFragmentationSpec(ms_fragmentation_spec); + QString precursor_charge_values = m_ui.precursorChargeLineEdit->text(); + // qDebug() << "The precursor charge values in the table cell:" + //<< precursor_charge_values; - return true; -} + // Now set all these values to the model proxy which will use them. + // Note that the precision/tolerance for the mz value matches is automatically + // set to the proxy model upon modifying values in the widget (see connection + // at initialization). + bool res = mp_msRunDataSetTableViewProxyModel->convertFilteringStrings( + ms_level, + indices, + rt_values, + dt_values, + precursor_index_values, + precursor_mz_values, + precursor_charge_values); -void -MsRunDataSetTableViewWnd::show() -{ - readSettings(); + // qDebug() << "res:" << res; - QMainWindow::show(); -} + if(!res) + { + statusBar()->showMessage( + "A problem with at least one filtering data entity was encountered", + 2000); + return; + } -void -MsRunDataSetTableViewWnd::keyPressEvent(QKeyEvent *event) -{ - // If Ctrl return, run the filter + // Since the filter string conversion worked, go on forcing filtering. - if(event->key() == Qt::Key_Return && - event->modifiers() & Qt::ControlModifier && - m_ui.filteringOptionsGroupBox->isChecked()) - { - executeFilteringPushButtonClicked(); - } -} + mp_msRunDataSetTableViewProxyModel->invalidate(); + std::size_t row_count = mp_msRunDataSetTableViewProxyModel->rowCount(); -void -MsRunDataSetTableViewWnd::ticIntensityValue(double intensity_value) -{ - statusBar()->showMessage(QString::number(intensity_value, 'g', 6), 2000); + // Do not set a time out for this status bar message. + statusBar()->showMessage(QString("%1 %2 retained after filtering.") + .arg(row_count) + .arg(row_count > 1 ? "spectra" : "spectrum")); } @@ -444,521 +433,308 @@ void -MsRunDataSetTableViewWnd::executeFilteringPushButtonClicked() +MsRunDataSetTableViewWnd::ticIntensityValue(double intensity_value) { - // qDebug(); - - // We need to get all the strings from the various line edit widgets. - std::size_t ms_level = m_ui.msLevelSpinBox->value(); - QString indices = m_ui.indexLineEdit->text(); - QString rt_values = m_ui.retentionTimeLineEdit->text(); - QString dt_values = m_ui.driftTimeLineEdit->text(); - QString precursor_index_values = m_ui.precursorIndexLineEdit->text(); + statusBar()->showMessage(QString::number(intensity_value, 'g', 6), 2000); +} - QString precursor_mz_values = m_ui.precursorMzLineEdit->text(); - // qDebug() << "The precursor mz values in the table cell:" - //<< precursor_mz_values; - QString precursor_charge_values = m_ui.precursorChargeLineEdit->text(); - // qDebug() << "The precursor charge values in the table cell:" - //<< precursor_charge_values; +void +MsRunDataSetTableViewWnd::keyPressEvent(QKeyEvent *event) +{ + // If Ctrl return, run the filter - // Now set all these values to the model proxy which will use them. - // Note that the precision/tolerance for the mz value matches is automatically - // set to the proxy model upon modifying values in the widget (see connection - // at initialization). + if(event->key() == Qt::Key_Return && + event->modifiers() & Qt::ControlModifier && + m_ui.filteringOptionsGroupBox->isChecked()) + { + executeFilteringPushButtonClicked(); + } +} - bool res = mp_msRunDataSetTableViewProxyModel->convertFilteringStrings( - ms_level, - indices, - rt_values, - dt_values, - precursor_index_values, - precursor_mz_values, - precursor_charge_values); - // qDebug() << "res:" << res; +void +MsRunDataSetTableViewWnd::createMainMenu() +{ - if(!res) - { - statusBar()->showMessage( - "A problem with at least one filtering data entity was encountered", - 2000); + mp_mainMenu = new QMenu(this); - return; - } + const QIcon main_menu_icon = + QIcon(":/images/svg/mobile-phone-like-menu-button.svg"); + mp_mainMenuPushButton = new QPushButton(main_menu_icon, QString(""), this); - // Since the filter string conversion worked, go on forcing filtering. + // When the main menu push button is clicked, the menu show up. + connect(mp_mainMenuPushButton, &QPushButton::clicked, [this]() { + mp_mainMenu->show(); + }); - mp_msRunDataSetTableViewProxyModel->invalidate(); + QAction *show_mz_integration_params_dlg_action_p = new QAction( + "Open m/z integration params dialog", dynamic_cast(this)); + show_mz_integration_params_dlg_action_p->setShortcut( + QKeySequence("Ctrl+O, I")); + show_mz_integration_params_dlg_action_p->setStatusTip( + "Open m/z integration params dialog"); + connect(show_mz_integration_params_dlg_action_p, + &QAction::triggered, + this, + &MsRunDataSetTableViewWnd::showMzIntegrationParamsDlg); - std::size_t row_count = mp_msRunDataSetTableViewProxyModel->rowCount(); + mp_mainMenu->addAction(show_mz_integration_params_dlg_action_p); - // Do not set a time out for this status bar message. - statusBar()->showMessage(QString("%1 %2 retained after filtering.") - .arg(row_count) - .arg(row_count > 1 ? "spectra" : "spectrum")); + // The main menu is under the control of a push button. + mp_mainMenuPushButton->setMenu(mp_mainMenu); } -void -MsRunDataSetTableViewWnd::integrateToRt() +bool +MsRunDataSetTableViewWnd::recordMsFragmentationSpec() { - // We need to craft a brand new processing flow because we do not want to - // pollute the member datum. - - recordMsFragmentationSpec(); - - ProcessingFlow local_processing_flow(m_processingFlow); - // Immediately set the mz integration params to the step. These are located in - // the processing flow as the default mz integartion params. + MsFragmentationSpec ms_fragmentation_spec = + m_processingFlow.getDefaultMsFragmentationSpec(); - // Create the processing step to document the processing. - ProcessingStep *step_p = new ProcessingStep; + ms_fragmentation_spec.setMsLevel(m_ui.msLevelSpinBox->value()); - step_p->setMzIntegrationParams( - local_processing_flow.getDefaultMzIntegrationParams()); + m_processingFlow.setDefaultMsFragmentationSpec(ms_fragmentation_spec); - // The ProcessingSpec below does not have any range data, but this is no - // problem. - ProcessingSpec *spec_p = new ProcessingSpec(); - - // Aggregate the spec to the step. - // qDebug() << "New spec: DATA_TABLE_VIEW_TO_RT"; - step_p->newSpec(ProcessingType("DATA_TABLE_VIEW_TO_RT"), spec_p); + return true; +} - // At this point, make sure we document in the processing flow the other - // critical parameters: the RT and DT values along with the MS fragmentation - // spec data. These elements are not taken into the account in the integration - // itself, because the integration works by going through the list of - // currently selected items in the table view, but they will be important in - // subsequent integrations are performed starting from the trace generated by - // the present integration. Otherwise we loose the fundamental concept of - // "virtually restricting" the data set to the innermost ranges used all along - // the integrations. - using VectorOfQualMassSpecCstSPtrSPtr = - std::shared_ptr>; +void +MsRunDataSetTableViewWnd::recordQualifiedMassSpectraToIntegrate( + std::vector + &vector_of_qualified_mass_spectra, + ProcessingStep &processing_step, + const QString &integration_type) const +{ + // qDebug() << "integration_type:" << integration_type; + // Start by getting the raw values. double begin_rt = -1; double end_rt = -1; double begin_dt = -1; double end_dt = -1; - std::vector - vector_of_qualified_mass_spectra = - recordQualifiedMassSpectraToIntegrate(begin_rt, end_rt, begin_dt, end_dt); + QItemSelectionModel *selection_model_p = + mp_msRunDataSetTableView->selectionModel(); - if(!vector_of_qualified_mass_spectra.size()) - return; + QModelIndexList selected_rows_list = selection_model_p->selectedRows(); + // qDebug() << "The number of selected rows is:" << selected_rows_list.size(); - // qDebug() << "begin_rt:" << begin_rt; - // qDebug() << "end_rt:" << end_rt; + double smallest_rt_value = std::numeric_limits::max(); + double greatest_rt_value = std::numeric_limits::min(); - spec_p = new ProcessingSpec(begin_rt, end_rt); + double smallest_dt_value = std::numeric_limits::max(); + double greatest_dt_value = std::numeric_limits::min(); - // Aggregate the new spec to the step. - // qDebug() << "New spec: RT_TO_ANY"; - step_p->newSpec("RT_TO_ANY", spec_p); - - // For the DT of course this is only necessary if the data are from an ion - // mobility mass spectrometry experiment. - if(begin_dt != -1 && end_dt != -1) + for(int iter = 0; iter < selected_rows_list.size(); ++iter) { - spec_p = new ProcessingSpec(begin_dt, end_dt); + QModelIndex index = selected_rows_list.at(iter); - // Aggregate the new spec to the step. - // qDebug() << "New spec: DT_TO_ANY"; - step_p->newSpec("DT_TO_ANY", spec_p); - } + // Attention, when working with proxy filter models, the internal + // pointer to the table view item is no more the one that points to the + // initially created view item. We need to step up to the source model + // to get the index to the "original" table view item. So, here we + // convert that proxy index to a source model index - // We have finished documenting the flow's step, append it to the processing - // flow. - local_processing_flow.push_back(step_p); + QModelIndex source_index = + mp_msRunDataSetTableViewProxyModel->mapToSource(index); - // qDebug().noquote() << "Right before integrating, processing flow:" - //<< local_processing_flow.toString(); + // Try to get the table view item itself that contains interesting data, + // like the pointer to the mass spectmrm. - VectorOfQualMassSpecCstSPtrSPtr vector_of_qualified_mass_spectra_sp = - std::make_shared>( - vector_of_qualified_mass_spectra); + MsRunDataSetTableViewItem *view_item_p = + static_cast( + source_index.internalPointer()); - mp_programWindow->integrateFromMsRunDataSetTableViewToRt( - mcsp_msRunDataSet, - vector_of_qualified_mass_spectra_sp, - local_processing_flow, - m_color); -} + if(view_item_p == nullptr) + qFatal("Pointer cannot be nullptr."); + pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = + view_item_p->getQualifiedMassSpectrum(); -void -MsRunDataSetTableViewWnd::integrateToMz() -{ - // We need to craft a brand new processing flow because we do not want to - // pollute the member datum. + if(qualified_mass_spectrum_csp == nullptr || + qualified_mass_spectrum_csp.get() == nullptr) + qFatal("Pointer cannot be nullptr"); - recordMsFragmentationSpec(); + // Try to get the data. - ProcessingFlow local_processing_flow(m_processingFlow); + QModelIndex sibling_index = source_index.siblingAtColumn( + static_cast(MassSpecDataViewColumns::COLUMN_SPECTRUM_INDEX)); + QString spectrum_index_string = sibling_index.data().toString(); - // Immediately set the mz integration params to the step. These are located in - // the processing flow as the default mz integartion params. + double rt_value = qualified_mass_spectrum_csp->getRtInMinutes(); - // Create the processing step to document the processing. - ProcessingStep *step_p = new ProcessingStep; + smallest_rt_value = std::min(smallest_rt_value, rt_value); + greatest_rt_value = std::max(greatest_rt_value, rt_value); - step_p->setMzIntegrationParams( - local_processing_flow.getDefaultMzIntegrationParams()); - // The ProcessingSpec below does not have any range data, but this is no - // problem. - ProcessingSpec *spec_p = new ProcessingSpec(); - - // Aggregate the spec to the step. - // qDebug() << "New spec: DATA_TABLE_VIEW_TO_MZ"; - step_p->newSpec(ProcessingType("DATA_TABLE_VIEW_TO_MZ"), spec_p); + double dt_value = qualified_mass_spectrum_csp->getDtInMilliSeconds(); - // At this point, make sure we document in the processing flow the other - // critical parameters: the RT and DT values along with the MS fragmentation - // spec data. These elements are not taken into the account in the integration - // itself, because the integration works by going through the list of - // currently selected items in the table view, but they will be important in - // subsequent integrations are performed starting from the trace generated by - // the present integration. Otherwise we loose the fundamental concept of - // "virtually restricting" the data set to the innermost ranges used all along - // the integrations. - - using VectorOfQualMassSpecCstSPtrSPtr = - std::shared_ptr>; - - double begin_rt = -1; - double end_rt = -1; + if(dt_value > -1) + { + smallest_dt_value = std::min(smallest_dt_value, dt_value); + greatest_dt_value = std::max(greatest_dt_value, dt_value); + } - double begin_dt = -1; - double end_dt = -1; + //qDebug() << qSetRealNumberPrecision(10) << "From the table view: " + //<< "rt_value: " << rt_value << "dt_value: " << dt_value; - std::vector - vector_of_qualified_mass_spectra = - recordQualifiedMassSpectraToIntegrate(begin_rt, end_rt, begin_dt, end_dt); + // Finally store the pointer to the qualified mass spectrum. + vector_of_qualified_mass_spectra.push_back(qualified_mass_spectrum_csp); + } if(!vector_of_qualified_mass_spectra.size()) return; + // At this point, we know the rt range and potentially also the dt range. + + begin_rt = smallest_rt_value; // qDebug() << "begin_rt:" << begin_rt; + + end_rt = greatest_rt_value; // qDebug() << "end_rt:" << end_rt; - spec_p = new ProcessingSpec(begin_rt, end_rt); + // Note that if the user selects either only one mass spectrum of a given RT + // or only drift spectra of a given RT, then, begin_rt == end_rt and we cannot + // craft a polygon. But we need to, because if DT data are included, the + // selection is 2-dimensional. - // Aggregate the new spec to the step. - // qDebug() << "New spec: RT_TO_ANY"; - step_p->newSpec("RT_TO_ANY", spec_p); - - // For the DT of course this is only necessary if the data are from an ion - // mobility mass spectrometry experiment. - if(begin_dt != -1 && end_dt != -1) + if(begin_rt == end_rt) { - spec_p = new ProcessingSpec(begin_dt, end_dt); + qDebug() + << "There is only one RT value, crafting an artificial RT range."; - // Aggregate the new spec to the step. - // qDebug() << "New spec: DT_TO_ANY"; - step_p->newSpec("DT_TO_ANY", spec_p); + end_rt = pappso::Utils::nearestGreater(end_rt); } - // We have finished documenting the flow's step, append it to the processing - // flow. - local_processing_flow.push_back(step_p); - - // qDebug().noquote() << "Right before integrating, processing flow:" - //<< local_processing_flow.toString(); - - VectorOfQualMassSpecCstSPtrSPtr vector_of_qualified_mass_spectra_sp = - std::make_shared>( - vector_of_qualified_mass_spectra); - - mp_programWindow->integrateToMz( - nullptr, vector_of_qualified_mass_spectra_sp, local_processing_flow); -} - - -void -MsRunDataSetTableViewWnd::integrateToDt() -{ - // We need to craft a brand new processing flow because we do not want to - // pollute the member datum. - - recordMsFragmentationSpec(); - - ProcessingFlow local_processing_flow(m_processingFlow); - - // Immediately set the mz integration params to the step. These are located in - // the processing flow as the default mz integartion params. - - // Create the processing step to document the processing. - ProcessingStep *step_p = new ProcessingStep; - - step_p->setMzIntegrationParams( - local_processing_flow.getDefaultMzIntegrationParams()); - - // The ProcessingSpec below does not have any range data, but this is no - // problem. - ProcessingSpec *spec_p = new ProcessingSpec(); - - // Aggregate the spec to the step. - // qDebug() << "New spec: DATA_TABLE_VIEW_TO_DT"; - step_p->newSpec(ProcessingType("DATA_TABLE_VIEW_TO_DT"), spec_p); - - // At this point, make sure we document in the processing flow the other - // critical parameters: the RT and DT values along with the MS fragmentation - // spec data. These elements are not taken into the account in the integration - // itself, because the integration works by going through the list of - // currently selected items in the table view, but they will be important in - // subsequent integrations are performed starting from the trace generated by - // the present integration. Otherwise we loose the fundamental concept of - // "virtually restricting" the data set to the innermost ranges used all along - // the integrations. - - using VectorOfQualMassSpecCstSPtrSPtr = - std::shared_ptr>; - - double begin_rt = -1; - double end_rt = -1; - - double begin_dt = -1; - double end_dt = -1; - - std::vector - vector_of_qualified_mass_spectra = - recordQualifiedMassSpectraToIntegrate(begin_rt, end_rt, begin_dt, end_dt); + if(smallest_dt_value != std::numeric_limits::max() && + greatest_dt_value != std::numeric_limits::min()) + { + begin_dt = smallest_dt_value; + qDebug() << "begin_dt:" << begin_dt; - if(!vector_of_qualified_mass_spectra.size()) - return; + end_dt = greatest_dt_value; + qDebug() << "end_dt:" << end_dt; - spec_p = new ProcessingSpec(begin_rt, end_rt); + if(begin_dt == end_dt) + { + qDebug() + << "There is only one DT value, crafting an artificial DT range."; - // Aggregate the new spec to the step. - // qDebug() << "New spec: RT_TO_ANY"; - step_p->newSpec("RT_TO_ANY", spec_p); - - // For the DT of course this is only necessary if the data are from an ion - // mobility mass spectrometry experiment. - if(begin_dt != -1 && end_dt != -1) + end_dt = pappso::Utils::nearestGreater(end_dt); + } + } + else { - spec_p = new ProcessingSpec(begin_dt, end_dt); - - // Aggregate the new spec to the step. - // qDebug() << "New spec: DT_TO_ANY"; - step_p->newSpec("DT_TO_ANY", spec_p); + begin_dt = -1; + end_dt = -1; } - // We have finished documenting the flow's step, append it to the processing - // flow. - local_processing_flow.push_back(step_p); - - // qDebug().noquote() << "Right before integrating, processing flow:" - //<< local_processing_flow.toString(); - - // Finally make a shared pointer with the vector of qualified mass spectra. - VectorOfQualMassSpecCstSPtrSPtr vector_of_qualified_mass_spectra_sp = - std::make_shared>( - vector_of_qualified_mass_spectra); - - mp_programWindow->integrateFromMsRunDataSetTableViewToDt( - mcsp_msRunDataSet, - vector_of_qualified_mass_spectra_sp, - local_processing_flow, - m_color); -} + // At this point, craft the selection polygon. + pappso::SelectionPolygon selection_polygon; -void -MsRunDataSetTableViewWnd::integrateToTicIntensity() -{ - // We need to craft a brand new processing flow because we do not want to - // pollute the member datum. - - recordMsFragmentationSpec(); - - ProcessingFlow local_processing_flow(m_processingFlow); - - // Immediately set the mz integration params to the step. These are located in - // the processing flow as the default mz integartion params. - - // Create the processing step to document the processing. - ProcessingStep *step_p = new ProcessingStep; - - step_p->setMzIntegrationParams( - local_processing_flow.getDefaultMzIntegrationParams()); - - // The ProcessingSpec below does not have any range data, but this is no - // problem. - ProcessingSpec *spec_p = new ProcessingSpec(); - - // Aggregate the spec to the step. - // qDebug() << "New spec: DATA_TABLE_VIEW_TO_INT"; - step_p->newSpec(ProcessingType("DATA_TABLE_VIEW_TO_INT"), spec_p); - - // At this point, make sure we document in the processing flow the other - // critical parameters: the RT and DT values along with the MS fragmentation - // spec data. These elements are not taken into the account in the integration - // itself, because the integration works by going through the list of - // currently selected items in the table view, but they will be important in - // subsequent integrations are performed starting from the trace generated by - // the present integration. Otherwise we loose the fundamental concept of - // "virtually restricting" the data set to the innermost ranges used all along - // the integrations. - - using VectorOfQualMassSpecCstSPtrSPtr = - std::shared_ptr>; - - double begin_rt = -1; - double end_rt = -1; - - double begin_dt = -1; - double end_dt = -1; - - std::vector - vector_of_qualified_mass_spectra = - recordQualifiedMassSpectraToIntegrate(begin_rt, end_rt, begin_dt, end_dt); - - if(!vector_of_qualified_mass_spectra.size()) - return; - - // qDebug() << "begin_rt:" << begin_rt; - // qDebug() << "end_rt:" << end_rt; - - spec_p = new ProcessingSpec(begin_rt, end_rt); - - // Aggregate the new spec to the step. - // qDebug() << "New spec: RT_TO_ANY"; - step_p->newSpec("RT_TO_ANY", spec_p); - - // For the DT of course this is only necessary if the data are from an ion - // mobility mass spectrometry experiment. - if(begin_dt != -1 && end_dt != -1) + if(begin_dt == -1 || end_dt == -1) { - spec_p = new ProcessingSpec(begin_dt, end_dt); + // Ion mobility is not a criterion here. Craft a 1D polygon with the RT + // data only. - // Aggregate the new spec to the step. - // qDebug() << "New spec: DT_TO_ANY"; - step_p->newSpec("DT_TO_ANY", spec_p); + selection_polygon.set1D(begin_rt, end_rt); } + else + { + // that is, if(begin_dt > -1 && end_dt > -1) - // We have finished documenting the flow's step, append it to the processing - // flow. - local_processing_flow.push_back(step_p); - - // qDebug().noquote() << "Right before integrating, processing flow:" - //<< local_processing_flow.toString(); - - // Finally make a shared pointer with the vector of qualified mass spectra. - VectorOfQualMassSpecCstSPtrSPtr vector_of_qualified_mass_spectra_sp = - std::make_shared>( - vector_of_qualified_mass_spectra); - - mp_programWindow->integrateFromMsRunDataSetTableViewToTicIntensity( - mcsp_msRunDataSet, - vector_of_qualified_mass_spectra_sp, - local_processing_flow, - m_color); -} - + // The data set contains ion mobility data. -void -MsRunDataSetTableViewWnd::integrateToDtMz() -{ - // We need to craft a brand new processing flow because we do not want to - // pollute the member datum. + // Craft a 2D polygon with x=DT and y=RT (alphabetical sorting of the + // axes). - recordMsFragmentationSpec(); + //qDebug() << qSetRealNumberPrecision(50) + //<< "rt difference:" << end_rt - begin_rt + //<< "dt difference:" << end_dt - begin_dt; - ProcessingFlow local_processing_flow(m_processingFlow); + selection_polygon.set2D(QPointF(begin_dt, end_rt), + QPointF(end_dt, end_rt), + QPointF(end_dt, begin_rt), + QPointF(begin_dt, begin_rt)); + } - // Immediately set the mz integration params to the step. These are located in - // the processing flow as the default mz integartion params. + processing_step.setSelectionPolygon(selection_polygon); - // Create the processing step to document the processing. - ProcessingStep *step_p = new ProcessingStep; + // Note that if the user selects either only one mass spectrum of a given RT + // or only drift spectra of a given RT, then, begin_rt == end_rt and we cannot + // craft a polygon. But we need to, because if DT data are included, the + // selection is 2-dimensional. - step_p->setMzIntegrationParams( - local_processing_flow.getDefaultMzIntegrationParams()); + // We need to document the ProcessingType. - // The ProcessingSpec below does not have any range data, but this is no - // problem. - ProcessingSpec *spec_p = new ProcessingSpec(); - - // Aggregate the spec to the step. - // qDebug() << "New spec: DATA_TABLE_VIEW_TO_DT_MZ"; - step_p->newSpec(ProcessingType("DATA_TABLE_VIEW_TO_DT_MZ"), spec_p); + bool is_selection_polygon_2D = selection_polygon.is2D(); - // At this point, make sure we document in the processing flow the other - // critical parameters: the RT and DT values along with the MS fragmentation - // spec data. These elements are not taken into the account in the integration - // itself, because the integration works by going through the list of - // currently selected items in the table view, but they will be important in - // subsequent integrations are performed starting from the trace generated by - // the present integration. Otherwise we loose the fundamental concept of - // "virtually restricting" the data set to the innermost ranges used all along - // the integrations. - - using VectorOfQualMassSpecCstSPtrSPtr = - std::shared_ptr>; - - double begin_rt = -1; - double end_rt = -1; + if(is_selection_polygon_2D) + { + // If the selection polygon is bi-dimensional, then that means that + // there are DT values. So we set dt for the x axis and rt for the y axis + // (remember we set the axes according to the processing type source name + // (here DT_RT). - double begin_dt = -1; - double end_dt = -1; + qDebug() << "The selection polygon is 2D."; - std::vector - vector_of_qualified_mass_spectra = - recordQualifiedMassSpectraToIntegrate(begin_rt, end_rt, begin_dt, end_dt); + processing_step.setDataKind(pappso::Axis::x, pappso::DataKind::dt); + processing_step.setDataKind(pappso::Axis::y, pappso::DataKind::rt); - if(!vector_of_qualified_mass_spectra.size()) - return; + processing_step.setSrcProcessingType(pappso::Axis::x, + "DATA_TABLE_VIEW_DT"); + processing_step.setSrcProcessingType(pappso::Axis::y, + "DATA_TABLE_VIEW_RT"); + } + else + { + // If the selection polygon is mono-dimensional, then that means that + // there are no DT values. So we set rt for the x axis. - spec_p = new ProcessingSpec(begin_rt, end_rt); + qDebug() << "The selection polygon is 1D."; - // Aggregate the new spec to the step. - // qDebug() << "New spec: RT_TO_ANY"; - step_p->newSpec("RT_TO_ANY", spec_p); - - // For the DT of course this is only necessary if the data are from an ion - // mobility mass spectrometry experiment. - if(begin_dt != -1 && end_dt != -1) - { - spec_p = new ProcessingSpec(begin_dt, end_dt); + processing_step.setDataKind(pappso::Axis::x, pappso::DataKind::rt); + processing_step.setDataKind(pappso::Axis::y, pappso::DataKind::unset); - // Aggregate the new spec to the step. - // qDebug() << "New spec: DT_TO_ANY"; - step_p->newSpec("DT_TO_ANY", spec_p); + processing_step.setSrcProcessingType(pappso::Axis::x, + "DATA_TABLE_VIEW_RT"); + processing_step.setSrcProcessingType(pappso::Axis::y, + "NOT_SET"); } - // We have finished documenting the flow's step, append it to the processing - // flow. - local_processing_flow.push_back(step_p); - - // qDebug().noquote() << "Right before integrating, processing flow:" - //<< local_processing_flow.toString(); + // And now configure the destination type. - // Finally make a shared pointer with the vector of qualified mass spectra. - VectorOfQualMassSpecCstSPtrSPtr vector_of_qualified_mass_spectra_sp = - std::make_shared>( - vector_of_qualified_mass_spectra); + if(integration_type == "TO_DT") + processing_step.setDestProcessingType("DT"); + else if(integration_type == "TO_MZ") + processing_step.setDestProcessingType("MZ"); + else if(integration_type == "TO_RT") + processing_step.setDestProcessingType("RT"); + else if(integration_type == "TO_INT") + processing_step.setDestProcessingType("INT"); + else if(integration_type == "TO_DT_MZ") + processing_step.setDestProcessingType("DT_MZ"); + else if(integration_type == "TO_DT_RT") + processing_step.setDestProcessingType("DT_RT"); + else if(integration_type == "TO_MZ_RT") + processing_step.setDestProcessingType("MZ_RT"); + else + qFatal("Programming error."); - mp_programWindow->integrateFromMsRunDataSetTableViewToDtRtMz( - pappso::DataKind::dt, - mcsp_msRunDataSet, - vector_of_qualified_mass_spectra_sp, - local_processing_flow, - m_color); + qDebug() << "Finally configured step:" << processing_step.toString(); } void -MsRunDataSetTableViewWnd::integrateToRtMz() +MsRunDataSetTableViewWnd::integrate(const QString &integration_type) { + qDebug() << "Integration type:" << integration_type; + // We need to craft a brand new processing flow because we do not want to // pollute the member datum. @@ -969,20 +745,15 @@ // Immediately set the mz integration params to the step. These are located in // the processing flow as the default mz integartion params. - // Create the processing step to document the processing. - ProcessingStep *step_p = new ProcessingStep; + // Create the processing step to document the processing. We cannot set the + // ProcessingType because that will depend on the kind of data we use for the + // integration below. + + ProcessingStep *step_p = new ProcessingStep(); step_p->setMzIntegrationParams( local_processing_flow.getDefaultMzIntegrationParams()); - // The ProcessingSpec below does not have any range data, but this is no - // problem. - ProcessingSpec *spec_p = new ProcessingSpec(); - - // Aggregate the spec to the step. - // qDebug() << "New spec: DATA_TABLE_VIEW_TO_RT_MZ"; - step_p->newSpec(ProcessingType("DATA_TABLE_VIEW_TO_RT_MZ"), spec_p); - // At this point, make sure we document in the processing flow the other // critical parameters: the RT and DT values along with the MS fragmentation // spec data. These elements are not taken into the account in the integration @@ -993,38 +764,17 @@ // "virtually restricting" the data set to the innermost ranges used all along // the integrations. - using VectorOfQualMassSpecCstSPtrSPtr = - std::shared_ptr>; - - double begin_rt = -1; - double end_rt = -1; - - double begin_dt = -1; - double end_dt = -1; - std::vector - vector_of_qualified_mass_spectra = - recordQualifiedMassSpectraToIntegrate(begin_rt, end_rt, begin_dt, end_dt); + vector_of_qualified_mass_spectra; + + recordQualifiedMassSpectraToIntegrate( + vector_of_qualified_mass_spectra, *step_p, integration_type); if(!vector_of_qualified_mass_spectra.size()) return; - spec_p = new ProcessingSpec(begin_rt, end_rt); - - // Aggregate the new spec to the step. - // qDebug() << "New spec: RT_TO_ANY"; - step_p->newSpec("RT_TO_ANY", spec_p); - - // For the DT of course this is only necessary if the data are from an ion - // mobility mass spectrometry experiment. - if(begin_dt != -1 && end_dt != -1) - { - spec_p = new ProcessingSpec(begin_dt, end_dt); - - // Aggregate the new spec to the step. - // qDebug() << "New spec: DT_TO_ANY"; - step_p->newSpec("DT_TO_ANY", spec_p); - } + qDebug() << "The number of spectra recorded for integration:" + << vector_of_qualified_mass_spectra.size(); // We have finished documenting the flow's step, append it to the processing // flow. @@ -1034,361 +784,38 @@ //<< local_processing_flow.toString(); // Finally make a shared pointer with the vector of qualified mass spectra. - VectorOfQualMassSpecCstSPtrSPtr vector_of_qualified_mass_spectra_sp = - std::make_shared>( - vector_of_qualified_mass_spectra); - - mp_programWindow->integrateFromMsRunDataSetTableViewToDtRtMz( - pappso::DataKind::rt, - mcsp_msRunDataSet, - vector_of_qualified_mass_spectra_sp, - local_processing_flow, - m_color); -} - - -void -MsRunDataSetTableViewWnd::integrateToRtDt() -{ - // We need to craft a brand new processing flow because we do not want to - // pollute the member datum. - - recordMsFragmentationSpec(); - - ProcessingFlow local_processing_flow(m_processingFlow); - - // Immediately set the mz integration params to the step. These are located in - // the processing flow as the default mz integartion params. - - // Create the processing step to document the processing. - ProcessingStep *step_p = new ProcessingStep; - - step_p->setMzIntegrationParams( - local_processing_flow.getDefaultMzIntegrationParams()); - - // The ProcessingSpec below does not have any range data, but this is no - // problem. - ProcessingSpec *spec_p = new ProcessingSpec(); - - // Aggregate the spec to the step. - qDebug() << "New spec: DATA_TABLE_VIEW_TO_RT_DT"; - step_p->newSpec(ProcessingType("DATA_TABLE_VIEW_TO_RT_DT"), spec_p); - - // At this point, make sure we document in the processing flow the other - // critical parameters: the RT and DT values along with the MS fragmentation - // spec data. These elements are not taken into the account in the integration - // itself, because the integration works by going through the list of - // currently selected items in the table view, but they will be important in - // subsequent integrations are performed starting from the trace generated by - // the present integration. Otherwise we loose the fundamental concept of - // "virtually restricting" the data set to the innermost ranges used all along - // the integrations. - using VectorOfQualMassSpecCstSPtrSPtr = std::shared_ptr>; - double begin_rt = -1; - double end_rt = -1; - - double begin_dt = -1; - double end_dt = -1; - - std::vector - vector_of_qualified_mass_spectra = - recordQualifiedMassSpectraToIntegrate(begin_rt, end_rt, begin_dt, end_dt); - - if(!vector_of_qualified_mass_spectra.size()) - return; - - spec_p = new ProcessingSpec(begin_rt, end_rt); - - // Aggregate the new spec to the step. - // qDebug() << "New spec: RT_TO_ANY"; - step_p->newSpec("RT_TO_ANY", spec_p); - - // For the DT of course this is only necessary if the data are from an ion - // mobility mass spectrometry experiment. - if(begin_dt != -1 && end_dt != -1) - { - spec_p = new ProcessingSpec(begin_dt, end_dt); - - // Aggregate the new spec to the step. - // qDebug() << "New spec: DT_TO_ANY"; - step_p->newSpec("DT_TO_ANY", spec_p); - } - - // We have finished documenting the flow's step, append it to the processing - // flow. - local_processing_flow.push_back(step_p); - - // qDebug().noquote() << "Right before integrating, processing flow:" - //<< local_processing_flow.toString(); - - // Finally make a shared pointer with the vector of qualified mass spectra. VectorOfQualMassSpecCstSPtrSPtr vector_of_qualified_mass_spectra_sp = std::make_shared>( vector_of_qualified_mass_spectra); - mp_programWindow->integrateFromMsRunDataSetTableViewToRtDt( - pappso::DataKind::rt, - mcsp_msRunDataSet, - vector_of_qualified_mass_spectra_sp, - local_processing_flow, - m_color); -} - - -std::vector -MsRunDataSetTableViewWnd::recordQualifiedMassSpectraToIntegrate( - double &begin_rt, double &end_rt, double &begin_dt, double &end_dt) const -{ - // qDebug(); - - std::vector - vector_of_qualified_mass_spectra; - - // QList selected_indices_list = - // mp_msRunDataSetTableViewSelectionModel->selectedIndexes(); - - // qDebug() << "The number of selected indices is:" - //<< selected_indices_list.size(); - - QItemSelectionModel *selection_model_p = - mp_msRunDataSetTableView->selectionModel(); - - QModelIndexList selected_rows_list = selection_model_p->selectedRows(); - - // qDebug() << "The number of selected rows is:" << selected_rows_list.size(); - - double smallest_rt_value = std::numeric_limits::max(); - double greatest_rt_value = std::numeric_limits::min(); - - double smallest_dt_value = std::numeric_limits::max(); - double greatest_dt_value = std::numeric_limits::min(); - - for(int iter = 0; iter < selected_rows_list.size(); ++iter) - { - QModelIndex index = selected_rows_list.at(iter); - - // Attention, when working with proxy filter models, the internal - // pointer to the table view item is no more the one that points to the - // initially created view item. We need to step up to the source model - // to get the index to the "original" table view item. So, here we - // convert that proxy index to a source model index - - QModelIndex source_index = - mp_msRunDataSetTableViewProxyModel->mapToSource(index); - - // Try to get the data. - - QModelIndex sibling_index = source_index.siblingAtColumn( - static_cast(MassSpecDataViewColumns::COLUMN_SPECTRUM_INDEX)); - QString spectrum_index_string = sibling_index.data().toString(); - - sibling_index = source_index.siblingAtColumn( - static_cast(MassSpecDataViewColumns::COLUMN_RT)); - QString rt_string = sibling_index.data().toString(); - - bool ok = false; - - double rt_value = rt_string.toDouble(&ok); - - if(!ok) - qFatal("Programming error."); + // We can now select the right integration. - if(rt_value < smallest_rt_value) - smallest_rt_value = rt_value; - - if(rt_value > greatest_rt_value) - greatest_rt_value = rt_value; - - sibling_index = source_index.siblingAtColumn( - static_cast(MassSpecDataViewColumns::COLUMN_DT)); - QString dt_string = sibling_index.data().toString(); - - // This one is conditional: only if there are mobility data. - - if(!dt_string.isEmpty()) - { - double dt_value = dt_string.toDouble(&ok); - - if(!ok) - qFatal("Programming error."); - - if(dt_value > -1) - { - if(dt_value < smallest_dt_value) - smallest_dt_value = dt_value; - - if(dt_value > greatest_dt_value) - greatest_dt_value = dt_value; - } - } - - // qDebug() << "From the table view -- spectrum_index_string:" - //<< spectrum_index_string << "rt_string:" << rt_string - //<< "dt_string:" << dt_string; - - // Try to get the item itself that contains interesting data: - - MsRunDataSetTableViewItem *view_item_p = - static_cast( - source_index.internalPointer()); - - if(view_item_p == nullptr) - qFatal("Pointer cannot be nullptr."); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - view_item_p->getQualifiedMassSpectrum(); - - vector_of_qualified_mass_spectra.push_back(qualified_mass_spectrum_csp); - - // qDebug() - //<< "From the qualified mass spectrum:" - //<< "mass spectrum index:" - //<< qualified_mass_spectrum_csp->getMassSpectrumId().getSpectrumIndex() - //<< "rt:" << qualified_mass_spectrum_csp->getRtInMinutes() - //<< "dt:" << qualified_mass_spectrum_csp->getDtInMilliSeconds(); - } - - // At this point, we know the rt ranges and potentially also the dt ranges. - - begin_rt = smallest_rt_value; - // qDebug() << "begin_rt:" << begin_rt; - - end_rt = greatest_rt_value; - // qDebug() << "end_rt:" << end_rt; - - if(smallest_dt_value != std::numeric_limits::max() && - greatest_dt_value != std::numeric_limits::min()) - { - begin_dt = smallest_dt_value; - // qDebug() << "begin_dt:" << begin_rt; - - end_dt = greatest_dt_value; - // qDebug() << "end_dt:" << end_rt; - } - - // qDebug() << "Returning a vector of qualified mass spectra of size:" - //<< vector_of_qualified_mass_spectra.size(); - - statusBar()->showMessage(QString("%1 spectra stored for later integration.") - .arg(vector_of_qualified_mass_spectra.size()), - 2000); - - return vector_of_qualified_mass_spectra; -} - - -void -MsRunDataSetTableViewWnd::integrationRangesForRtAndDt(double &begin_rt, - double &end_rt, - double &begin_dt, - double &end_dt) const -{ - // qDebug(); - - // QList selected_indices_list = - // mp_msRunDataSetTableViewSelectionModel->selectedIndexes(); - - // qDebug() << "The number of selected indices is:" - //<< selected_indices_list.size(); - - QItemSelectionModel *selection_model_p = - mp_msRunDataSetTableView->selectionModel(); - - QModelIndexList selected_rows_list = selection_model_p->selectedRows(); - - // qDebug() << "The number of selected rows is:" << selected_rows_list.size(); - - double smallest_rt_value = std::numeric_limits::max(); - double greatest_rt_value = std::numeric_limits::min(); - - double smallest_dt_value = std::numeric_limits::max(); - double greatest_dt_value = std::numeric_limits::min(); - - for(int iter = 0; iter < selected_rows_list.size(); ++iter) - { - QModelIndex index = selected_rows_list.at(iter); - - // Attention, when working with proxy filter models, the internal - // pointer to the table view item is no more the one that points to the - // initially created view item. We need to step up to the source model - // to get the index to the "original" table view item. So, here we - // convert that proxy index to a source model index - - // QModelIndex source_index = - // mp_msRunDataSetTableViewProxyModel->sourceModel()->index( - // index.row(), index.column(), index.parent()); - - QModelIndex source_index = - mp_msRunDataSetTableViewProxyModel->mapToSource(index); - - // Try to get the data. - - QModelIndex sibling_index = source_index.siblingAtColumn( - static_cast(MassSpecDataViewColumns::COLUMN_SPECTRUM_INDEX)); - QString spectrum_index_string = sibling_index.data().toString(); - - sibling_index = source_index.siblingAtColumn( - static_cast(MassSpecDataViewColumns::COLUMN_RT)); - QString rt_string = sibling_index.data().toString(); - - bool ok = false; - - double rt_value = rt_string.toDouble(&ok); - - if(!ok) - qFatal("Programming error."); - - if(rt_value < smallest_rt_value) - smallest_rt_value = rt_value; - - if(rt_value > greatest_rt_value) - greatest_rt_value = rt_value; - - sibling_index = source_index.siblingAtColumn( - static_cast(MassSpecDataViewColumns::COLUMN_DT)); - QString dt_string = sibling_index.data().toString(); - - // This one is conditional: only if there are mobility data. - - if(!dt_string.isEmpty() && dt_string > -1) - { - double dt_value = dt_string.toDouble(&ok); - - if(!ok) - qFatal("Programming error."); - - if(dt_value < smallest_dt_value) - smallest_dt_value = dt_value; - - if(dt_value > greatest_dt_value) - greatest_dt_value = dt_value; - } - - // qDebug() << "From the table view -- spectrum_index_string:" - //<< spectrum_index_string << "rt_string:" << rt_string - //<< "dt_string:" << dt_string; - } - - // At this point, we know the rt ranges and potentially also the dt ranges. - - begin_rt = smallest_rt_value; - // qDebug() << "begin_rt:" << begin_rt; - - end_rt = greatest_rt_value; - // qDebug() << "end_rt:" << end_rt; - - if(smallest_dt_value != std::numeric_limits::max() && - greatest_dt_value != std::numeric_limits::min()) - { - begin_dt = smallest_dt_value; - // qDebug() << "begin_dt:" << begin_rt; - - end_dt = greatest_dt_value; - // qDebug() << "end_dt:" << end_rt; - } + if(integration_type == "TO_DT") + mp_programWindow->integrateToDt( + nullptr, vector_of_qualified_mass_spectra_sp, local_processing_flow); + else if(integration_type == "TO_MZ") + mp_programWindow->integrateToMz( + nullptr, vector_of_qualified_mass_spectra_sp, local_processing_flow); + else if(integration_type == "TO_RT") + mp_programWindow->integrateToRt( + nullptr, vector_of_qualified_mass_spectra_sp, local_processing_flow); + else if(integration_type == "TO_INT") + mp_programWindow->integrateToTicIntensity( + nullptr, vector_of_qualified_mass_spectra_sp, local_processing_flow); + else if(integration_type == "TO_DT_MZ") + mp_programWindow->integrateToDtMz( + nullptr, vector_of_qualified_mass_spectra_sp, local_processing_flow); + else if(integration_type == "TO_DT_RT") + mp_programWindow->integrateToDtRt( + nullptr, vector_of_qualified_mass_spectra_sp, local_processing_flow); + else if(integration_type == "TO_MZ_RT") + mp_programWindow->integrateToMzRt( + nullptr, vector_of_qualified_mass_spectra_sp, local_processing_flow); + else + qFatal("Programming error."); } diff -Nru minexpert2-7.4.1/src/gui/MsRunDataSetTableViewWnd.hpp minexpert2-8.1.1/src/gui/MsRunDataSetTableViewWnd.hpp --- minexpert2-7.4.1/src/gui/MsRunDataSetTableViewWnd.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/MsRunDataSetTableViewWnd.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -83,17 +83,20 @@ virtual ~MsRunDataSetTableViewWnd(); - bool initialize(); void closeEvent(QCloseEvent *event); + void writeSettings(); void readSettings(); + bool initialize(); + void show(); void executeFilteringPushButtonClicked(); void showMzIntegrationParamsDlg(); - void mzIntegrationParamsChanged(pappso::MzIntegrationParams mz_integration_params); + void + mzIntegrationParamsChanged(pappso::MzIntegrationParams mz_integration_params); public slots: @@ -137,23 +140,13 @@ bool recordMsFragmentationSpec(); - std::vector - recordQualifiedMassSpectraToIntegrate(double &begin_rt, - double &end_rt, - double &begin_dt, - double &end_dt) const; - void integrationRangesForRtAndDt(double &begin_rt, - double &end_rt, - double &begin_dt, - double &end_dt) const; - - void integrateToMz(); - void integrateToDt(); - void integrateToRt(); - void integrateToTicIntensity(); - void integrateToDtMz(); - void integrateToRtDt(); - void integrateToRtMz(); + void recordQualifiedMassSpectraToIntegrate( + std::vector + &vector_of_qualified_mass_spectra, + ProcessingStep &processing_step, + const QString &integration_type) const; + + void integrate(const QString &integration_type); }; diff -Nru minexpert2-7.4.1/src/gui/OpenMsRunDataSetsDlg.cpp minexpert2-8.1.1/src/gui/OpenMsRunDataSetsDlg.cpp --- minexpert2-7.4.1/src/gui/OpenMsRunDataSetsDlg.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/OpenMsRunDataSetsDlg.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -147,7 +147,7 @@ // Create the menu push button. const QIcon main_menu_icon = - QIcon(":/images/mobile-phone-like-menu-button.svg"); + QIcon(":/images/svg/mobile-phone-like-menu-button.svg"); m_ui.mainMenuPushButton->setIcon(main_menu_icon); // Finally set the push button to be the menu... diff -Nru minexpert2-7.4.1/src/gui/ProgramWindow.cpp minexpert2-8.1.1/src/gui/ProgramWindow.cpp --- minexpert2-7.4.1/src/gui/ProgramWindow.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ProgramWindow.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -56,6 +56,7 @@ /////////////////////// pappsomspp includes #include +#include /////////////////////// Local includes @@ -66,14 +67,12 @@ #include "MsRunDataSetTableViewProxyModel.hpp" #include "../nongui/globals.hpp" #include "MsRunReadTask.hpp" -#include #include "../nongui/MassDataIntegrator.hpp" #include "ColorSelector.hpp" #include "MsRunSelectorDlg.hpp" #include "../nongui/MassDataIntegratorTask.hpp" #include "../nongui/MsRunDataSet.hpp" #include "TicXicChromMassSpecColorMapWnd.hpp" -#include "../nongui/MsRunDataSetTreeMassDataIntegratorToMz.hpp" namespace msxps @@ -88,12 +87,6 @@ m_lastUsedDirectory = QDir::home().absolutePath(); - // This attribute make sure that the main window of the program is destroyed - // when it is closed. Effectively stopping the program. - setAttribute(Qt::WA_DeleteOnClose); - - setWindowIcon(QIcon(":/images/icons/32x32/minexpert2.png")); - setupWindow(); } @@ -115,797 +108,899 @@ void -ProgramWindow::readSettings() +ProgramWindow::setMaxThreadUseCount(std::size_t count) { - QSettings settings(static_cast(QCoreApplication::instance()) - ->getUserConfigSettingsFilePath(), - QSettings::IniFormat); - settings.beginGroup("ProgramWindow"); + m_maxThreadUseCount = count; +} - restoreGeometry(settings.value("geometry").toByteArray()); - settings.endGroup(); +std::size_t +ProgramWindow::getMaxThreadUseCount() +{ + return m_maxThreadUseCount; } -void -ProgramWindow::writeSettings() +bool +ProgramWindow::openMassSpectrometryFileDlg(const QString &dir_name, + bool full_in_memory) { - QSettings settings(static_cast(QCoreApplication::instance()) - ->getUserConfigSettingsFilePath(), - QSettings::IniFormat); - settings.beginGroup("ProgramWindow"); + qDebug() << "The directory name is:" << dir_name; - settings.setValue("geometry", saveGeometry()); + QFileDialog file_dialog( + this, + QString("%1 - Select mass spectrometry data file(s)").arg(m_moduleName)); - settings.endGroup(); -} + file_dialog.setFileMode(QFileDialog::ExistingFiles); + file_dialog.setViewMode(QFileDialog::Detail); + file_dialog.setAcceptMode(QFileDialog::AcceptOpen); + // Open the dialog in the right directory. + if(dir_name.isEmpty()) + file_dialog.setDirectory(m_lastUsedDirectory); + else + file_dialog.setDirectory(dir_name); -void -ProgramWindow::initializeAllWindows() -{ - mp_openMsRunDataSetsDlg = new OpenMsRunDataSetsDlg(this); - // mp_openMsRunDataSetsDlg->show(); + QStringList file_names; - mp_ticXicChromPlotWnd = new TicXicChromTracePlotWnd( - this, "TIC/XIC chromatograms", "TicXicChromTracePlotWnd"); - // mp_ticXicChromPlotWnd->show(); + if(file_dialog.exec()) + { + file_names = file_dialog.selectedFiles(); - mp_massSpecPlotWnd = - new MassSpecTracePlotWnd(this, "Mass spectra", "MassSpecTracePlotWnd"); - // mp_massSpecPlotWnd->show(); + // Store the directory name whence the selected files come. - mp_driftSpecPlotWnd = - new DriftSpecTracePlotWnd(this, "Drift spectra", "DriftSpecTracePlotWnd"); - // mp_driftSpecPlotWnd->show(); + if(file_names.size()) + { + QString last_used_directory; + QString first_file_name = file_names.at(0); + QFileInfo file_info = QFileInfo(first_file_name); + m_lastUsedDirectory = file_info.absoluteDir().dirName(); + } + } - mp_ticXicChromMassSpecColorMapWnd = - new TicXicChromMassSpecColorMapWnd(this, - "TIC/XIC chrom. / Mass spec. color maps", - "TicXicChromMassSpecColorMapWnd"); - // mp_ticXicChromMassSpecColorMapWnd->show(); + for(int iter = 0; iter < file_names.size(); ++iter) + { + QString cur_file_name = file_names.at(iter); - mp_ticXicChromDriftSpecColorMapWnd = new TicXicChromDriftSpecColorMapWnd( - this, - "TIC/XIC chrom. / Drift spec. color maps", - "TicXicChromDriftSpecColorMapWnd"); - // mp_ticXicChromDriftSpecColorMapWnd->show(); + bool res = openMassSpectrometryFile(cur_file_name, full_in_memory); - mp_driftSpecMassSpecColorMapWnd = - new DriftSpecMassSpecColorMapWnd(this, - "Drift spec. / Mass spec. color maps", - "DriftSpecMassSpecColorMapWnd"); - // mp_driftSpecMassSpecColorMapWnd->show(); + if(!res) + QMessageBox::warning(this, + "Mass spectrometry file loading failed", + "The file " + cur_file_name + "failed to load."); + } - mp_xicExtractionWnd = new XicExtractionWnd( - this, "XIC chromatogram extraction", "XicExtractionWnd"); + return true; +} - mp_taskMonitorWnd = - new TaskMonitorWnd(this, "Task monitors", "TaskMonitorWnd"); - // mp_taskMonitorWnd->show(); - mp_consoleWnd = new ConsoleWnd(this, m_moduleName); - // mp_consoleWnd->show(); +bool +ProgramWindow::openMassSpectrometryFile(const QString &file_name, + bool full_in_memory, + const QString &sample_name) +{ + // qDebug() << "Opening mass spectrometry file:" << file_name + //<< "with sample name:" << sample_name + //<< "from thread:" << QThread::currentThread(); - // NO, this one is "on demand". - // mp_isoSpecDlg = new IsoSpecDlg(this, m_moduleName); + if(file_name.isEmpty() || !QFileInfo::exists(file_name)) + { + return openMassSpectrometryFileDlg(QDir::homePath(), full_in_memory); + } - // NO, this one is "on demand". - // mp_massPeakShaperDlg = new MassPeakShaperDlg(this, m_moduleName); + // At this point, we have a file name. Let's store the directory where the + // file sits so that later the user can be directed there immediately. + m_lastUsedDirectory = QFileInfo(file_name).dir().absolutePath(); - // At this point, try to check if we should remind the user to - // cite the paper. + // Now let's start the file type identification work. - QSettings settings(static_cast(QCoreApplication::instance()) - ->getUserConfigSettingsFilePath(), - QSettings::IniFormat); + // The MsFileAccessor will allow to get a list of MS run ids that can then be + // used to request a MS run reader appropriate for the MS data file format. + // Beccause there might be more than one ms run in a single mzML file, we need + // to have a common prefix for all those ms run ids. + pappso::MsFileAccessor ms_file_accessor(file_name, m_msRunIdPrefix); - settings.beginGroup("Globals"); + // qDebug() << "Could get MsFileAccessor."; - int run_count = settings.value("run_count", 0).toInt(); + std::vector ms_run_ids = + ms_file_accessor.getMsRunIds(); - ++run_count; + std::size_t run_count = ms_run_ids.size(); - if(run_count == 15) + // qDebug() << "The number of ms run ids:" << run_count; + + if(!run_count) { - AboutDlg *dlg = showAboutDlg(); + QMessageBox::information(this, + "Open mass spectrometry file", + "This file does contain no MS run"); + return false; + } - dlg->showHowToCiteTab(); + int run_index = 0; - settings.setValue("run_count", 0); - } - else + // qDebug() << "The number of ms runs in the file is:" << run_count; + + // If there are more than one run, let the user select the one they are + // interested in. + + if(run_count > 1) { - settings.setValue("run_count", run_count); - } - settings.endGroup(); -} + // If the user cancels the dialog, returns -1, otherwise returns the index + // of the ms run id. + run_index = selectMsRun(ms_run_ids); -void -ProgramWindow::createMenusAndActions() -{ + // qDebug() << "The run_index: " << run_index; - // File menu - mp_fileMenu = menuBar()->addMenu("&File"); + if(run_index == -1) + return false; + } - mp_openFullMsFileAct = - new QAction("Open mass spectrum file(s) fully in &memory", - dynamic_cast(this)); - mp_openFullMsFileAct->setStatusTip("Open mass data file(s) fully in memory"); - mp_openFullMsFileAct->setShortcut(QKeySequence("Ctrl+O, M")); + // Now actually load the data! - connect(mp_openFullMsFileAct, &QAction::triggered, [this]() { - openMassSpectrometryFileDlg(m_lastUsedDirectory, true); - }); + // Allocate a ms run reader task to read the data. + MsRunReadTask *ms_run_read_task_p = new MsRunReadTask(this); - mp_fileMenu->addAction(mp_openFullMsFileAct); + // Get the first run id of the vector. + pappso::MsRunIdCstSPtr ms_run_id_csp = ms_run_ids.at(run_index); - mp_openStreamedMsFileAct = - new QAction("Open mass spectrum file(s) in &streamed mode", - dynamic_cast(this)); - mp_openStreamedMsFileAct->setStatusTip( - "Open mass data file(s) in streamed mode"); - mp_openStreamedMsFileAct->setShortcut(QKeySequence("Ctrl+O, S")); + if(!sample_name.isEmpty()) + { + // qDebug() << "The sample name is not empty:" << sample_name; - connect(mp_openStreamedMsFileAct, &QAction::triggered, [this]() { - openMassSpectrometryFileDlg(m_lastUsedDirectory, false); - }); + std::const_pointer_cast(ms_run_id_csp) + ->setSampleName(sample_name); + } - mp_fileMenu->addAction(mp_openStreamedMsFileAct); + // qDebug() << "The run id as text:" << ms_run_id_csp->toString(); - QAction *open_ms_file_from_clipboard_act_p = new QAction( - "Load mass spectrum from &clipboard", dynamic_cast(this)); - open_ms_file_from_clipboard_act_p->setStatusTip( - "Load a mass spectrum directly from the clipboard"); - open_ms_file_from_clipboard_act_p->setShortcut(QKeySequence("Ctrl+L, C")); + MassSpecDataFileLoaderSPtr loader_sp = + std::make_shared(ms_file_accessor.getFileName(), + full_in_memory); - connect(open_ms_file_from_clipboard_act_p, &QAction::triggered, [this]() { - openMassSpectrometryFileFromClipBoard(); - }); + if(loader_sp == nullptr) + qFatal("Programming error"); - mp_fileMenu->addAction(open_ms_file_from_clipboard_act_p); + // Allocate a new TaskMonitorCompositeWidget - mp_fileMenu->addSeparator(); + TaskMonitorCompositeWidget *task_monitor_composite_widget_p = + mp_taskMonitorWnd->addTaskMonitorWidget(Qt::red); - QAction *analysis_preferences_act_p = - new QAction("&Analysis preferences...", dynamic_cast(this)); - analysis_preferences_act_p->setStatusTip(tr("Set the analysis preferences")); - analysis_preferences_act_p->setShortcut(QKeySequence("Ctrl+A, P")); + // Make sure the task monitor window is visible ! + showTaskMonitorWnd(); - connect(analysis_preferences_act_p, &QAction::triggered, [this]() { - openAnalysisPreferencesDlg(); - }); - mp_fileMenu->addAction(analysis_preferences_act_p); + // Initialize the monitor composite widget's widgets and make all the + // connections loader <--> widget. - mp_fileMenu->addSeparator(); + task_monitor_composite_widget_p->setMsRunIdText( + ms_run_id_csp->getSampleName()); + task_monitor_composite_widget_p->setTaskDescriptionText( + "Reading MS run data"); + task_monitor_composite_widget_p->setProgressBarMinValue(0); - mp_quitAct = new QAction(tr("&Quit"), dynamic_cast(this)); - mp_quitAct->setStatusTip(tr("Exit mineXpert")); - mp_quitAct->setShortcut(tr("Ctrl+Q")); + // Make the connections - connect(mp_quitAct, &QAction::triggered, this, &ProgramWindow::close); - mp_fileMenu->addAction(mp_quitAct); + // When the MsRunReadTask instance has finished working, it will send a signal + // that we trap to finally destroy (after a time lag of some seconds, the + // monitor widget. - // Windows menu - mp_windowsMenu = menuBar()->addMenu("&Windows"); - QAction *action_p = new QAction("Show &TIC/XIC chromatograms window", - dynamic_cast(this)); - action_p->setShortcut(QKeySequence("Ctrl+W, R")); - action_p->setStatusTip("Show the TIC/XIC chromatograms window"); - connect(action_p, - &QAction::triggered, - this, - &ProgramWindow::showTicXicChromatogramsWnd); - mp_windowsMenu->addAction(action_p); + connect(ms_run_read_task_p, + &MsRunReadTask::finishedReadingMsRunDataSignal, + task_monitor_composite_widget_p, + &TaskMonitorCompositeWidget::taskFinished, + Qt::QueuedConnection); + // If the user clicks the cancel button, relay the signal to the loader. + connect(task_monitor_composite_widget_p, + &TaskMonitorCompositeWidget::cancelTaskSignal, + loader_sp.get(), + &MassSpecDataFileLoader::cancelOperation); - action_p = - new QAction("Show &mass spectra window", dynamic_cast(this)); - action_p->setShortcut(QKeySequence("Ctrl+W, M")); - action_p->setStatusTip("Show the mass spectra window"); - connect( - action_p, &QAction::triggered, this, &ProgramWindow::showMassSpectraWnd); - mp_windowsMenu->addAction(action_p); + // We need to register the meta type for std::size_t because otherwise it + // cannobe shipped though signals. + qRegisterMetaType("std::size_t"); - action_p = - new QAction("Show &drift spectra window", dynamic_cast(this)); - action_p->setShortcut(QKeySequence("Ctrl+W, D")); - action_p->setStatusTip("Show the drift spectra window"); - connect( - action_p, &QAction::triggered, this, &ProgramWindow::showDriftSpectraWnd); - mp_windowsMenu->addAction(action_p); + task_monitor_composite_widget_p->makeMassSpecDataFileLoaderConnections( + loader_sp.get()); + // From the file accessor get a shared pointer to the MS run reader for the ms + // run id of interest. + pappso::MsRunReaderSPtr ms_run_reader_sp = + ms_file_accessor.msRunReaderSp(ms_run_id_csp); - action_p = new QAction("Show TIC/&XIC chrom. / mass spec. color maps window", - dynamic_cast(this)); - action_p->setShortcut(QKeySequence("Ctrl+W, I")); - action_p->setStatusTip( - "Show the TIC/XIC chrom. / mass spectra color maps window"); - connect(action_p, - &QAction::triggered, - this, - &ProgramWindow::showTicXicChromMassSpecColorMapWnd); - mp_windowsMenu->addAction(action_p); + if(ms_run_reader_sp == nullptr) + qFatal("Failed to get a MS data file reader."); + MsRunDataSetSPtr ms_run_data_set_sp = + std::make_shared(nullptr /*parent*/, ms_run_reader_sp); - action_p = new QAction("Show TIC/XIC chrom. / drift &spec. color maps window", - dynamic_cast(this)); - action_p->setShortcut(QKeySequence("Ctrl+W, S")); - action_p->setStatusTip( - "Show the TIC/XIC chrom. / drift spectra color maps window"); - connect(action_p, - &QAction::triggered, - this, - &ProgramWindow::showTicXicChromDriftSpecColorMapWnd); - mp_windowsMenu->addAction(action_p); + if(ms_run_data_set_sp == nullptr) + qFatal("Cannot be that pointer is nullptr"); + if(ms_run_data_set_sp.get() == nullptr) + qFatal("Cannot be that pointer is nullptr"); - action_p = new QAction("Show drift s&pec. / mass spec. color maps window", - dynamic_cast(this)); - action_p->setShortcut(QKeySequence("Ctrl+W, P")); - action_p->setStatusTip( - "Show the drift spectra / mass spectra color maps window"); - connect(action_p, - &QAction::triggered, - this, - &ProgramWindow::showDriftSpecMassSpecColorMapWnd); - mp_windowsMenu->addAction(action_p); + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); + // Inform the loader that the mass spec data is there. + loader_sp->setMsRunDataSet(ms_run_data_set_sp); - action_p = - new QAction("Show tas&k monitor window", dynamic_cast(this)); - action_p->setShortcut(QKeySequence("Ctrl+W, T")); - action_p->setStatusTip("Show the task monitor window"); - connect( - action_p, &QAction::triggered, this, &ProgramWindow::showTaskMonitorWnd); - mp_windowsMenu->addAction(action_p); + // qRegisterMetaType("msxps::minexpert::MsRunDataSetSPtr"); + qRegisterMetaType("MsRunDataSetSPtr"); + + // This is how we start the computation in the MsRunReadTask object. + connect(this, + &ProgramWindow::readMsRunDataSignal, + ms_run_read_task_p, + &MsRunReadTask::readMsRunData, + // Fundamental for signals that travel across QThread instances... + Qt::QueuedConnection); + // When the read task finishes, it sends a signal that we trap to go on with + // the file data loading procedure in another function. - action_p = new QAction("Show open ms r&un data sets window", - dynamic_cast(this)); - action_p->setShortcut(QKeySequence("Ctrl+W, O")); - action_p->setStatusTip("Show the open MS run data sets window"); - connect(action_p, - &QAction::triggered, + connect(ms_run_read_task_p, + &MsRunReadTask::finishedReadingMsRunDataSignal, this, - &ProgramWindow::showOpenMsRunDataSetsWnd); + &ProgramWindow::finishedReadingMsRunData, + // Fundamental for signals that travel across QThread instances... + Qt::QueuedConnection); - mp_windowsMenu->addAction(action_p); + QThread *thread_p = new QThread; + // Move the task to the matching thread. + ms_run_read_task_p->moveToThread(thread_p); + thread_p->start(); - action_p = new QAction("Show &console window", dynamic_cast(this)); - action_p->setShortcut(QKeySequence("Ctrl+W, C")); - action_p->setStatusTip("Show the console window"); - connect(action_p, &QAction::triggered, this, &ProgramWindow::showConsoleWnd); + // Since we allocated the QThread dynamically we need to be able to destroy it + // later, so make the connection. + connect(ms_run_read_task_p, + &MsRunReadTask::finishedReadingMsRunDataSignal, + this, + [thread_p, ms_run_read_task_p]() { + // Do not forget that we have to delete the MsRunReadTask allocated + // instance. + ms_run_read_task_p->deleteLater(); + // Once the task has been labelled to be deleted later, we can stop + // the thread and ask for it to also be deleted later. + thread_p->deleteLater(), thread_p->quit(); + thread_p->wait(); + }); - mp_windowsMenu->addAction(action_p); + // qDebug() << "Emitting readMsRunDataSignal(ms_run_read_task_p, " + //"ms_run_reader_sp, loader_sp);"; - mp_windowsMenu->addSeparator(); + emit readMsRunDataSignal(ms_run_read_task_p, ms_run_reader_sp, loader_sp); - action_p = new QAction("Save &workspace", dynamic_cast(this)); - action_p->setStatusTip("Save the current layout of the workspace"); - connect(action_p, &QAction::triggered, this, &ProgramWindow::saveWorkspace); + return true; +} - mp_windowsMenu->addAction(action_p); +bool +ProgramWindow::openMassSpectrometryFileFromClipBoard() +{ + QClipboard *clipboard = QGuiApplication::clipboard(); + QString ms_data = clipboard->text(); - // Utilities menu - mp_utilitiesMenu = menuBar()->addMenu("&Utilities"); + QDateTime current_date_time = QDateTime::currentDateTime(); - action_p = - new QAction("XIC chromatogram &extractions", dynamic_cast(this)); - action_p->setStatusTip("Open the XIC chromatogram extraction functionality"); - action_p->setShortcut(tr("Ctrl+X, E")); + QString time_as_string = current_date_time.toString("yyyyMMdd-HHmmss"); - connect( - action_p, &QAction::triggered, this, &ProgramWindow::showXicExtractionWnd); + return openMassSpectrometryFileFromText(ms_data, + "clipBoard-" + time_as_string); +} - mp_utilitiesMenu->addAction(action_p); +bool +ProgramWindow::openMassSpectrometryFileFromText(const QString &text, + const QString &sample_name) +{ - action_p = new QAction("&Isotopic cluster calculations", - dynamic_cast(this)); - action_p->setStatusTip("Open the isotopic cluster calculation functionality"); - action_p->setShortcut(QKeySequence("Ctrl+I, C")); + // qDebug() << "Opening mass spectrum from text with sample name:" + //<< sample_name; - connect(action_p, &QAction::triggered, this, &ProgramWindow::showIsoSpecDlg); + if(text.isEmpty()) + { + statusBar()->showMessage(QString("The clipboard is empty"), 4000); - mp_utilitiesMenu->addAction(action_p); + return false; + } - action_p = - new QAction("Mass peak &shape calculations", dynamic_cast(this)); - action_p->setStatusTip("Open the mass peak shape calculation functionality"); - action_p->setShortcut(QKeySequence("Ctrl+M, S")); + // Now write the text to a temporary file and load it. - connect( - action_p, &QAction::triggered, this, &ProgramWindow::showMassPeakShaperDlg); + // Get a directory suitable for temp files. - mp_utilitiesMenu->addAction(action_p); + QDir sys_tmp_dir = QDir::temp(); + // Craft the sample name with the date and time - // Preferences menu - mp_preferencesMenu = menuBar()->addMenu("&Preferences"); + QString temp_file_name = "mineXpert2-"; - action_p = - new QAction("Set max. thread count", dynamic_cast(this)); - action_p->setStatusTip("Set the maximum number of threads to be used for the integrations"); - action_p->setShortcut(tr("Ctrl+P, T")); + temp_file_name.append( + QDateTime::currentDateTime().toString("ddMMyyyy-HHmmss")); - connect( - action_p, &QAction::triggered, [this]() - { - std::size_t ideal_thread_count = QThread::idealThreadCount(); + QFile file(sys_tmp_dir.absolutePath() + '/' + temp_file_name); - m_maxThreadUseCount = QInputDialog::getInt(this, "Set max. thread count", - "Count", ideal_thread_count, 1, ideal_thread_count, 1); + // qDebug() << "Opening file: " << file.fileName(); - //qDebug() << "Set the max. thread use count to : " << m_maxThreadUseCount; - }); + if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) + qFatal("Failed to open destination file."); - mp_preferencesMenu->addAction(action_p); + QTextStream out(&file); + out << text; - // Help menu - mp_helpMenu = menuBar()->addMenu("&Help"); + out.flush(); - action_p = new QAction(QIcon(":/images/icons/svg/help-information-icon.svg"), - tr("&About"), - dynamic_cast(this)); - action_p->setStatusTip(tr("Show the &application's About box")); - action_p->setShortcut(QKeySequence("Ctrl+H, A")); + file.close(); - connect(action_p, &QAction::triggered, this, &ProgramWindow::showAboutDlg); - mp_helpMenu->addAction(action_p); + // qDebug() << "File " << file.fileName() << "has been closed now."; - action_p = - new QAction(QIcon(":/images/icons/svg/help-qt-information-icon.svg"), - tr("About &Qt"), - dynamic_cast(this)); - action_p->setStatusTip(tr("Show the Qt &library's About box")); - connect(action_p, &QAction::triggered, this, &Application::aboutQt); - action_p->setShortcut(QKeySequence("Ctrl+H, Q")); + bool result = openMassSpectrometryFile(file.fileName(), true, sample_name); - mp_helpMenu->addAction(action_p); + return result; } void -ProgramWindow::setupWindow() +ProgramWindow::openAnalysisPreferencesDlg() { - // qDebug(); + if(mp_analysisPreferencesDlg == nullptr) + { + mp_analysisPreferencesDlg = + new AnalysisPreferencesDlg(dynamic_cast(this), m_moduleName); + } - QPixmap pixmap(":/images/msxpertsuite-icon-32.png"); - QIcon icon(pixmap); - setWindowIcon(icon); + int res = mp_analysisPreferencesDlg->exec(); - setAttribute(Qt::WA_DeleteOnClose); - statusBar()->setSizeGripEnabled(true); + if(res == QDialog::Accepted) + { + // Copy the preferences from the dialog window to *this. + mpa_analysisPreferences = new AnalysisPreferences( + mp_analysisPreferencesDlg->analysisPreferences()); - createMenusAndActions(); - initializeAllWindows(); - readSettings(); -} + // Let's check if the recording should go a file, in which case we test + // that we can open it properly. -AboutDlg * -ProgramWindow::showAboutDlg() -{ - // The application name will be set automatically by default parameter - // value. - AboutDlg *dlg = new AboutDlg(this, m_moduleName); + if((mpa_analysisPreferences->m_recordTarget & + RecordTarget::RECORD_TO_FILE) == RecordTarget::RECORD_TO_FILE) + { + // Now check that the analysis file could be opened. - dlg->show(); + if(mpa_analysisFile != nullptr) + { + delete mpa_analysisFile; + mpa_analysisFile = nullptr; + } - return dlg; -} + mpa_analysisFile = new QFile(mpa_analysisPreferences->m_fileName); + bool res = false; -void -ProgramWindow::setMaxThreadUseCount(std::size_t count) -{ - m_maxThreadUseCount = count; -} + if(mpa_analysisPreferences->m_fileOpenMode == QIODevice::Truncate) + // Interestingly, only truncate did not work. Since writeonly + // implies truncate, that's fine, and it works. -std::size_t -ProgramWindow::getMaxThreadUseCount() -{ - return m_maxThreadUseCount; -} + res = mpa_analysisFile->open(QIODevice::WriteOnly); + else + res = mpa_analysisFile->open(QIODevice::Append); + if(!res) + { + delete mpa_analysisFile; + mpa_analysisFile = nullptr; -TaskMonitorWnd * -ProgramWindow::getTaskMonitorWnd() const -{ - return mp_taskMonitorWnd; + QMessageBox msgBox; + msgBox.setText( + "Failed to open the analysis file, please fix " + "the analysis preferences."); + msgBox.exec(); + + return; + } + else + { + // Close the file, which will be opened each time it is + // necessary. + mpa_analysisFile->close(); + + // We can effectively start the work. The windows needing to + // access the file will call getAnalysisFile() and make sure that + // it is not nullptr. + } + } + } + else // if(res == QDialog::Accepted) + { + // The dialog returned a rejected result. We cannot do anything. + } } -bool -ProgramWindow::openMassSpectrometryFileDlg(const QString &dir_name, - bool full_in_memory) +void +ProgramWindow::msRunDataSetRemovalRequested( + MsRunDataSetCstSPtr &ms_run_data_set_csp) { - QFileDialog file_dialog( - this, - QString("%1 - Select mass spectrometry data file(s)").arg(m_moduleName)); + // qDebug() << "Removal of ms run data set:" << ms_run_data_set_csp.get() + //<< "requested"; - file_dialog.setFileMode(QFileDialog::ExistingFiles); - file_dialog.setViewMode(QFileDialog::Detail); - file_dialog.setAcceptMode(QFileDialog::AcceptOpen); + // The user asks that a given ms run data set be removed from the software. + // We need to orderly remove all the shared pointer references so that the + // object is destroyed. Shared pointers to the ms run data set are located + // in the plottables created on the basis of the ms run data set. We need to + // remove from all the plot widgets, all the plottables that have been + // created using the ms run data set as the starting point of integrations. - // Open the dialog in the right directory. - if(dir_name.isEmpty()) - file_dialog.setDirectory(m_lastUsedDirectory); - else - file_dialog.setDirectory(dir_name); + // All the plottables are registered in the tree that mimicks the structure + // of all the plottable and plot widget in the program. - QStringList file_names; + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); - if(file_dialog.exec()) - { - file_names = file_dialog.selectedFiles(); + // Find all the root nodes that match ms_run_data_set_csp non recursively. + std::vector found_nodes = + m_dataPlottableTree.findNodes(ms_run_data_set_csp, false); - // Store the directory name whence the selected files come. + // qDebug() << "Found nodes:" << found_nodes.size() << "nodes:"; + // for(std::size_t iter = 0; iter < found_nodes.size(); ++iter) + // qDebug() << found_nodes.at(iter)->toString(0, true); - if(file_names.size()) - { - QString last_used_directory; - QString first_file_name = file_names.at(0); - QFileInfo file_info = QFileInfo(first_file_name); - m_lastUsedDirectory = file_info.absoluteDir().dirName(); - } - } + // Since each node has both the plot widget and the plottable pointer, we + // can ask for the recursive destruction of the plottable. - for(int iter = 0; iter < file_names.size(); ++iter) - { - QString cur_file_name = file_names.at(iter); + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); - bool res = openMassSpectrometryFile(cur_file_name, full_in_memory); + for(auto &&node : found_nodes) + { + // true: recursively + // false: not destroying a widget. - if(!res) - QMessageBox::warning(this, - "Mass spectrometry file loading failed", - "The file " + cur_file_name + "failed to load."); + plottableDestructionRequested( + node->getPlotWidget(), node->getPlottable(), true); } - return true; -} - + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); -bool -ProgramWindow::openMassSpectrometryFileFromText(const QString &text, - const QString &sample_name) -{ + // Look for a tree view window that matches the ms + // run data set. - // qDebug() << "Opening mass spectrum from text with sample name:" - //<< sample_name; + std::map::iterator + res_iterator = std::find_if( + mp_msRunDataSetTableViewWndMap.begin(), + mp_msRunDataSetTableViewWndMap.end(), + [ms_run_data_set_csp]( + const std::pair item) { + return item.first == ms_run_data_set_csp; + }); - if(text.isEmpty()) + if(res_iterator == mp_msRunDataSetTableViewWndMap.end()) { - statusBar()->showMessage(QString("The clipboard is empty"), 4000); + // Nothing to do, the data set had not associated tree view. + } + else + { + delete res_iterator->second; - return false; + mp_msRunDataSetTableViewWndMap.erase(ms_run_data_set_csp); } - // Now write the text to a temporary file and load it. + // Finally remove the ms run data set item from the list widget in the + // open ms run data set dialog window. - // Get a directory suitable for temp files. + mp_openMsRunDataSetsDlg->removeMsRunDataSet(ms_run_data_set_csp); - QDir sys_tmp_dir = QDir::temp(); + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); +} - // Craft the sample name with the date and time - QString temp_file_name = "mineXpert2-"; +const DataPlottableTree & +ProgramWindow::getDataPlottableTree() const +{ + return m_dataPlottableTree; +} - temp_file_name.append( - QDateTime::currentDateTime().toString("ddMMyyyy-HHmmss")); - QFile file(sys_tmp_dir.absolutePath() + '/' + temp_file_name); +std::vector +ProgramWindow::allSelectedOrUniqueMsRunDataSet() +{ + return mp_openMsRunDataSetsDlg->allSelectedOrUniqueMsRunDataSets(); +} - // qDebug() << "Opening file: " << file.fileName(); - if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) - qFatal("Failed to open destination file."); +BaseTracePlotWnd * +ProgramWindow::getPlotWndPtr(const QString &type_name) +{ + if(type_name != "mass spectrum" && type_name != "tic xic chromatogram" && + type_name != "drift spectrum") + qFatal("Error with the plot window type name."); - QTextStream out(&file); + if(type_name == "mass spectrum") + return mp_massSpecPlotWnd; + else if(type_name == "tic xic chromatogram") + return mp_ticXicChromPlotWnd; + else if(type_name == "drift spectrum") + return mp_driftSpecPlotWnd; - out << text; + qFatal("Should never encounter this point."); - out.flush(); + return nullptr; +} - file.close(); - // qDebug() << "File " << file.fileName() << "has been closed now."; +TaskMonitorWnd * +ProgramWindow::getTaskMonitorWnd() const +{ + return mp_taskMonitorWnd; +} - bool result = openMassSpectrometryFile(file.fileName(), true, sample_name); - return result; +void +ProgramWindow::integrateToDt( + QCPAbstractPlottable *parent_plottable_p, + std::shared_ptr> + qualified_mass_spectra_sp, + const ProcessingFlow &processing_flow) +{ + // Each trace plot window handles the integration requests that produce + // their own type of data, so we delegate the integration to the + // relevant window. + + mp_driftSpecPlotWnd->integrateToDt( + parent_plottable_p, qualified_mass_spectra_sp, processing_flow); } -bool -ProgramWindow::openMassSpectrometryFileFromClipBoard() +void +ProgramWindow::integrateToMz( + QCPAbstractPlottable *parent_plottable_p, + std::shared_ptr> + qualified_mass_spectra_sp, + const ProcessingFlow &processing_flow) { - QClipboard *clipboard = QGuiApplication::clipboard(); - QString ms_data = clipboard->text(); - - QDateTime current_date_time = QDateTime::currentDateTime(); + // Each trace plot window handles the integration requests that produce + // their own type of data, so we delegate the integration to the + // relevant window. - QString time_as_string = current_date_time.toString("yyyyMMdd-HHmmss"); + // qDebug().noquote() << "Integrating to mz with processing flow:" + //<< processing_flow.toString(); - return openMassSpectrometryFileFromText(ms_data, - "clipBoard-" + time_as_string); + mp_massSpecPlotWnd->integrateToMz( + parent_plottable_p, qualified_mass_spectra_sp, processing_flow); } + void -ProgramWindow::displayMassSpectralTrace(pappso::Trace trace, - const ProcessingFlow &processing_flow, - const QString &sample_name) +ProgramWindow::integrateToRt( + QCPAbstractPlottable *parent_plottable_p, + std::shared_ptr> + qualified_mass_spectra_sp, + const ProcessingFlow &processing_flow) { - // qDebug() << "The trace has size:" << trace.size() - //<< "and sample name:" << sample_name; + // Each trace plot window handles the integration requests that produce + // their own type of data, so we delegate the integration to the + // relevant window. - // There are two possibilities: - // - // 1. There is not a single MS run data set: we need to create one as a shim - // 2. There is/are at least one MS run data set: ask the user if they want to - // anchor the new to one of these by providing a selection list. + // qDebug().noquote() << "Integrating to rt with processing flow:" + //<< processing_flow.toString(); - // Check with the OpenMsRunDataSetsDlg if there is at least one MsRunDataSet - // available. + mp_ticXicChromPlotWnd->integrateToRt( + parent_plottable_p, qualified_mass_spectra_sp, processing_flow); +} - // Set the pointer to nullptr, that will help us later. - MsRunDataSetCstSPtr ms_run_data_set_csp = nullptr; - QColor color; +void +ProgramWindow::integrateToTicIntensity( +[[maybe_unused]] QCPAbstractPlottable *parent_plottable_p, + std::shared_ptr> + qualified_mass_spectra_sp, + const ProcessingFlow &processing_flow) +{ - bool ok = false; + // Get the ms run data set that for the graph we are going to base the + // integration on. + MsRunDataSetCstSPtr ms_run_data_set_csp = + processing_flow.getMsRunDataSetCstSPtr(); + if(ms_run_data_set_csp == nullptr) + qFatal("Cannot be that the pointer is nullptr."); - QString local_sample_name; + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - std::size_t opened_ms_run_data_sets = - mp_openMsRunDataSetsDlg->msRunDataSetCount(); + // Allocate the mass data integrator that is speciaized in the computation of + // TIC chromaotograms, starting from a vector of qualified mass spectrum + // pointers. - if(opened_ms_run_data_sets) - { + QualifiedMassSpectrumVectorMassDataIntegratorToTicInt + *mass_data_integrator_p = + new QualifiedMassSpectrumVectorMassDataIntegratorToTicInt( + ms_run_data_set_csp, processing_flow, qualified_mass_spectra_sp); - // There is a least one MS run data set. Provide a list to the user and - // let them choose one of these. There might also be a choice to create a - // shim file. + mass_data_integrator_p->setMaxThreadUseCount(m_maxThreadUseCount); - // Get a list of the MS run data sets. - std::vector ms_run_data_sets = - mp_openMsRunDataSetsDlg->allMsRunDataSets(); + MassDataIntegratorTask *mass_data_integrator_task_p = + new MassDataIntegratorTask(); - // qDebug() << "MS run data sets count:" << ms_run_data_sets.size(); + // This signal starts the computation in the MassDataIntegratorTask object. + connect( + this, - // The list of items' sample names will start with an item - // allowing the user to ask for the creation of a new MS run data set for - // the trace to be displayed. - QStringList item_texts = {"Create a new MS run data set"}; + static_cast( + &ProgramWindow::integrateQualifiedMassSpectrumVectorToTicIntensitySignal), - // Extract a list of strings from that list of widgets. - for(auto &&item : ms_run_data_sets) - { - local_sample_name = item->getMsRunId()->getSampleName(); - // qDebug() << "local_sample_name:" << local_sample_name; + mass_data_integrator_task_p, - item_texts.append(local_sample_name); - } + static_cast( + &MassDataIntegratorTask::integrateToTicIntensity), - // qDebug() << "All the sample names:" << item_texts; + // Fundamental for signals that travel across QThread instances... + Qt::QueuedConnection); - // Craft an input dialog. + // When the task finishes, it sends a signal that we trap to go on with + // the plot widget creation stuff. - QInputDialog input_dialog(this); - input_dialog.setComboBoxItems(item_texts); + connect(mass_data_integrator_task_p, - // Now as the user to select one item. + static_cast( + &MassDataIntegratorTask::finishedIntegratingDataSignal), - QString item_text = QInputDialog::getItem(this, - "Select a MS run data set", - "MS run data set:", - item_texts, - 0, - false, - &ok); - if(!ok) - { - // The user pressed cancel. Just return. - return; - } + this, - if(item_text != "Create a new MS run data set") - { - // Now we know that the user wants the new trace to be anchored to a - // given MsRunDataSet. + static_cast( + &ProgramWindow:: + finishedIntegratingQualifiedMassSpectrumVectorToTicIntensity), - ok = false; - ok = mp_openMsRunDataSetsDlg->msRunDataSetFromSampleName( - item_text, ms_run_data_set_csp, color); + // Fundamental for signals that travel across QThread instances... + Qt::QueuedConnection); - if(!ok || ms_run_data_set_csp == nullptr) - qFatal("Programming error."); + // Allocate the thread in which the integrator task will run. + QThread *thread_p = new QThread; - // At this point we know we won't need to create a shim ms run data - // set because ms_run_data_set_csp is no more nullptr and we also know - // the color. - } - else - { - // qDebug() << "Creating a new MS run data set."; - } - } - // End of - // if(opened_ms_run_data_sets) + // Move the task to the matching thread. + mass_data_integrator_task_p->moveToThread(thread_p); + thread_p->start(); - // Now test if we need to create a shim ms run data set or not by checking - // ms_run_data_set_csp + // Since we allocated the QThread dynamically we need to be able to destroy it + // later, so make the connection. + connect(mass_data_integrator_task_p, - if(ms_run_data_set_csp == nullptr) - { + static_cast( + &MassDataIntegratorTask::finishedIntegratingDataSignal), - // Craft a local sample name + this, - if(sample_name.isEmpty()) - { - QDateTime current_date_time = QDateTime::currentDateTime(); + [thread_p, mass_data_integrator_task_p]() { + // Do not forget that we have to delete the MassDataIntegratorTask + // allocated instance. + mass_data_integrator_task_p->deleteLater(); + // Once the task has been labelled to be deleted later, we can stop + // the thread and ask for it to also be deleted later. + thread_p->deleteLater(), thread_p->quit(); + thread_p->wait(); + }); - QString time_as_string = current_date_time.toString("yyyyMMdd-HHmm"); + // Ensure the mass data integrator messages are used. - local_sample_name = "mass-spectrum-" + time_as_string; - } - else - local_sample_name = sample_name; + connect( + mass_data_integrator_p, + &QualifiedMassSpectrumVectorMassDataIntegrator::logTextToConsoleSignal, + this, + &ProgramWindow::logTextToConsole); - openMassSpectrometryFileFromText(trace.toString(), local_sample_name); + // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - // At this point we should have a new file. When the new ms run data set - // will be added to the open ms run data sets dlg list widget, it will be - // selected. + // Allocate a new TaskMonitorCompositeWidget that will receive all the + // integrator's signals and provide feedback to the user about the ongoing + // integration. - showOpenMsRunDataSetsWnd(); + TaskMonitorCompositeWidget *task_monitor_composite_widget_p = + mp_taskMonitorWnd->addTaskMonitorWidget(Qt::red); - QMessageBox::information( - this, - "Select a MS run data set", - "One shim mass data file was loaded.\n" - "Please, perform the task agin and select the right MS run data set."); + // Initialize the monitor composite widget's widgets and make all the + // connections mass data integrator <--> widget. - return; - } + task_monitor_composite_widget_p->setMsRunIdText( + ms_run_data_set_csp->getMsRunId()->getSampleName()); + task_monitor_composite_widget_p->setTaskDescriptionText( + "Integrating to TIC intensity from the table view"); + task_monitor_composite_widget_p->setProgressBarMinValue(0); - // At this point we have what we needed, a proper ms run data set pointer! + // Make the connections - ProcessingFlow local_processing_flow(processing_flow); + // When the MsRunReadTask instance has finished working, it will send a signal + // that we trap to finally destroy (after a time lag of some seconds, the + // monitor widget. - local_processing_flow.setMsRunDataSetCstSPtr(ms_run_data_set_csp); + connect(mass_data_integrator_task_p, + static_cast( + &MassDataIntegratorTask::finishedIntegratingDataSignal), + task_monitor_composite_widget_p, + &TaskMonitorCompositeWidget::taskFinished, + Qt::QueuedConnection); - mp_massSpecPlotWnd->addTracePlot( - trace, ms_run_data_set_csp, local_processing_flow, color, nullptr); -} + // If the user clicks the cancel button, relay the signal to the loader. + connect(task_monitor_composite_widget_p, + &TaskMonitorCompositeWidget::cancelTaskSignal, + mass_data_integrator_p, + &QualifiedMassSpectrumVectorMassDataIntegrator::cancelOperation); + task_monitor_composite_widget_p->makeMassDataIntegratorConnections( + mass_data_integrator_p); -bool -ProgramWindow::openMassSpectrometryFile(const QString &file_name, - bool full_in_memory, - const QString &sample_name) -{ - // qDebug() << "Opening mass spectrometry file:" << file_name - //<< "with sample name:" << sample_name - //<< "from thread:" << QThread::currentThread(); + emit integrateQualifiedMassSpectrumVectorToTicIntensitySignal( + mass_data_integrator_p); - if(file_name.isEmpty() || !QFileInfo::exists(file_name)) - { - return openMassSpectrometryFileDlg(QDir::homePath(), full_in_memory); - } + // Because the emitter is the same ProgramWindow object, we need to disconnect + // the signal so that at next opening of mass data file, it will not be called + // twice. + disconnect( + this, - // At this point, we have a file name. Let's store the directory where the - // file sits so that later the user can be directed there immediately. + static_cast( + &ProgramWindow::integrateQualifiedMassSpectrumVectorToTicIntensitySignal), - m_lastUsedDirectory = QFileInfo(file_name).dir().absolutePath(); + mass_data_integrator_task_p, - // Now let's start the file type identification work. + static_cast( + &MassDataIntegratorTask::integrateToTicIntensity)); +} - // The MsFileAccessor will allow to get a list of MS run ids that can then be - // used to request a MS run reader appropriate for the MS data file format. - // Beccause there might be more than one ms run in a single mzML file, we need - // to have a common prefix for all those ms run ids. - pappso::MsFileAccessor ms_file_accessor(file_name, m_msRunIdPrefix); - // qDebug() << "Could get MsFileAccessor."; +void +ProgramWindow::integrateToDtMz( + QCPAbstractPlottable *parent_plottable_p, + std::shared_ptr> + qualified_mass_spectra_sp, + const ProcessingFlow &processing_flow) +{ + mp_driftSpecMassSpecColorMapWnd->integrateToDtMz( + parent_plottable_p, qualified_mass_spectra_sp, processing_flow); +} - std::vector ms_run_ids = - ms_file_accessor.getMsRunIds(); - std::size_t run_count = ms_run_ids.size(); +void +ProgramWindow::integrateToDtRt( + QCPAbstractPlottable *parent_plottable_p, + std::shared_ptr> + qualified_mass_spectra_sp, + const ProcessingFlow &processing_flow) +{ + mp_ticXicChromDriftSpecColorMapWnd->integrateToDtRt( + parent_plottable_p, qualified_mass_spectra_sp, processing_flow); +} - // qDebug() << "The number of ms run ids:" << run_count; - if(!run_count) - { - QMessageBox::information(this, - "Open mass spectrometry file", - "This file does contain no MS run"); - return false; - } +void +ProgramWindow::integrateToMzRt( + QCPAbstractPlottable *parent_plottable_p, + std::shared_ptr> + qualified_mass_spectra_sp, + const ProcessingFlow &processing_flow) +{ + mp_ticXicChromMassSpecColorMapWnd->integrateToMzRt( + parent_plottable_p, qualified_mass_spectra_sp, processing_flow); +} - int run_index = 0; - // qDebug() << "The number of ms runs in the file is:" << run_count; +void +ProgramWindow::xicIntegrationToRt(const ProcessingFlow &processing_flow) +{ + // qDebug().noquote() << "XIC integration to rt with processing flow:" + //<< processing_flow.toString(); - // If there are more than one run, let the user select the one they are - // interested in. + // Sanity check: - if(run_count > 1) - { + if(processing_flow.getMsRunDataSetCstSPtr() == nullptr) + qFatal("Cannot be that the pointer is nullptr."); - // If the user cancels the dialog, returns -1, otherwise returns the index - // of the ms run id. + MsRunDataSetCstSPtr ms_run_data_set_csp = + processing_flow.getMsRunDataSetCstSPtr(); - run_index = selectMsRun(ms_run_ids); + // Pass the integrator the flow we got as param and that describes in its most + // recent step the integration that it should perform. + MsRunDataSetTreeMassDataIntegratorToRt *mass_data_integrator_p = + new MsRunDataSetTreeMassDataIntegratorToRt(ms_run_data_set_csp, + processing_flow); - // qDebug() << "The run_index: " << run_index; + // Ensure the mass data integrator messages are used. - if(run_index == -1) - return false; - } + connect(mass_data_integrator_p, + &MassDataIntegrator::logTextToConsoleSignal, + this, + &ProgramWindow::logTextToConsole); - // Now actually load the data! + // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - // Allocate a ms run reader task to read the data. - MsRunReadTask *ms_run_read_task_p = new MsRunReadTask(this); + // Allocate a mass data integrator to integrate the data. - // Get the first run id of the vector. - pappso::MsRunIdCstSPtr ms_run_id_csp = ms_run_ids.at(run_index); + MassDataIntegratorTask *mass_data_integrator_task_p = + new MassDataIntegratorTask(); - if(!sample_name.isEmpty()) - { - // qDebug() << "The sample name is not empty:" << sample_name; + // This signal starts the computation in the MassDataIntegratorTask object. + connect( + this, + // SIGNAL(integrateToRtSignal(MsRunDataSetTreeMassDataIntegratorToRt *)), + static_cast( + &ProgramWindow::integrateToRtSignal), + mass_data_integrator_task_p, + // SLOT(integrateToRt(MsRunDataSetTreeMassDataIntegratorToRt *)), + static_cast( + &MassDataIntegratorTask::integrateToRt), + // Fundamental for signals that travel across QThread instances... + Qt::QueuedConnection); - std::const_pointer_cast(ms_run_id_csp) - ->setSampleName(sample_name); - } + // Allocate the thread in which the integrator task will run. + QThread *thread_p = new QThread; - // qDebug() << "The run id as text:" << ms_run_id_csp->toString(); + // Move the task to the matching thread. + mass_data_integrator_task_p->moveToThread(thread_p); + thread_p->start(); - MassSpecDataFileLoaderSPtr loader_sp = - std::make_shared(ms_file_accessor.getFileName(), - full_in_memory); + // When the read task finishes, it sends a signal that we trap to go on with + // the plot widget creation stuff. - if(loader_sp == nullptr) - qFatal("Programming error"); + // Since we allocated the QThread dynamically we need to be able to destroy it + // later, so make the connection. + connect( + mass_data_integrator_task_p, + static_cast( + &MassDataIntegratorTask::finishedIntegratingDataSignal), + this, + [this, thread_p, mass_data_integrator_p, mass_data_integrator_task_p]() { + // Do not forget that we have to delete the MassDataIntegratorTask + // allocated instance. + mass_data_integrator_task_p->deleteLater(); + // Once the task has been labelled to be deleted later, we can stop + // the thread and ask for it to also be deleted later. + thread_p->deleteLater(), thread_p->quit(); + thread_p->wait(); + this->finishedXicIntegrationToRt(mass_data_integrator_p); + }); - // Allocate a new TaskMonitorCompositeWidget - TaskMonitorCompositeWidget *task_monitor_composite_widget_p = - mp_taskMonitorWnd->addTaskMonitorWidget(Qt::red); + // Allocate a new TaskMonitorCompositeWidget that will receive all the + // integrator's signals and provide feedback to the user about the ongoing + // integration. - // Make sure the task monitor window is visible ! - showTaskMonitorWnd(); + TaskMonitorCompositeWidget *task_monitor_composite_widget_p = + getTaskMonitorWnd()->addTaskMonitorWidget(Qt::red); // Initialize the monitor composite widget's widgets and make all the - // connections loader <--> widget. + // connections mass data integrator <--> widget. task_monitor_composite_widget_p->setMsRunIdText( - ms_run_id_csp->getSampleName()); + ms_run_data_set_csp->getMsRunId()->getSampleName()); task_monitor_composite_widget_p->setTaskDescriptionText( - "Reading MS run data"); + "Integrating to XIC chromatogram."); task_monitor_composite_widget_p->setProgressBarMinValue(0); // Make the connections - // When the MsRunReadTask instance has finished working, it will send a signal - // that we trap to finally destroy (after a time lag of some seconds, the - // monitor widget. - + // When the integrator task instance has finished working, it will send a + // signal that we trap to finally destroy (after a time lag of some seconds, + // the monitor widget. - connect(ms_run_read_task_p, - &MsRunReadTask::finishedReadingMsRunDataSignal, + connect(mass_data_integrator_task_p, + static_cast( + &MassDataIntegratorTask::finishedIntegratingDataSignal), task_monitor_composite_widget_p, &TaskMonitorCompositeWidget::taskFinished, Qt::QueuedConnection); @@ -913,1297 +1008,444 @@ // If the user clicks the cancel button, relay the signal to the loader. connect(task_monitor_composite_widget_p, &TaskMonitorCompositeWidget::cancelTaskSignal, - loader_sp.get(), - &MassSpecDataFileLoader::cancelOperation); + mass_data_integrator_p, + &MassDataIntegrator::cancelOperation); // We need to register the meta type for std::size_t because otherwise it - // cannobe shipped though signals. + // cannot be shipped though signals. qRegisterMetaType("std::size_t"); - task_monitor_composite_widget_p->makeMassSpecDataFileLoaderConnections( - loader_sp.get()); + // Now make all the connections that will allow the integrator to provide + // dynamic feedback to the user via the task monitor widget. + task_monitor_composite_widget_p->makeMassDataIntegratorConnections( + mass_data_integrator_p); - // From the file accessor get a shared pointer to the MS run reader for the ms - // run id of interest. - pappso::MsRunReaderSPtr ms_run_reader_sp = - ms_file_accessor.msRunReaderSp(ms_run_id_csp); + // qDebug() << "going to emit integrateToRtSignal with mass " + //"data integrator:" + //<< mass_data_integrator_p; - if(ms_run_reader_sp == nullptr) - qFatal("Failed to get a MS data file reader."); + emit integrateToRtSignal(mass_data_integrator_p); - MsRunDataSetSPtr ms_run_data_set_sp = - std::make_shared(nullptr /*parent*/, ms_run_reader_sp); + // We do not want to make signal/slot calls more than once. This is because + // one user might well trigger more than one integration from this window to a + // mass spectrum. Thus we do not want that *this window be still connected to + // the specific mass_data_integrator_task_p when a new integration is + // triggered. We want the signal/slot pairs to be contained to specific + // objects. Each MassSpecTracePlotWnd::integrateToMz() call must be contained + // to a this/mass_data_integrator_task_p specific signal/slot pair. + disconnect( + this, + // SIGNAL(integrateToRtSignal(MsRunDataSetTreeMassDataIntegratorToRt *)), + static_cast( + &ProgramWindow::integrateToRtSignal), + mass_data_integrator_task_p, + // SLOT(integrateToRt(MsRunDataSetTreeMassDataIntegratorToRt *))); + static_cast( + &MassDataIntegratorTask::integrateToRt)); +} - if(ms_run_data_set_sp == nullptr) - qFatal("Cannot be that pointer is nullptr"); - if(ms_run_data_set_sp.get() == nullptr) - qFatal("Cannot be that pointer is nullptr"); +void +ProgramWindow::displayMassSpectralTrace(pappso::Trace trace, + const ProcessingFlow &processing_flow, + const QString &sample_name) +{ + // qDebug() << "The trace has size:" << trace.size() + //<< "and sample name:" << sample_name; - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); + // There are two possibilities: + // + // 1. There is not a single MS run data set: we need to create one as a shim + // 2. There is/are at least one MS run data set: ask the user if they want to + // anchor the new to one of these by providing a selection list. - // Inform the loader that the mass spec data is there. - loader_sp->setMsRunDataSet(ms_run_data_set_sp); + // Check with the OpenMsRunDataSetsDlg if there is at least one MsRunDataSet + // available. - // qRegisterMetaType("msxps::minexpert::MsRunDataSetSPtr"); - qRegisterMetaType("MsRunDataSetSPtr"); + // Set the pointer to nullptr, that will help us later. + MsRunDataSetCstSPtr ms_run_data_set_csp = nullptr; - // This is how we start the computation in the MsRunReadTask object. - connect(this, - &ProgramWindow::readMsRunDataSignal, - ms_run_read_task_p, - &MsRunReadTask::readMsRunData, - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); + QColor color; - // When the read task finishes, it sends a signal that we trap to go on with - // the file data loading procedure in another function. + bool ok = false; - connect(ms_run_read_task_p, - &MsRunReadTask::finishedReadingMsRunDataSignal, - this, - &ProgramWindow::finishedReadingMsRunData, - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); + QString local_sample_name; - QThread *thread_p = new QThread; + std::size_t opened_ms_run_data_sets = + mp_openMsRunDataSetsDlg->msRunDataSetCount(); - // Move the task to the matching thread. - ms_run_read_task_p->moveToThread(thread_p); - thread_p->start(); + if(opened_ms_run_data_sets) + { - // Since we allocated the QThread dynamically we need to be able to destroy it - // later, so make the connection. - connect(ms_run_read_task_p, - &MsRunReadTask::finishedReadingMsRunDataSignal, - this, - [thread_p, ms_run_read_task_p]() { - // Do not forget that we have to delete the MsRunReadTask allocated - // instance. - ms_run_read_task_p->deleteLater(); - // Once the task has been labelled to be deleted later, we can stop - // the thread and ask for it to also be deleted later. - thread_p->deleteLater(), thread_p->quit(); - thread_p->wait(); - }); - - // qDebug() << "Emitting readMsRunDataSignal(ms_run_read_task_p, " - //"ms_run_reader_sp, loader_sp);"; - - emit readMsRunDataSignal(ms_run_read_task_p, ms_run_reader_sp, loader_sp); - - return true; -} - - -QFile * -ProgramWindow::getAnalysisFilePtr() -{ - return mpa_analysisFile; -} - - -AnalysisPreferences * -ProgramWindow::getAnalysisPreferences() -{ - return mpa_analysisPreferences; -} - - -void -ProgramWindow::openAnalysisPreferencesDlg() -{ - if(mp_analysisPreferencesDlg == nullptr) - { - mp_analysisPreferencesDlg = - new AnalysisPreferencesDlg(dynamic_cast(this), m_moduleName); - } + // There is a least one MS run data set. Provide a list to the user and + // let them choose one of these. There might also be a choice to create a + // shim file. - int res = mp_analysisPreferencesDlg->exec(); + // Get a list of the MS run data sets. + std::vector ms_run_data_sets = + mp_openMsRunDataSetsDlg->allMsRunDataSets(); - if(res == QDialog::Accepted) - { - // Copy the preferences from the dialog window to *this. - mpa_analysisPreferences = new AnalysisPreferences( - mp_analysisPreferencesDlg->analysisPreferences()); + // qDebug() << "MS run data sets count:" << ms_run_data_sets.size(); - // Let's check if the recording should go a file, in which case we test - // that we can open it properly. + // The list of items' sample names will start with an item + // allowing the user to ask for the creation of a new MS run data set for + // the trace to be displayed. + QStringList item_texts = {"Create a new MS run data set"}; - if((mpa_analysisPreferences->m_recordTarget & - RecordTarget::RECORD_TO_FILE) == RecordTarget::RECORD_TO_FILE) + // Extract a list of strings from that list of widgets. + for(auto &&item : ms_run_data_sets) { - // Now check that the analysis file could be opened. - - if(mpa_analysisFile != nullptr) - { - delete mpa_analysisFile; - mpa_analysisFile = nullptr; - } - - mpa_analysisFile = new QFile(mpa_analysisPreferences->m_fileName); - - bool res = false; - - if(mpa_analysisPreferences->m_fileOpenMode == QIODevice::Truncate) + local_sample_name = item->getMsRunId()->getSampleName(); + // qDebug() << "local_sample_name:" << local_sample_name; - // Interestingly, only truncate did not work. Since writeonly - // implies truncate, that's fine, and it works. + item_texts.append(local_sample_name); + } - res = mpa_analysisFile->open(QIODevice::WriteOnly); - else - res = mpa_analysisFile->open(QIODevice::Append); + // qDebug() << "All the sample names:" << item_texts; - if(!res) - { - delete mpa_analysisFile; - mpa_analysisFile = nullptr; + // Craft an input dialog. - QMessageBox msgBox; - msgBox.setText( - "Failed to open the analysis file, please fix " - "the analysis preferences."); - msgBox.exec(); + QInputDialog input_dialog(this); + input_dialog.setComboBoxItems(item_texts); - return; - } - else - { - // Close the file, which will be opened each time it is - // necessary. - mpa_analysisFile->close(); + // Now as the user to select one item. - // We can effectively start the work. The windows needing to - // access the file will call getAnalysisFile() and make sure that - // it is not nullptr. - } + QString item_text = QInputDialog::getItem(this, + "Select a MS run data set", + "MS run data set:", + item_texts, + 0, + false, + &ok); + if(!ok) + { + // The user pressed cancel. Just return. + return; } - } - else // if(res == QDialog::Accepted) - { - // The dialog returned a rejected result. We cannot do anything. - } -} - - -void -ProgramWindow::recordAnalysisStanza(QString stanza, const QColor &color) -{ - // Check that the user configured the analysis preferences. - - if(mpa_analysisPreferences == nullptr) - return; - // The record might go to a file or to the console, to the clipboard... - if((mpa_analysisPreferences->m_recordTarget & RecordTarget::RECORD_TO_FILE) == - RecordTarget::RECORD_TO_FILE) - { - if(mpa_analysisFile != nullptr) + if(item_text != "Create a new MS run data set") { + // Now we know that the user wants the new trace to be anchored to a + // given MsRunDataSet. - // Write the stanza, that was crafted by the calling plot widget to - // the file. - - if(!mpa_analysisFile->open(QIODevice::Append)) - { - statusBar()->showMessage( - QString("Could not record the step because " - "the file could not be opened."), - 4000); - } - else - { - mpa_analysisFile->write(stanza.toLatin1()); + ok = false; + ok = mp_openMsRunDataSetsDlg->msRunDataSetFromSampleName( + item_text, ms_run_data_set_csp, color); - // Force writing because we may want to have tail -f work fine on - // the file, and see modifications live to change fiels in a text - // editor. + if(!ok || ms_run_data_set_csp == nullptr) + qFatal("Programming error."); - mpa_analysisFile->flush(); - mpa_analysisFile->close(); - } + // At this point we know we won't need to create a shim ms run data + // set because ms_run_data_set_csp is no more nullptr and we also know + // the color. } else { - // qDebug() << "The mpa_analysisFile pointer is nullptr."; - - statusBar()->showMessage( - QString("Could not record the analysis step to file. " - "Please define a file to write the data to."), - 4000); + // qDebug() << "Creating a new MS run data set."; } } + // End of + // if(opened_ms_run_data_sets) - // Also, if recording to the console is asked for, then do that also. - if((mpa_analysisPreferences->m_recordTarget & - RecordTarget::RECORD_TO_CONSOLE) == RecordTarget::RECORD_TO_CONSOLE) - { - logColoredTextToConsole(stanza, color); - } + // Now test if we need to create a shim ms run data set or not by checking + // ms_run_data_set_csp - // Also, if recording to the clipboard is asked for, then do that also. - if((mpa_analysisPreferences->m_recordTarget & - RecordTarget::RECORD_TO_CLIPBOARD) == RecordTarget::RECORD_TO_CLIPBOARD) + if(ms_run_data_set_csp == nullptr) { - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(clipboard->text() + stanza, QClipboard::Clipboard); - } - - return; -} - - -// Here we need to finalize the reading of the ms run data set and also chain -// with the calculation of the corresponding TIC chromatogram. -void -ProgramWindow::finishedReadingMsRunData(MsRunDataSetSPtr ms_run_data_set_sp) -{ - - // qDebug() << "Finished reading ms run data for sample name:" - //<< ms_run_data_set_sp->getMsRunId()->getSampleName(); - - // We are here as a slot to a signal sent by the MsRunReadTask. - - // Increment the loaded file count so that next time we'll feed it with a new - // value to the file accessor constructor (see above). - ++m_loadedFileCount; - - // Since we are load ms run data from file, we need to provide the user with - // starting points for their data exploration: a TIC chromatogram at least. - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - -#if 0 - // Let's control how the data loading process went. - - pappso::MsRunDataSetTreeCstSPtr ms_run_data_set_tree_csp = - ms_run_data_set_sp->getMsRunDataSetTreeCstSPtr(); - const std::map &index_node_map = - ms_run_data_set_tree_csp->getIndexNodeMap(); - - qDebug() << "The number of spectra:" - << ms_run_data_set_tree_csp->getSpectrumCount() - << "and the data tree has this depth:" - << ms_run_data_set_tree_csp->depth() - << "and the index node map has this number of items:" - << index_node_map.size(); -#endif + // Craft a local sample name - // We want to try the multi-visitor approach: a single visitor that contains a - // vector of visitors. This is interesting because it makes reading the mass - // spectral data required only once. + if(sample_name.isEmpty()) + { + QDateTime current_date_time = QDateTime::currentDateTime(); - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); + QString time_as_string = current_date_time.toString("yyyyMMdd-HHmm"); - seedInitialTicChromatogramAndMsRunDataSetStatistics(ms_run_data_set_sp); + local_sample_name = "mass-spectrum-" + time_as_string; + } + else + local_sample_name = sample_name; - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); -} + openMassSpectrometryFileFromText(trace.toString(), local_sample_name); - -void -ProgramWindow::seedInitialTicChromatogramAndMsRunDataSetStatistics( - MsRunDataSetSPtr &ms_run_data_set_sp) -{ - if(ms_run_data_set_sp == nullptr) - qFatal("Cannot be that pointer is nullptr"); - - // qDebug() << "sample name:" - //<< ms_run_data_set_sp->getMsRunId()->getSampleName(); - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - - MassDataIntegratorTask *mass_data_integrator_task_p = - new MassDataIntegratorTask(); - - // This signal starts the computation in the MassDataIntegratorTask object. - connect( - this, - &ProgramWindow::seedInitialTicChromatogramAndMsRunDataSetStatisticsSignal, - mass_data_integrator_task_p, - &MassDataIntegratorTask:: - seedInitialTicChromatogramAndMsRunDataSetStatistics, - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // When the task finishes, it sends a signal that we trap to go on with - // the plot widget creation stuff. - - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - this, - &ProgramWindow:: - finishedSeedingInitialTicChromatogramAndMsRunDataSetStatistics, - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // Allocate the thread in which the integrator task will run. - QThread *thread_p = new QThread; - - // Move the task to the matching thread. - mass_data_integrator_task_p->moveToThread(thread_p); - thread_p->start(); - - // Since we allocated the QThread dynamically we need to be able to destroy it - // later, so make the connection. - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - this, - [thread_p, mass_data_integrator_task_p]() { - // Do not forget that we have to delete the MassDataIntegratorTask - // allocated instance. - mass_data_integrator_task_p->deleteLater(); - // Once the task has been labelled to be deleted later, we can stop - // the thread and ask for it to also be deleted later. - thread_p->deleteLater(), thread_p->quit(); - thread_p->wait(); - }); - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - - // No need to provide any processing flow object to the constructor, as we - // have none yet, this is the very first integration. - MsRunDataSetTreeMassDataIntegratorToRt *mass_data_integrator_p = - new MsRunDataSetTreeMassDataIntegratorToRt(ms_run_data_set_sp); - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - - // Ensure the mass data integrator messages are used. - - connect(mass_data_integrator_p, - &MassDataIntegrator::logTextToConsoleSignal, - this, - &ProgramWindow::logTextToConsole); - - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - - // Allocate a new TaskMonitorCompositeWidget that will receive all the - // integrator's signals and provide feedback to the user about the ongoing - // integration. - - TaskMonitorCompositeWidget *task_monitor_composite_widget_p = - mp_taskMonitorWnd->addTaskMonitorWidget(Qt::red); - - // Initialize the monitor composite widget's widgets and make all the - // connections mass data integrator <--> widget. - - task_monitor_composite_widget_p->setMsRunIdText( - ms_run_data_set_sp->getMsRunId()->getSampleName()); - task_monitor_composite_widget_p->setTaskDescriptionText( - "Integrating to initial TIC chromatogram and calculating MS run " - "statistics"); - task_monitor_composite_widget_p->setProgressBarMinValue(0); - - // Make the connections - - // When the MsRunReadTask instance has finished working, it will send a signal - // that we trap to finally destroy (after a time lag of some seconds, the - // monitor widget. - - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::taskFinished, - Qt::QueuedConnection); - - // If the user clicks the cancel button, relay the signal to the loader. - connect(task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::cancelTaskSignal, - mass_data_integrator_p, - &MassDataIntegrator::cancelOperation); - - // We need to register the meta type for std::size_t because otherwise it - // cannot be shipped though signals. - - qRegisterMetaType("std::size_t"); - - task_monitor_composite_widget_p->makeMassDataIntegratorConnections( - mass_data_integrator_p); - - // qDebug() << "going to emit integrateToInitialTicChromatogramSignal with - // mass " "data integrator:" - //<< mass_data_integrator_p; - - emit seedInitialTicChromatogramAndMsRunDataSetStatisticsSignal( - mass_data_integrator_p); - - // Because the emitter is the same ProgramWindow object, we need to disconnect - // the signal so that at next opening of mass data file, it will not be called - // twice. - disconnect( - this, - &ProgramWindow::seedInitialTicChromatogramAndMsRunDataSetStatisticsSignal, - mass_data_integrator_task_p, - &MassDataIntegratorTask:: - seedInitialTicChromatogramAndMsRunDataSetStatistics); -} - - -void -ProgramWindow::finishedSeedingInitialTicChromatogramAndMsRunDataSetStatistics( - MassDataIntegrator *mass_data_integrator_p) -{ - // qDebug(); - - // In this calculation, the m_mapTrace object in the integrator is the TIC - // chroamtogram. - - // The function below uses the mass_data_integrator_p to get to the TIC - // chromatogram and create the TIC chrom widget. - std::pair result_pair = - mp_ticXicChromPlotWnd->finishedIntegratingToInitialTicChromatogram( - static_cast( - mass_data_integrator_p)); - - // Make sure the tic chrom wnd is visible! - showTicXicChromatogramsWnd(); - - // qDebug() << "the sample name:" - //<< result_pair.first->getMsRunId()->getSampleName(); - - if(result_pair.first != nullptr) - { - // There were data in the data set ! Go on. - - mp_openMsRunDataSetsDlg->newOpenMsRunDataSet(result_pair.first, - result_pair.second); + // At this point we should have a new file. When the new ms run data set + // will be added to the open ms run data sets dlg list widget, it will be + // selected. showOpenMsRunDataSetsWnd(); - } - - // As for the statistics of the ms run data set, it has been set - // to the data set already. -} - - -void -ProgramWindow::integrateFromMsRunDataSetTableViewToRt( - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr> - qualified_mass_spectra_vector_sp, - const ProcessingFlow &processing_flow, - [[maybe_unused]] const QColor &color) -{ - // We receive a vector of qualified mass spectrum pointers that we need to - // combine. - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - - // Allocate the mass data integrator that is speciaized in the computation of - // TIC chromaotograms, starting from a vector of qualified mass spectrum - // pointers. - - QualifiedMassSpectrumVectorMassDataIntegratorToRt *mass_data_integrator_p = - new QualifiedMassSpectrumVectorMassDataIntegratorToRt( - ms_run_data_set_csp, processing_flow, qualified_mass_spectra_vector_sp); - - mass_data_integrator_p->setMaxThreadUseCount(m_maxThreadUseCount); - - MassDataIntegratorTask *mass_data_integrator_task_p = - new MassDataIntegratorTask(); - - // This signal starts the computation in the MassDataIntegratorTask object. - connect(this, - - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToRtSignal), - - mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::integrateToRt), - - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // When the task finishes, it sends a signal that we trap to go on with - // the plot widget creation stuff. - - connect(mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - - this, - - static_cast( - &ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToRt), - - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // Allocate the thread in which the integrator task will run. - QThread *thread_p = new QThread; - - // Move the task to the matching thread. - mass_data_integrator_task_p->moveToThread(thread_p); - thread_p->start(); - - // Since we allocated the QThread dynamically we need to be able to destroy it - // later, so make the connection. - connect(mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - - this, - - [thread_p, mass_data_integrator_task_p]() { - // Do not forget that we have to delete the MassDataIntegratorTask - // allocated instance. - mass_data_integrator_task_p->deleteLater(); - // Once the task has been labelled to be deleted later, we can stop - // the thread and ask for it to also be deleted later. - thread_p->deleteLater(), thread_p->quit(); - thread_p->wait(); - }); - - // Ensure the mass data integrator messages are used. - - connect( - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::logTextToConsoleSignal, - this, - &ProgramWindow::logTextToConsole); - - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - - // Allocate a new TaskMonitorCompositeWidget that will receive all the - // integrator's signals and provide feedback to the user about the ongoing - // integration. - - TaskMonitorCompositeWidget *task_monitor_composite_widget_p = - mp_taskMonitorWnd->addTaskMonitorWidget(Qt::red); - - // Initialize the monitor composite widget's widgets and make all the - // connections mass data integrator <--> widget. - - task_monitor_composite_widget_p->setMsRunIdText( - ms_run_data_set_csp->getMsRunId()->getSampleName()); - task_monitor_composite_widget_p->setTaskDescriptionText( - "Integrating to XIC chromatogram from the table view"); - task_monitor_composite_widget_p->setProgressBarMinValue(0); - - // Make the connections - - // When the MsRunReadTask instance has finished working, it will send a signal - // that we trap to finally destroy (after a time lag of some seconds, the - // monitor widget. - - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::taskFinished, - Qt::QueuedConnection); - - // If the user clicks the cancel button, relay the signal to the loader. - connect(task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::cancelTaskSignal, - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::cancelOperation); - - task_monitor_composite_widget_p->makeMassDataIntegratorConnections( - mass_data_integrator_p); - - emit integrateQualifiedMassSpectrumVectorToRtSignal(mass_data_integrator_p); - - // Because the emitter is the same ProgramWindow object, we need to disconnect - // the signal so that at next opening of mass data file, it will not be called - // twice. - disconnect(this, - - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToRtSignal), - - mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::integrateToRt)); -} - - -void -ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToRt( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p) -{ - // qDebug(); - - // At this point we need to ask the TIC XIC chromatogram window to display the - // result of the compuation. - - MsRunDataSetCstSPtr ms_run_data_set_csp = - mass_data_integrator_p->getMsRunDataSet(); - - pappso::Trace trace = mass_data_integrator_p->getMapTrace().toTrace(); - - ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); - - QColor color = - mp_openMsRunDataSetsDlg->colorForMsRunDataSet(ms_run_data_set_csp); - - // The newTrace function ensure that if there are pushpinned widget, the new - // trace will be handled according to the destination selected (wipe and - // replace, combine, overlay). - mp_ticXicChromPlotWnd->newTrace( - trace, ms_run_data_set_csp, processing_flow, color, nullptr); - - if(!mp_ticXicChromPlotWnd->isVisible()) - mp_ticXicChromPlotWnd->showWindow(); - - // Finally destroy the integrator! - delete mass_data_integrator_p; -} - - -void -ProgramWindow::integrateFromMsRunDataSetTableViewToDt( - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr> - vector_of_qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow, - [[maybe_unused]] const QColor &color) -{ - // We receive a vector of qualified mass spectrum pointers for which we need - // to calculate a TIC as a function of the drift time. - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - - // Allocate the mass data integrator that is speciaized in the computation of - // TIC chromaotograms, starting from a vector of qualified mass spectrum - // pointers. - - QualifiedMassSpectrumVectorMassDataIntegratorToDt *mass_data_integrator_p = - new QualifiedMassSpectrumVectorMassDataIntegratorToDt( - ms_run_data_set_csp, - processing_flow, - vector_of_qualified_mass_spectra_sp); - - mass_data_integrator_p->setMaxThreadUseCount(m_maxThreadUseCount); - - MassDataIntegratorTask *mass_data_integrator_task_p = - new MassDataIntegratorTask(); - - // This signal starts the computation in the MassDataIntegratorTask object. - - connect(this, - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToDtSignal), - mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::integrateToDt), - Qt::QueuedConnection); - - // When the task finishes, it sends a signal that we trap to go on with - // the plot widget creation stuff. - - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - this, - static_cast( - &ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToDt), - Qt::QueuedConnection); - - // Allocate the thread in which the integrator task will run. - QThread *thread_p = new QThread; - - // Move the task to the matching thread. - mass_data_integrator_task_p->moveToThread(thread_p); - thread_p->start(); - - // Since we allocated the QThread dynamically we need to be able to destroy it - // later, so make the connection. - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - this, - [thread_p, mass_data_integrator_task_p]() { - // Do not forget that we have to delete the MassDataIntegratorTask - // allocated instance. - mass_data_integrator_task_p->deleteLater(); - // Once the task has been labelled to be deleted later, we can stop - // the thread and ask for it to also be deleted later. - thread_p->deleteLater(), thread_p->quit(); - thread_p->wait(); - }); - - // Ensure the mass data integrator messages are used. - - connect( - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::logTextToConsoleSignal, - this, - &ProgramWindow::logTextToConsole); - - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - - // Allocate a new TaskMonitorCompositeWidget that will receive all the - // integrator's signals and provide feedback to the user about the ongoing - // integration. - - TaskMonitorCompositeWidget *task_monitor_composite_widget_p = - mp_taskMonitorWnd->addTaskMonitorWidget(Qt::red); - - // Initialize the monitor composite widget's widgets and make all the - // connections mass data integrator <--> widget. - - task_monitor_composite_widget_p->setMsRunIdText( - ms_run_data_set_csp->getMsRunId()->getSampleName()); - task_monitor_composite_widget_p->setTaskDescriptionText( - "Integrating to drift spectrum from the table view"); - task_monitor_composite_widget_p->setProgressBarMinValue(0); - - // Make the connections - - // When the MsRunReadTask instance has finished working, it will send a signal - // that we trap to finally destroy (after a time lag of some seconds, the - // monitor widget. - - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::taskFinished, - Qt::QueuedConnection); - - // If the user clicks the cancel button, relay the signal to the loader. - connect(task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::cancelTaskSignal, - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::cancelOperation); - - task_monitor_composite_widget_p->makeMassDataIntegratorConnections( - mass_data_integrator_p); - - emit integrateQualifiedMassSpectrumVectorToDtSignal(mass_data_integrator_p); - - // Because the emitter is the same ProgramWindow object, we need to disconnect - // the signal so that at next opening of mass data file, it will not be called - // twice. - disconnect(this, - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToDtSignal), - mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::integrateToDt)); -} - - -void -ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToDt( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p) -{ - // qDebug(); - - // At this point we need to ask the drift spectra window to display the - // result of the compuation. - - MsRunDataSetCstSPtr ms_run_data_set_csp = - mass_data_integrator_p->getMsRunDataSet(); - - pappso::Trace trace = mass_data_integrator_p->getMapTrace().toTrace(); - - ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); - - QColor color = - mp_openMsRunDataSetsDlg->colorForMsRunDataSet(ms_run_data_set_csp); - - mp_driftSpecPlotWnd->addTracePlot( - trace, ms_run_data_set_csp, processing_flow, color, nullptr); - - if(!mp_driftSpecPlotWnd->isVisible()) - mp_driftSpecPlotWnd->showWindow(); - - // Finally destroy the integrator! - delete mass_data_integrator_p; -} - - -void -ProgramWindow::integrateFromMsRunDataSetTableViewToMz( - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr> - qualified_mass_spectra_vector_sp, - const ProcessingFlow &processing_flow, - [[maybe_unused]] const QColor &color) -{ - // We receive a vector of qualified mass spectrum pointers that we need to - // combine to produce a combination mass spectrum. - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); - - // Allocate the mass data integrator that is speciaized in the computation of - // mass spectra, starting from a vector of qualified mass spectrum - // pointers. - - QualifiedMassSpectrumVectorMassDataIntegratorToMz *mass_data_integrator_p = - new QualifiedMassSpectrumVectorMassDataIntegratorToMz( - ms_run_data_set_csp, processing_flow, qualified_mass_spectra_vector_sp); - - mass_data_integrator_p->setMaxThreadUseCount(m_maxThreadUseCount); - - // qDebug() << "Receiving processing flow:" << processing_flow.toString(); - - MassDataIntegratorTask *mass_data_integrator_task_p = - new MassDataIntegratorTask(); - - // This signal starts the computation in the MassDataIntegratorTask object. - connect(this, - - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToMzSignal), - - mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::integrateToMz), - - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // When the task finishes, it sends a signal that we trap to go on with - // the plot widget creation stuff. - - connect(mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - - this, - - static_cast( - &ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToMz), - // - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // Allocate the thread in which the integrator task will run. - QThread *thread_p = new QThread; - - // Move the task to the matching thread. - mass_data_integrator_task_p->moveToThread(thread_p); - thread_p->start(); - - // Since we allocated the QThread dynamically we need to be able to destroy it - // later, so make the connection. - connect(mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - - this, - - [thread_p, mass_data_integrator_task_p]() { - // Do not forget that we have to delete the MassDataIntegratorTask - // allocated instance. - mass_data_integrator_task_p->deleteLater(); - // Once the task has been labelled to be deleted later, we can stop - // the thread and ask for it to also be deleted later. - thread_p->deleteLater(), thread_p->quit(); - thread_p->wait(); - }); - - // Ensure the mass data integrator messages are used. - - connect( - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::logTextToConsoleSignal, - this, - &ProgramWindow::logTextToConsole); - - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - - // Allocate a new TaskMonitorCompositeWidget that will receive all the - // integrator's signals and provide feedback to the user about the ongoing - // integration. - - TaskMonitorCompositeWidget *task_monitor_composite_widget_p = - mp_taskMonitorWnd->addTaskMonitorWidget(Qt::red); - - // Initialize the monitor composite widget's widgets and make all the - // connections mass data integrator <--> widget. - - task_monitor_composite_widget_p->setMsRunIdText( - ms_run_data_set_csp->getMsRunId()->getSampleName()); - task_monitor_composite_widget_p->setTaskDescriptionText( - "Integrating to mass spectrum from the table view"); - task_monitor_composite_widget_p->setProgressBarMinValue(0); - - // Make the connections - - // When the MsRunReadTask instance has finished working, it will send a signal - // that we trap to finally destroy (after a time lag of some seconds, the - // monitor widget. - - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::taskFinished, - Qt::QueuedConnection); - - // If the user clicks the cancel button, relay the signal to the loader. - connect(task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::cancelTaskSignal, - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::cancelOperation); - - task_monitor_composite_widget_p->makeMassDataIntegratorConnections( - mass_data_integrator_p); - - emit integrateQualifiedMassSpectrumVectorToMzSignal(mass_data_integrator_p); - - // Because the emitter is the same ProgramWindow object, we need to disconnect - // the signal so that at integration, it will not be called - // twice. - disconnect(this, - - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToMzSignal), - - mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::integrateToMz)); -} - - -void -ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToMz( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p) -{ - // At this point we need to ask the TIC XIC chromatogram window to display the - // result of the compuation. - - MsRunDataSetCstSPtr ms_run_data_set_csp = - mass_data_integrator_p->getMsRunDataSet(); - pappso::Trace trace = mass_data_integrator_p->getMapTrace().toTrace(); + QMessageBox::information( + this, + "Select a MS run data set", + "One shim mass data file was loaded.\n" + "Please, perform the task agin and select the right MS run data set."); - ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); + return; + } - // qDebug() << "The processing flow:" << processing_flow.toString(); + // At this point we have what we needed, a proper ms run data set pointer! - QColor color = - mp_openMsRunDataSetsDlg->colorForMsRunDataSet(ms_run_data_set_csp); + ProcessingFlow local_processing_flow(processing_flow); - // The newTrace function ensure that if there are pushpinned widget, the new - // trace will be handled according to the destination selected (wipe and - // replace, combine, overlay). - mp_massSpecPlotWnd->newTrace( - trace, ms_run_data_set_csp, processing_flow, color, nullptr); + local_processing_flow.setMsRunDataSetCstSPtr(ms_run_data_set_csp); + + mp_massSpecPlotWnd->addTracePlot( + trace, ms_run_data_set_csp, local_processing_flow, color, nullptr); +} - if(!mp_massSpecPlotWnd->isVisible()) - mp_massSpecPlotWnd->showWindow(); - // Finally destroy the integrator! - delete mass_data_integrator_p; +const BasePlotCompositeWidget * +ProgramWindow::getPlotWidget( + [[maybe_unused]] MsRunDataSetCstSPtr ms_run_data_set_csp, + QCPAbstractPlottable *plottable_p) +{ + return m_dataPlottableTree.getPlotWidget(plottable_p); } + void -ProgramWindow::integrateFromMsRunDataSetTableViewToTicIntensity( +ProgramWindow::documentMsRunDataPlottableFiliation( MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr> - qualified_mass_spectra_vector_sp, - const ProcessingFlow &processing_flow, - [[maybe_unused]] const QColor &color) + QCPAbstractPlottable *new_plottable_p, + QCPAbstractPlottable *parent_plottable_p, + BasePlotCompositeWidget *plot_widget_p) { - // We receive a vector of qualified mass spectrum pointers that we need to - // combine. + // qDebug(); // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); + // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); - // Allocate the mass data integrator that is speciaized in the computation of - // TIC chromaotograms, starting from a vector of qualified mass spectrum - // pointers. + // Now we need to document the filiation of the parent / child + // plottable. - QualifiedMassSpectrumVectorMassDataIntegratorToTicInt - *mass_data_integrator_p = - new QualifiedMassSpectrumVectorMassDataIntegratorToTicInt( - ms_run_data_set_csp, processing_flow, qualified_mass_spectra_vector_sp); + // qDebug() << "Before documenting: data plottable tree has" + //<< m_dataPlottableTree.depth() << "depth and" + //<< m_dataPlottableTree.size() << "size"; - mass_data_integrator_p->setMaxThreadUseCount(m_maxThreadUseCount); + m_dataPlottableTree.addPlottable( + ms_run_data_set_csp, new_plottable_p, parent_plottable_p, plot_widget_p); - MassDataIntegratorTask *mass_data_integrator_task_p = - new MassDataIntegratorTask(); + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); - // This signal starts the computation in the MassDataIntegratorTask object. - connect( - this, + // qDebug() << "After documenting data plot plottable tree has" + //<< m_dataPlottableTree.depth() << "depth and" + //<< m_dataPlottableTree.size() << "size"; +} - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToTicIntensitySignal), - mass_data_integrator_task_p, +void +ProgramWindow::plottableDestructionRequested( + BasePlotCompositeWidget *base_plot_composite_widget_p, + QCPAbstractPlottable *plottable_p, + bool recursively) +{ + // qDebug().noquote() << "Destruction of plottable:" + //<< pappso::Utils::pointerToString(plottable_p) + //<< "is being requested recursively:" << recursively; - static_cast( - &MassDataIntegratorTask::integrateToTicIntensity), + MsRunDataSetCstSPtr ms_run_data_set_csp = + base_plot_composite_widget_p->getMsRunDataSetCstSPtrForPlottable( + plottable_p); - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); - // When the task finishes, it sends a signal that we trap to go on with - // the plot widget creation stuff. + // When one plottable is on the verge of being deleted, we need to first + // check its node in the plottable data tree. This is because we need to + // at least remove that node ! - connect(mass_data_integrator_task_p, + // Further, there is another fact to keep in mind: if the user wanted to + // remove all the children plottable, then we would need to do that. - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), + // Another complexity: if the plottable that is removed had children, + // but the user does not want to remove them, we would need to reparent + // them to the parent of the plottable being deleted ! - this, + // How many children did that plottable have? - static_cast( - &ProgramWindow:: - finishedIntegratingQualifiedMassSpectrumVectorToTicIntensity), + // qDebug() << "Getting the right node for the plottable to be destroyed."; - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); + DataPlottableNode *plottable_node_p = + m_dataPlottableTree.findNode(plottable_p); - // Allocate the thread in which the integrator task will run. - QThread *thread_p = new QThread; + if(plottable_node_p == nullptr) + qFatal( + "Could not find a node for plottable . This is a programming " + "error."); - // Move the task to the matching thread. - mass_data_integrator_task_p->moveToThread(thread_p); - thread_p->start(); + // qDebug() << "The plottable is in node:" + //<< plottable_node_p->toString(0, true); - // Since we allocated the QThread dynamically we need to be able to destroy it - // later, so make the connection. - connect(mass_data_integrator_task_p, + std::size_t descendant_count = 0; + plottable_node_p->size(descendant_count); - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), + // qDebug() << "The plottable node has" << descendant_count << + // "descendants"; - this, + // bool res = + m_dataPlottableTree.removeNodeAndPlottable(plottable_node_p, recursively); - [thread_p, mass_data_integrator_task_p]() { - // Do not forget that we have to delete the MassDataIntegratorTask - // allocated instance. - mass_data_integrator_task_p->deleteLater(); - // Once the task has been labelled to be deleted later, we can stop - // the thread and ask for it to also be deleted later. - thread_p->deleteLater(), thread_p->quit(); - thread_p->wait(); - }); + // qDebug() << "Removal of node(s) and plottable(s) is success:" << res; - // Ensure the mass data integrator messages are used. + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); +} - connect( - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::logTextToConsoleSignal, - this, - &ProgramWindow::logTextToConsole); - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; +void +ProgramWindow::plottableDestructionRequested( + BasePlotCompositeWidget *base_plot_composite_widget_p, + QCPAbstractPlottable *plottable_p, + const pappso::BasePlotContext &context) +{ + bool recursively = context.m_keyboardModifiers & Qt::ControlModifier; - // Allocate a new TaskMonitorCompositeWidget that will receive all the - // integrator's signals and provide feedback to the user about the ongoing - // integration. + // If a recursive plottable destruction is requested, the the plottable + // and all its children, as documented by the main program's plottable + // tree nodes are to be destroyed. - TaskMonitorCompositeWidget *task_monitor_composite_widget_p = - mp_taskMonitorWnd->addTaskMonitorWidget(Qt::red); + // if(recursively) + // qDebug() << "Destruction recursive of plottable:" << plottable_p + //<< "is being requested."; + // else + // qDebug() << "Destruction of plottable:" << plottable_p + //<< "is being requested."; - // Initialize the monitor composite widget's widgets and make all the - // connections mass data integrator <--> widget. + return plottableDestructionRequested( + base_plot_composite_widget_p, plottable_p, recursively); +} - task_monitor_composite_widget_p->setMsRunIdText( - ms_run_data_set_csp->getMsRunId()->getSampleName()); - task_monitor_composite_widget_p->setTaskDescriptionText( - "Integrating to TIC intensity from the table view"); - task_monitor_composite_widget_p->setProgressBarMinValue(0); - // Make the connections +void +ProgramWindow::plotCompositeWidgetDestructionRequested( + BasePlotCompositeWidget *base_plot_composite_widget_p) +{ + // qDebug() << "Handling the destruction of the plot widget:" + //<< base_plot_composite_widget_p; - // When the MsRunReadTask instance has finished working, it will send a signal - // that we trap to finally destroy (after a time lag of some seconds, the - // monitor widget. + // One plot widget and all the plottables that it contains need to be + // destroyed. We first need to get a list of all the data plot tree nodes + // that match the plot widget. Then we non-recursively destroy all the + // plottables and matching data tree nodes. Finally we destroy the widget. - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::taskFinished, - Qt::QueuedConnection); + std::vector plottable_nodes = + m_dataPlottableTree.findNodes(base_plot_composite_widget_p, true); - // If the user clicks the cancel button, relay the signal to the loader. - connect(task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::cancelTaskSignal, - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::cancelOperation); + // qDebug() << "The number of nodes for plot widget:" + //<< base_plot_composite_widget_p << "is:" << plottable_nodes.size(); - task_monitor_composite_widget_p->makeMassDataIntegratorConnections( - mass_data_integrator_p); + // We want an orderly destruction of the plottable(s). - emit integrateQualifiedMassSpectrumVectorToTicIntensitySignal( - mass_data_integrator_p); + for(auto &&node_p : plottable_nodes) + { - // Because the emitter is the same ProgramWindow object, we need to disconnect - // the signal so that at next opening of mass data file, it will not be called - // twice. - disconnect( - this, + plottableDestructionRequested( + base_plot_composite_widget_p, node_p->getPlottable(), false); + } - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToTicIntensitySignal), + // Once all the plottables have been destroyed, we need to destroy the plot + // widget itself. - mass_data_integrator_task_p, + delete base_plot_composite_widget_p; - static_cast( - &MassDataIntegratorTask::integrateToTicIntensity)); + // qDebug() << "Done deleting the composite widget."; } +// Here we need to finalize the reading of the ms run data set and also chain +// with the calculation of the corresponding TIC chromatogram. void -ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToTicIntensity( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p) +ProgramWindow::finishedReadingMsRunData(MsRunDataSetSPtr ms_run_data_set_sp) { - // qDebug(); - MsRunDataSetCstSPtr ms_run_data_set_csp = - mass_data_integrator_p->getMsRunDataSet(); + // qDebug() << "Finished reading ms run data for sample name:" + //<< ms_run_data_set_sp->getMsRunId()->getSampleName(); - pappso::Trace trace = mass_data_integrator_p->getMapTrace().toTrace(); + // We are here as a slot to a signal sent by the MsRunReadTask. + + // Increment the loaded file count so that next time we'll feed it with a new + // value to the file accessor constructor (see above). + ++m_loadedFileCount; + + // Since we are load ms run data from file, we need to provide the user with + // starting points for their data exploration: a TIC chromatogram at least. - ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - // We now need to display the result into the status bar of the window. + //#if 0 + // Let's control how the data loading process went. - double tic_intensity = - static_cast( - mass_data_integrator_p) - ->getTicIntensity(); + pappso::MsRunDataSetTreeCstSPtr ms_run_data_set_tree_csp = + ms_run_data_set_sp->getMsRunDataSetTreeCstSPtr(); - emit(ticIntensityValueSignal(tic_intensity)); + const std::map &index_node_map = + ms_run_data_set_tree_csp->getIndexNodeMap(); - QString sample_name = ms_run_data_set_csp->getMsRunId()->getSampleName(); + qDebug() << "The number of spectra:" + << ms_run_data_set_tree_csp->getSpectrumCount() + << "and the data tree has this depth:" + << ms_run_data_set_tree_csp->depth() + << "and the index node map has this number of items:" + << index_node_map.size(); + //#endif - QString msg = - QString("%1: TIC intensity: %2\n").arg(sample_name).arg(tic_intensity); + // We want to try the multi-visitor approach: a single visitor that contains a + // vector of visitors. This is interesting because it makes reading the mass + // spectral data required only once. - QColor color = - mp_openMsRunDataSetsDlg->colorForMsRunDataSet(ms_run_data_set_csp); + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - logColoredTextToConsole(msg, color); + seedInitialTicChromatogramAndMsRunDataSetStatistics(ms_run_data_set_sp); - // Finally destroy the integrator! - delete mass_data_integrator_p; + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); } void -ProgramWindow::integrateFromMsRunDataSetTableViewToDtRtMz( - pappso::DataKind data_kind, - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr> - qualified_mass_spectra_vector_sp, - const ProcessingFlow &processing_flow, - [[maybe_unused]] const QColor &color) +ProgramWindow::seedInitialTicChromatogramAndMsRunDataSetStatistics( + MsRunDataSetSPtr &ms_run_data_set_sp) { - // We receive a vector of qualified mass spectrum pointers that we need to - // combine. + if(ms_run_data_set_sp == nullptr) + qFatal("Cannot be that pointer is nullptr"); + + // qDebug() << "sample name:" + //<< ms_run_data_set_sp->getMsRunId()->getSampleName(); // Let's see the usage count of the MsRunDataSetCstSPtr. // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - // qDebug() << "Number of qualified mass spectra to integrate:" - //<< qualified_mass_spectra_vector_sp->size(); - - QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz - *mass_data_integrator_p = - new QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz( - ms_run_data_set_csp, processing_flow, qualified_mass_spectra_vector_sp); - - mass_data_integrator_p->setMaxThreadUseCount(m_maxThreadUseCount); - MassDataIntegratorTask *mass_data_integrator_task_p = new MassDataIntegratorTask(); - qRegisterMetaType("pappso::DataKind"); - // This signal starts the computation in the MassDataIntegratorTask object. - connect(this, - - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToDtRtMzSignal), - - mass_data_integrator_task_p, - - static_cast(&MassDataIntegratorTask::integrateToDtRtMz), - - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // When the task finishes, it sends a signal that we trap to go on with - // the plot widget creation stuff. - connect( - mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - this, - - static_cast( - &ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToDtRtMz), - + &ProgramWindow::seedInitialTicChromatogramAndMsRunDataSetStatisticsSignal, + mass_data_integrator_task_p, + &MassDataIntegratorTask:: + seedInitialTicChromatogramAndMsRunDataSetStatistics, // Fundamental for signals that travel across QThread instances... Qt::QueuedConnection); + // When the task finishes, it sends a signal that we trap to go on with + // the plot widget creation stuff. + + connect(mass_data_integrator_task_p, + static_cast( + &MassDataIntegratorTask::finishedIntegratingDataSignal), + this, + &ProgramWindow:: + finishedSeedingInitialTicChromatogramAndMsRunDataSetStatistics, + // Fundamental for signals that travel across QThread instances... + Qt::QueuedConnection); + // Allocate the thread in which the integrator task will run. QThread *thread_p = new QThread; @@ -2214,13 +1456,9 @@ // Since we allocated the QThread dynamically we need to be able to destroy it // later, so make the connection. connect(mass_data_integrator_task_p, - - static_cast( + static_cast( &MassDataIntegratorTask::finishedIntegratingDataSignal), - this, - [thread_p, mass_data_integrator_task_p]() { // Do not forget that we have to delete the MassDataIntegratorTask // allocated instance. @@ -2231,13 +1469,23 @@ thread_p->wait(); }); + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); + + // No need to provide any processing flow object to the constructor, as we + // have none yet, this is the very first integration. + MsRunDataSetTreeMassDataIntegratorToRt *mass_data_integrator_p = + new MsRunDataSetTreeMassDataIntegratorToRt(ms_run_data_set_sp); + + // Let's see the usage count of the MsRunDataSetCstSPtr. + // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); + // Ensure the mass data integrator messages are used. - connect( - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::logTextToConsoleSignal, - this, - &ProgramWindow::logTextToConsole); + connect(mass_data_integrator_p, + &MassDataIntegrator::logTextToConsoleSignal, + this, + &ProgramWindow::logTextToConsole); // qDebug() << "the integrator pointer:" << mass_data_integrator_p; @@ -2252,9 +1500,10 @@ // connections mass data integrator <--> widget. task_monitor_composite_widget_p->setMsRunIdText( - ms_run_data_set_csp->getMsRunId()->getSampleName()); + ms_run_data_set_sp->getMsRunId()->getSampleName()); task_monitor_composite_widget_p->setTaskDescriptionText( - "Integrating to XIC chromatogram from the table view"); + "Integrating to initial TIC chromatogram and calculating MS run " + "statistics"); task_monitor_composite_widget_p->setProgressBarMinValue(0); // Make the connections @@ -2264,8 +1513,7 @@ // monitor widget. connect(mass_data_integrator_task_p, - static_cast( + static_cast( &MassDataIntegratorTask::finishedIntegratingDataSignal), task_monitor_composite_widget_p, &TaskMonitorCompositeWidget::taskFinished, @@ -2275,1077 +1523,780 @@ connect(task_monitor_composite_widget_p, &TaskMonitorCompositeWidget::cancelTaskSignal, mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::cancelOperation); + &MassDataIntegrator::cancelOperation); + + // We need to register the meta type for std::size_t because otherwise it + // cannot be shipped though signals. + + qRegisterMetaType("std::size_t"); task_monitor_composite_widget_p->makeMassDataIntegratorConnections( mass_data_integrator_p); - // qDebug() << "Emitting integrateQualifiedMassSpectrumVectorToDtRtMzSignal " - //"with data_kind" - //<< static_cast(data_kind); + // qDebug() << "going to emit integrateToInitialTicChromatogramSignal with + // mass " "data integrator:" + //<< mass_data_integrator_p; - emit integrateQualifiedMassSpectrumVectorToDtRtMzSignal( - mass_data_integrator_p, data_kind); + emit seedInitialTicChromatogramAndMsRunDataSetStatisticsSignal( + mass_data_integrator_p); // Because the emitter is the same ProgramWindow object, we need to disconnect // the signal so that at next opening of mass data file, it will not be called // twice. disconnect( this, - - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToDtRtMzSignal), - + &ProgramWindow::seedInitialTicChromatogramAndMsRunDataSetStatisticsSignal, mass_data_integrator_task_p, - - static_cast(&MassDataIntegratorTask::integrateToDtRtMz)); + &MassDataIntegratorTask:: + seedInitialTicChromatogramAndMsRunDataSetStatistics); } + void -ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToDtRtMz( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p) +ProgramWindow::finishedSeedingInitialTicChromatogramAndMsRunDataSetStatistics( + MassDataIntegrator *mass_data_integrator_p) { // qDebug(); - // At this point we need to ask the proper color map window to display the - // result of the compuation. - - MsRunDataSetCstSPtr ms_run_data_set_csp = - mass_data_integrator_p->getMsRunDataSet(); - - ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); + // In this calculation, the m_mapTrace object in the integrator is the TIC + // chroamtogram. - QColor color = - mp_openMsRunDataSetsDlg->colorForMsRunDataSet(ms_run_data_set_csp); + // The function below uses the mass_data_integrator_p to get to the TIC + // chromatogram and create the TIC chrom widget. + std::pair result_pair = + mp_ticXicChromPlotWnd->finishedIntegratingToInitialTicChromatogram( + static_cast( + mass_data_integrator_p)); - // Get a pointer to the double maptrace map that will serve as the data to - // fill-in the color map. - std::shared_ptr> double_map_trace_map_sp = - static_cast( - mass_data_integrator_p) - ->getDoubleMapTraceMapSPtr(); + // Make sure the tic chrom wnd is visible! + showTicXicChromatogramsWnd(); - // qDebug() << "rt / mz map size:" << double_map_trace_map_sp->size(); + // qDebug() << "the sample name:" + //<< result_pair.first->getMsRunId()->getSampleName(); - if(!double_map_trace_map_sp->size()) + if(result_pair.first != nullptr) { - qDebug() << "There is not a single item in the rt / mz map."; - return; - } - - // What was the kind of data handled in this integration? + // There were data in the data set ! Go on. - pappso::DataKind data_kind = - static_cast( - mass_data_integrator_p) - ->getLastIntegrationDataKind(); + mp_openMsRunDataSetsDlg->newOpenMsRunDataSet(result_pair.first, + result_pair.second); - // We need to have the specifics of the color map: the number of m/z cells, - // the minimum/maximum key value (the RT values) - // the minimum/maximum mz value. - - QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz - *qualified_mass_spectra_integrator = - static_cast( - mass_data_integrator_p); - - pappso::ColorMapPlotConfig color_map_plot_config( - data_kind, - pappso::DataKind::mz, - pappso::AxisScale::orig, - pappso::AxisScale::orig, - pappso::AxisScale::orig, - qualified_mass_spectra_integrator->getColorMapKeyCellCount(), - qualified_mass_spectra_integrator->getColorMapMzCellCount(), - qualified_mass_spectra_integrator->getColorMapMinKey(), - qualified_mass_spectra_integrator->getColorMapMaxKey(), - qualified_mass_spectra_integrator->getColorMapMinMz(), - qualified_mass_spectra_integrator->getColorMapMaxMz()); - - // qDebug() << "color_map_plot_config:" << color_map_plot_config.toString(); - - // Note that we do not support multiple color maps stacked one on top of the - // other. - - if(data_kind == pappso::DataKind::rt) - { - mp_ticXicChromMassSpecColorMapWnd->addColorMapPlot( - double_map_trace_map_sp, - color_map_plot_config, - ms_run_data_set_csp, - processing_flow, - color, - nullptr); - if(!mp_ticXicChromMassSpecColorMapWnd->isVisible()) - mp_ticXicChromMassSpecColorMapWnd->showWindow(); - } - else if(data_kind == pappso::DataKind::dt) - { - mp_driftSpecMassSpecColorMapWnd->addColorMapPlot(double_map_trace_map_sp, - color_map_plot_config, - ms_run_data_set_csp, - processing_flow, - color, - nullptr); - if(!mp_driftSpecMassSpecColorMapWnd->isVisible()) - mp_driftSpecMassSpecColorMapWnd->showWindow(); + showOpenMsRunDataSetsWnd(); } - // Finally destroy the integrator! - delete mass_data_integrator_p; -} - - -void -ProgramWindow::integrateFromMsRunDataSetTableViewToRtDt( - pappso::DataKind data_kind, - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr> - qualified_mass_spectra_vector_sp, - const ProcessingFlow &processing_flow, - [[maybe_unused]] const QColor &color) -{ - // We receive a vector of qualified mass spectrum pointers that we need to - // combine. - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_sp.use_count(); - - // qDebug() << "Number of qualified mass spectra to integrate:" - //<< qualified_mass_spectra_vector_sp->size(); - - QualifiedMassSpectrumVectorMassDataIntegratorToRtDt *mass_data_integrator_p = - new QualifiedMassSpectrumVectorMassDataIntegratorToRtDt( - ms_run_data_set_csp, processing_flow, qualified_mass_spectra_vector_sp); - - mass_data_integrator_p->setMaxThreadUseCount(m_maxThreadUseCount); - - MassDataIntegratorTask *mass_data_integrator_task_p = - new MassDataIntegratorTask(); - - qRegisterMetaType("pappso::DataKind"); - - // This signal starts the computation in the MassDataIntegratorTask object. - connect( - this, - - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToRtDtSignal), - - mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::integrateToRtDt), - - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // When the task finishes, it sends a signal that we trap to go on with - // the plot widget creation stuff. - - connect( - mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - - this, - - static_cast( - &ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToRtDt), - - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // Allocate the thread in which the integrator task will run. - QThread *thread_p = new QThread; - - // Move the task to the matching thread. - mass_data_integrator_task_p->moveToThread(thread_p); - thread_p->start(); - - // Since we allocated the QThread dynamically we need to be able to destroy it - // later, so make the connection. - connect(mass_data_integrator_task_p, - - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - - this, - - [thread_p, mass_data_integrator_task_p]() { - // Do not forget that we have to delete the MassDataIntegratorTask - // allocated instance. - mass_data_integrator_task_p->deleteLater(); - // Once the task has been labelled to be deleted later, we can stop - // the thread and ask for it to also be deleted later. - thread_p->deleteLater(), thread_p->quit(); - thread_p->wait(); - }); - - // Ensure the mass data integrator messages are used. - - connect( - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::logTextToConsoleSignal, - this, - &ProgramWindow::logTextToConsole); - - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - - // Allocate a new TaskMonitorCompositeWidget that will receive all the - // integrator's signals and provide feedback to the user about the ongoing - // integration. + // As for the statistics of the ms run data set, it has been set + // to the data set already. +} - TaskMonitorCompositeWidget *task_monitor_composite_widget_p = - mp_taskMonitorWnd->addTaskMonitorWidget(Qt::red); - // Initialize the monitor composite widget's widgets and make all the - // connections mass data integrator <--> widget. +void +ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToTicIntensity( + QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p) +{ + // qDebug(); - task_monitor_composite_widget_p->setMsRunIdText( - ms_run_data_set_csp->getMsRunId()->getSampleName()); - task_monitor_composite_widget_p->setTaskDescriptionText( - "Integrating to XIC chromatogram from the table view"); - task_monitor_composite_widget_p->setProgressBarMinValue(0); + MsRunDataSetCstSPtr ms_run_data_set_csp = + mass_data_integrator_p->getMsRunDataSet(); - // Make the connections + pappso::Trace trace = mass_data_integrator_p->getMapTrace().toTrace(); - // When the MsRunReadTask instance has finished working, it will send a signal - // that we trap to finally destroy (after a time lag of some seconds, the - // monitor widget. + ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::taskFinished, - Qt::QueuedConnection); + // We now need to display the result into the status bar of the window. - // If the user clicks the cancel button, relay the signal to the loader. - connect(task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::cancelTaskSignal, - mass_data_integrator_p, - &QualifiedMassSpectrumVectorMassDataIntegrator::cancelOperation); + double tic_intensity = + static_cast( + mass_data_integrator_p) + ->getTicIntensity(); - task_monitor_composite_widget_p->makeMassDataIntegratorConnections( - mass_data_integrator_p); + emit(ticIntensityValueSignal(tic_intensity)); - emit integrateQualifiedMassSpectrumVectorToRtDtSignal(mass_data_integrator_p, - data_kind); + QString sample_name = ms_run_data_set_csp->getMsRunId()->getSampleName(); - // Because the emitter is the same ProgramWindow object, we need to disconnect - // the signal so that at next opening of mass data file, it will not be called - // twice. - disconnect( - this, + QString msg = + QString("%1: TIC intensity: %2\n").arg(sample_name).arg(tic_intensity); - static_cast( - &ProgramWindow::integrateQualifiedMassSpectrumVectorToRtDtSignal), + QColor color = + mp_openMsRunDataSetsDlg->colorForMsRunDataSet(ms_run_data_set_csp); - mass_data_integrator_task_p, + logColoredTextToConsole(msg, color); - static_cast( - &MassDataIntegratorTask::integrateToRtDt)); + // Finally destroy the integrator! + delete mass_data_integrator_p; } void -ProgramWindow::finishedIntegratingQualifiedMassSpectrumVectorToRtDt( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p) +ProgramWindow::finishedXicIntegrationToRt( + MassDataIntegrator *mass_data_integrator_p) { // qDebug(); - // At this point we need to ask the proper color map window to display the + // At this point we need to ask the TIC XIC chromatogram window to display the // result of the compuation. MsRunDataSetCstSPtr ms_run_data_set_csp = mass_data_integrator_p->getMsRunDataSet(); + pappso::Trace trace = mass_data_integrator_p->getMapTrace().toTrace(); + ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); QColor color = mp_openMsRunDataSetsDlg->colorForMsRunDataSet(ms_run_data_set_csp); - // Get a pointer to the double maptrace map that will serve as the data to - // fill-in the color map. - std::shared_ptr> double_map_trace_map_sp = - static_cast( - mass_data_integrator_p) - ->getDoubleMapTraceMapSPtr(); + mp_ticXicChromPlotWnd->newTrace( + trace, ms_run_data_set_csp, processing_flow, color, nullptr); - // qDebug() << "rt / mz map size:" << double_map_trace_map_sp->size(); + if(!mp_ticXicChromPlotWnd->isVisible()) + mp_ticXicChromPlotWnd->showWindow(); - if(!double_map_trace_map_sp->size()) - { - qDebug() << "There is not a single item in the rt / mz map."; - return; - } + // Finally destroy the integrator! + delete mass_data_integrator_p; +} - pappso::DataKind data_kind = - static_cast( - mass_data_integrator_p) - ->getLastIntegrationDataKind(); - // We need to have the specifics of the color map: the number of m/z cells, - // the minimum/maximum key value (the RT values) - // the minimum/maximum mz value. - - QualifiedMassSpectrumVectorMassDataIntegratorToRtDt - *qualified_mass_spectra_integrator = - static_cast( - mass_data_integrator_p); - - pappso::ColorMapPlotConfig color_map_plot_config( - // Might be RT or DT - data_kind, - // Must be the other kind. - (data_kind == pappso::DataKind::rt ? pappso::DataKind::dt - : pappso::DataKind::rt), - pappso::AxisScale::orig, - pappso::AxisScale::orig, - pappso::AxisScale::orig, - qualified_mass_spectra_integrator->getColorMapKeyCellCount(), - qualified_mass_spectra_integrator->getColorMapMzCellCount(), - qualified_mass_spectra_integrator->getColorMapMinKey(), - qualified_mass_spectra_integrator->getColorMapMaxKey(), - qualified_mass_spectra_integrator->getColorMapMinMz(), - qualified_mass_spectra_integrator->getColorMapMaxMz()); - - // qDebug() << "color_map_plot_config:" << color_map_plot_config.toString(); - - // Note that we do not support multiple color maps stacked one on top of the - // other. - - mp_ticXicChromDriftSpecColorMapWnd->addColorMapPlot(double_map_trace_map_sp, - color_map_plot_config, - ms_run_data_set_csp, - processing_flow, - color, - nullptr); - if(!mp_ticXicChromDriftSpecColorMapWnd->isVisible()) - mp_ticXicChromDriftSpecColorMapWnd->showWindow(); +void +ProgramWindow::logTextToConsole(QString msg) +{ + mp_consoleWnd->logTextToConsole(msg); +} + - // Finally destroy the integrator! - delete mass_data_integrator_p; +void +ProgramWindow::logColoredTextToConsole(QString text, const QColor &color) +{ + mp_consoleWnd->logColoredTextToConsole(text, color); +} + + +QColor +ProgramWindow::getColorForMsRunDataSet( + MsRunDataSetCstSPtr ms_run_data_set_csp) const +{ + return mp_openMsRunDataSetsDlg->colorForMsRunDataSet(ms_run_data_set_csp); +} + + +QFile * +ProgramWindow::getAnalysisFilePtr() +{ + return mpa_analysisFile; +} + + +AnalysisPreferences * +ProgramWindow::getAnalysisPreferences() +{ + return mpa_analysisPreferences; } void -ProgramWindow::xicIntegrationToRt(const ProcessingFlow &processing_flow) +ProgramWindow::recordAnalysisStanza(QString stanza, const QColor &color) { - // qDebug().noquote() << "XIC integration to rt with processing flow:" - //<< processing_flow.toString(); + // Check that the user configured the analysis preferences. - // Sanity check: + if(mpa_analysisPreferences == nullptr) + return; - if(processing_flow.getMsRunDataSetCstSPtr() == nullptr) - qFatal("Cannot be that the pointer is nullptr."); + // The record might go to a file or to the console, to the clipboard... + if((mpa_analysisPreferences->m_recordTarget & RecordTarget::RECORD_TO_FILE) == + RecordTarget::RECORD_TO_FILE) + { + if(mpa_analysisFile != nullptr) + { - MsRunDataSetCstSPtr ms_run_data_set_csp = - processing_flow.getMsRunDataSetCstSPtr(); + // Write the stanza, that was crafted by the calling plot widget to + // the file. - // Pass the integrator the flow we got as param and that describes in its most - // recent step the integration that it should perform. - MsRunDataSetTreeMassDataIntegratorToRt *mass_data_integrator_p = - new MsRunDataSetTreeMassDataIntegratorToRt(ms_run_data_set_csp, - processing_flow); + if(!mpa_analysisFile->open(QIODevice::Append)) + { + statusBar()->showMessage( + QString("Could not record the step because " + "the file could not be opened."), + 4000); + } + else + { + mpa_analysisFile->write(stanza.toLatin1()); - // Ensure the mass data integrator messages are used. + // Force writing because we may want to have tail -f work fine on + // the file, and see modifications live to change fiels in a text + // editor. - connect(mass_data_integrator_p, - &MassDataIntegrator::logTextToConsoleSignal, - this, - &ProgramWindow::logTextToConsole); + mpa_analysisFile->flush(); + mpa_analysisFile->close(); + } + } + else + { + // qDebug() << "The mpa_analysisFile pointer is nullptr."; - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; + statusBar()->showMessage( + QString("Could not record the analysis step to file. " + "Please define a file to write the data to."), + 4000); + } + } - // Allocate a mass data integrator to integrate the data. + // Also, if recording to the console is asked for, then do that also. + if((mpa_analysisPreferences->m_recordTarget & + RecordTarget::RECORD_TO_CONSOLE) == RecordTarget::RECORD_TO_CONSOLE) + { + logColoredTextToConsole(stanza, color); + } - MassDataIntegratorTask *mass_data_integrator_task_p = - new MassDataIntegratorTask(); + // Also, if recording to the clipboard is asked for, then do that also. + if((mpa_analysisPreferences->m_recordTarget & + RecordTarget::RECORD_TO_CLIPBOARD) == RecordTarget::RECORD_TO_CLIPBOARD) + { + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(clipboard->text() + stanza, QClipboard::Clipboard); + } - // This signal starts the computation in the MassDataIntegratorTask object. - connect( - this, - // SIGNAL(integrateToRtSignal(MsRunDataSetTreeMassDataIntegratorToRt *)), - static_cast( - &ProgramWindow::integrateToRtSignal), - mass_data_integrator_task_p, - // SLOT(integrateToRt(MsRunDataSetTreeMassDataIntegratorToRt *)), - static_cast( - &MassDataIntegratorTask::integrateToRt), - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); + return; +} - // Allocate the thread in which the integrator task will run. - QThread *thread_p = new QThread; - // Move the task to the matching thread. - mass_data_integrator_task_p->moveToThread(thread_p); - thread_p->start(); +void +ProgramWindow::writeSettings() +{ + QSettings settings(static_cast(QCoreApplication::instance()) + ->getUserConfigSettingsFilePath(), + QSettings::IniFormat); + settings.beginGroup("ProgramWindow"); - // When the read task finishes, it sends a signal that we trap to go on with - // the plot widget creation stuff. + settings.setValue("geometry", saveGeometry()); - // Since we allocated the QThread dynamically we need to be able to destroy it - // later, so make the connection. - connect( - mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - this, - [this, thread_p, mass_data_integrator_p, mass_data_integrator_task_p]() { - // Do not forget that we have to delete the MassDataIntegratorTask - // allocated instance. - mass_data_integrator_task_p->deleteLater(); - // Once the task has been labelled to be deleted later, we can stop - // the thread and ask for it to also be deleted later. - thread_p->deleteLater(), thread_p->quit(); - thread_p->wait(); - this->finishedXicIntegrationToRt(mass_data_integrator_p); - }); + settings.endGroup(); +} - // Allocate a new TaskMonitorCompositeWidget that will receive all the - // integrator's signals and provide feedback to the user about the ongoing - // integration. +void +ProgramWindow::readSettings() +{ + QSettings settings(static_cast(QCoreApplication::instance()) + ->getUserConfigSettingsFilePath(), + QSettings::IniFormat); + settings.beginGroup("ProgramWindow"); - TaskMonitorCompositeWidget *task_monitor_composite_widget_p = - getTaskMonitorWnd()->addTaskMonitorWidget(Qt::red); + restoreGeometry(settings.value("geometry").toByteArray()); - // Initialize the monitor composite widget's widgets and make all the - // connections mass data integrator <--> widget. + settings.endGroup(); +} + + +void +ProgramWindow::initializeAllWindows() +{ + mp_openMsRunDataSetsDlg = new OpenMsRunDataSetsDlg(this); + // mp_openMsRunDataSetsDlg->show(); - task_monitor_composite_widget_p->setMsRunIdText( - ms_run_data_set_csp->getMsRunId()->getSampleName()); - task_monitor_composite_widget_p->setTaskDescriptionText( - "Integrating to XIC chromatogram."); - task_monitor_composite_widget_p->setProgressBarMinValue(0); + mp_ticXicChromPlotWnd = new TicXicChromTracePlotWnd( + this, "TIC/XIC chromatograms", "TicXicChromTracePlotWnd"); + // mp_ticXicChromPlotWnd->show(); - // Make the connections + mp_massSpecPlotWnd = + new MassSpecTracePlotWnd(this, "Mass spectra", "MassSpecTracePlotWnd"); + // mp_massSpecPlotWnd->show(); - // When the integrator task instance has finished working, it will send a - // signal that we trap to finally destroy (after a time lag of some seconds, - // the monitor widget. + mp_driftSpecPlotWnd = + new DriftSpecTracePlotWnd(this, "Drift spectra", "DriftSpecTracePlotWnd"); + // mp_driftSpecPlotWnd->show(); - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::taskFinished, - Qt::QueuedConnection); + mp_ticXicChromMassSpecColorMapWnd = + new TicXicChromMassSpecColorMapWnd(this, + "TIC/XIC chrom. / Mass spec. color maps", + "TicXicChromMassSpecColorMapWnd"); + // mp_ticXicChromMassSpecColorMapWnd->show(); - // If the user clicks the cancel button, relay the signal to the loader. - connect(task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::cancelTaskSignal, - mass_data_integrator_p, - &MassDataIntegrator::cancelOperation); + mp_ticXicChromDriftSpecColorMapWnd = new TicXicChromDriftSpecColorMapWnd( + this, + "TIC/XIC chrom. / Drift spec. color maps", + "TicXicChromDriftSpecColorMapWnd"); + // mp_ticXicChromDriftSpecColorMapWnd->show(); - // We need to register the meta type for std::size_t because otherwise it - // cannot be shipped though signals. + mp_driftSpecMassSpecColorMapWnd = + new DriftSpecMassSpecColorMapWnd(this, + "Drift spec. / Mass spec. color maps", + "DriftSpecMassSpecColorMapWnd"); + // mp_driftSpecMassSpecColorMapWnd->show(); - qRegisterMetaType("std::size_t"); + mp_xicExtractionWnd = new XicExtractionWnd( + this, "XIC chromatogram extraction", "XicExtractionWnd"); - // Now make all the connections that will allow the integrator to provide - // dynamic feedback to the user via the task monitor widget. - task_monitor_composite_widget_p->makeMassDataIntegratorConnections( - mass_data_integrator_p); + mp_taskMonitorWnd = + new TaskMonitorWnd(this, "Task monitors", "TaskMonitorWnd"); + // mp_taskMonitorWnd->show(); - // qDebug() << "going to emit integrateToRtSignal with mass " - //"data integrator:" - //<< mass_data_integrator_p; + mp_consoleWnd = new ConsoleWnd(this, m_moduleName); + // mp_consoleWnd->show(); - emit integrateToRtSignal(mass_data_integrator_p); + // NO, this one is "on demand". + // mp_isoSpecDlg = new IsoSpecDlg(this, m_moduleName); - // We do not want to make signal/slot calls more than once. This is because - // one user might well trigger more than one integration from this window to a - // mass spectrum. Thus we do not want that *this window be still connected to - // the specific mass_data_integrator_task_p when a new integration is - // triggered. We want the signal/slot pairs to be contained to specific - // objects. Each MassSpecTracePlotWnd::integrateToMz() call must be contained - // to a this/mass_data_integrator_task_p specific signal/slot pair. - disconnect( - this, - // SIGNAL(integrateToRtSignal(MsRunDataSetTreeMassDataIntegratorToRt *)), - static_cast( - &ProgramWindow::integrateToRtSignal), - mass_data_integrator_task_p, - // SLOT(integrateToRt(MsRunDataSetTreeMassDataIntegratorToRt *))); - static_cast( - &MassDataIntegratorTask::integrateToRt)); -} + // NO, this one is "on demand". + // mp_massPeakShaperDlg = new MassPeakShaperDlg(this, m_moduleName); -void -ProgramWindow::finishedXicIntegrationToRt( - MassDataIntegrator *mass_data_integrator_p) -{ - // qDebug(); + // At this point, try to check if we should remind the user to + // cite the paper. - // At this point we need to ask the TIC XIC chromatogram window to display the - // result of the compuation. + QSettings settings(static_cast(QCoreApplication::instance()) + ->getUserConfigSettingsFilePath(), + QSettings::IniFormat); - MsRunDataSetCstSPtr ms_run_data_set_csp = - mass_data_integrator_p->getMsRunDataSet(); + settings.beginGroup("Globals"); - pappso::Trace trace = mass_data_integrator_p->getMapTrace().toTrace(); + int run_count = settings.value("run_count", 0).toInt(); - ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); + ++run_count; - QColor color = - mp_openMsRunDataSetsDlg->colorForMsRunDataSet(ms_run_data_set_csp); + if(run_count == 15) + { + AboutDlg *dlg = showAboutDlg(); - mp_ticXicChromPlotWnd->newTrace( - trace, ms_run_data_set_csp, processing_flow, color, nullptr); + dlg->showHowToCiteTab(); - if(!mp_ticXicChromPlotWnd->isVisible()) - mp_ticXicChromPlotWnd->showWindow(); + settings.setValue("run_count", 0); + } + else + { + settings.setValue("run_count", run_count); + } - // Finally destroy the integrator! - delete mass_data_integrator_p; + settings.endGroup(); } + void -ProgramWindow::msRunDataSetRemovalRequested( - MsRunDataSetCstSPtr &ms_run_data_set_csp) +ProgramWindow::createMenusAndActions() { - // qDebug() << "Removal of ms run data set:" << ms_run_data_set_csp.get() - //<< "requested"; - // The user asks that a given ms run data set be removed from the software. - // We need to orderly remove all the shared pointer references so that the - // object is destroyed. Shared pointers to the ms run data set are located - // in the plottables created on the basis of the ms run data set. We need to - // remove from all the plot widgets, all the plottables that have been - // created using the ms run data set as the starting point of integrations. + // File menu + mp_fileMenu = menuBar()->addMenu("&File"); - // All the plottables are registered in the tree that mimicks the structure - // of all the plottable and plot widget in the program. + mp_openFullMsFileAct = + new QAction("Open mass spectrum file(s) fully in &memory", + dynamic_cast(this)); + mp_openFullMsFileAct->setStatusTip("Open mass data file(s) fully in memory"); + mp_openFullMsFileAct->setShortcut(QKeySequence("Ctrl+O, M")); - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); + connect(mp_openFullMsFileAct, &QAction::triggered, [this]() { + openMassSpectrometryFileDlg(m_lastUsedDirectory, true); + }); - // Find all the root nodes that match ms_run_data_set_csp non recursively. - std::vector found_nodes = - m_dataPlottableTree.findNodes(ms_run_data_set_csp, false); + mp_fileMenu->addAction(mp_openFullMsFileAct); - // qDebug() << "Found nodes:" << found_nodes.size() << "nodes:"; - // for(std::size_t iter = 0; iter < found_nodes.size(); ++iter) - // qDebug() << found_nodes.at(iter)->toString(0, true); + mp_openStreamedMsFileAct = + new QAction("Open mass spectrum file(s) in &streamed mode", + dynamic_cast(this)); + mp_openStreamedMsFileAct->setStatusTip( + "Open mass data file(s) in streamed mode"); + mp_openStreamedMsFileAct->setShortcut(QKeySequence("Ctrl+O, S")); - // Since each node has both the plot widget and the plottable pointer, we - // can ask for the recursive destruction of the plottable. + connect(mp_openStreamedMsFileAct, &QAction::triggered, [this]() { + openMassSpectrometryFileDlg(m_lastUsedDirectory, false); + }); - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); + mp_fileMenu->addAction(mp_openStreamedMsFileAct); - for(auto &&node : found_nodes) - { - // true: recursively - // false: not destroying a widget. + QAction *open_ms_file_from_clipboard_act_p = new QAction( + "Load mass spectrum from &clipboard", dynamic_cast(this)); + open_ms_file_from_clipboard_act_p->setStatusTip( + "Load a mass spectrum directly from the clipboard"); + open_ms_file_from_clipboard_act_p->setShortcut(QKeySequence("Ctrl+L, C")); - plottableDestructionRequested( - node->getPlotWidget(), node->getPlottable(), true); - } + connect(open_ms_file_from_clipboard_act_p, &QAction::triggered, [this]() { + openMassSpectrometryFileFromClipBoard(); + }); - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); + mp_fileMenu->addAction(open_ms_file_from_clipboard_act_p); - // Look for a tree view window that matches the ms - // run data set. + mp_fileMenu->addSeparator(); - std::map::iterator - res_iterator = std::find_if( - mp_msRunDataSetTableViewWndMap.begin(), - mp_msRunDataSetTableViewWndMap.end(), - [ms_run_data_set_csp]( - const std::pair item) { - return item.first == ms_run_data_set_csp; - }); + QAction *analysis_preferences_act_p = + new QAction("&Analysis preferences...", dynamic_cast(this)); + analysis_preferences_act_p->setStatusTip(tr("Set the analysis preferences")); + analysis_preferences_act_p->setShortcut(QKeySequence("Ctrl+A, P")); - if(res_iterator == mp_msRunDataSetTableViewWndMap.end()) - { - // Nothing to do, the data set had not associated tree view. - } - else - { - delete res_iterator->second; + connect(analysis_preferences_act_p, &QAction::triggered, [this]() { + openAnalysisPreferencesDlg(); + }); + mp_fileMenu->addAction(analysis_preferences_act_p); - mp_msRunDataSetTableViewWndMap.erase(ms_run_data_set_csp); - } + mp_fileMenu->addSeparator(); - // Finally remove the ms run data set item from the list widget in the - // open ms run data set dialog window. + mp_quitAct = new QAction(tr("&Quit"), dynamic_cast(this)); + mp_quitAct->setStatusTip(tr("Exit mineXpert")); + mp_quitAct->setShortcut(tr("Ctrl+Q")); - mp_openMsRunDataSetsDlg->removeMsRunDataSet(ms_run_data_set_csp); + connect(mp_quitAct, &QAction::triggered, this, &ProgramWindow::close); + mp_fileMenu->addAction(mp_quitAct); - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); -} + // Windows menu + mp_windowsMenu = menuBar()->addMenu("&Windows"); + + QAction *action_p = new QAction("Show &TIC/XIC chromatograms window", + dynamic_cast(this)); + action_p->setShortcut(QKeySequence("Ctrl+W, R")); + action_p->setStatusTip("Show the TIC/XIC chromatograms window"); + connect(action_p, + &QAction::triggered, + this, + &ProgramWindow::showTicXicChromatogramsWnd); + mp_windowsMenu->addAction(action_p); -std::vector -ProgramWindow::allSelectedOrUniqueMsRunDataSet() -{ - return mp_openMsRunDataSetsDlg->allSelectedOrUniqueMsRunDataSets(); -} + action_p = + new QAction("Show &mass spectra window", dynamic_cast(this)); + action_p->setShortcut(QKeySequence("Ctrl+W, M")); + action_p->setStatusTip("Show the mass spectra window"); + connect( + action_p, &QAction::triggered, this, &ProgramWindow::showMassSpectraWnd); + mp_windowsMenu->addAction(action_p); + + action_p = + new QAction("Show &drift spectra window", dynamic_cast(this)); + action_p->setShortcut(QKeySequence("Ctrl+W, D")); + action_p->setStatusTip("Show the drift spectra window"); + connect( + action_p, &QAction::triggered, this, &ProgramWindow::showDriftSpectraWnd); + mp_windowsMenu->addAction(action_p); -const DataPlottableTree & -ProgramWindow::getDataPlottableTree() const -{ - return m_dataPlottableTree; -} + action_p = new QAction("Show TIC/&XIC chrom. / mass spec. color maps window", + dynamic_cast(this)); + action_p->setShortcut(QKeySequence("Ctrl+W, I")); + action_p->setStatusTip( + "Show the TIC/XIC chrom. / mass spectra color maps window"); + connect(action_p, + &QAction::triggered, + this, + &ProgramWindow::showTicXicChromMassSpecColorMapWnd); + mp_windowsMenu->addAction(action_p); -void -ProgramWindow::showOpenMsRunDataSetsWnd() -{ - mp_openMsRunDataSetsDlg->activateWindow(); - mp_openMsRunDataSetsDlg->raise(); - mp_openMsRunDataSetsDlg->show(); -} + action_p = new QAction("Show TIC/XIC chrom. / drift &spec. color maps window", + dynamic_cast(this)); + action_p->setShortcut(QKeySequence("Ctrl+W, S")); + action_p->setStatusTip( + "Show the TIC/XIC chrom. / drift spectra color maps window"); + connect(action_p, + &QAction::triggered, + this, + &ProgramWindow::showTicXicChromDriftSpecColorMapWnd); + mp_windowsMenu->addAction(action_p); -const OpenMsRunDataSetsDlg * -ProgramWindow::getOpenMsRunDataSetsDlg() const -{ - return mp_openMsRunDataSetsDlg; -} + action_p = new QAction("Show drift s&pec. / mass spec. color maps window", + dynamic_cast(this)); + action_p->setShortcut(QKeySequence("Ctrl+W, P")); + action_p->setStatusTip( + "Show the drift spectra / mass spectra color maps window"); + connect(action_p, + &QAction::triggered, + this, + &ProgramWindow::showDriftSpecMassSpecColorMapWnd); + mp_windowsMenu->addAction(action_p); -void -ProgramWindow::showTicXicChromatogramsWnd() -{ - mp_ticXicChromPlotWnd->showWindow(); -} + action_p = + new QAction("Show tas&k monitor window", dynamic_cast(this)); + action_p->setShortcut(QKeySequence("Ctrl+W, T")); + action_p->setStatusTip("Show the task monitor window"); + connect( + action_p, &QAction::triggered, this, &ProgramWindow::showTaskMonitorWnd); + mp_windowsMenu->addAction(action_p); -void -ProgramWindow::showMassSpectraWnd() -{ - mp_massSpecPlotWnd->showWindow(); -} + action_p = new QAction("Show open ms r&un data sets window", + dynamic_cast(this)); + action_p->setShortcut(QKeySequence("Ctrl+W, O")); + action_p->setStatusTip("Show the open MS run data sets window"); + connect(action_p, + &QAction::triggered, + this, + &ProgramWindow::showOpenMsRunDataSetsWnd); -void -ProgramWindow::showDriftSpectraWnd() -{ - mp_driftSpecPlotWnd->showWindow(); -} + mp_windowsMenu->addAction(action_p); -void -ProgramWindow::showTicXicChromMassSpecColorMapWnd() -{ - mp_ticXicChromMassSpecColorMapWnd->showWindow(); -} + action_p = new QAction("Show &console window", dynamic_cast(this)); + action_p->setShortcut(QKeySequence("Ctrl+W, C")); + action_p->setStatusTip("Show the console window"); + connect(action_p, &QAction::triggered, this, &ProgramWindow::showConsoleWnd); + mp_windowsMenu->addAction(action_p); -void -ProgramWindow::showTicXicChromDriftSpecColorMapWnd() -{ - mp_ticXicChromDriftSpecColorMapWnd->showWindow(); -} + mp_windowsMenu->addSeparator(); + action_p = new QAction("Save &workspace", dynamic_cast(this)); + action_p->setStatusTip("Save the current layout of the workspace"); + connect(action_p, &QAction::triggered, this, &ProgramWindow::saveWorkspace); -void -ProgramWindow::showDriftSpecMassSpecColorMapWnd() -{ - mp_driftSpecMassSpecColorMapWnd->showWindow(); -} + mp_windowsMenu->addAction(action_p); -void -ProgramWindow::showXicExtractionWnd() -{ + // Utilities menu + mp_utilitiesMenu = menuBar()->addMenu("&Utilities"); - mp_xicExtractionWnd->showWindow(); -} + action_p = + new QAction("XIC chromatogram &extractions", dynamic_cast(this)); + action_p->setStatusTip("Open the XIC chromatogram extraction functionality"); + action_p->setShortcut(tr("Ctrl+X, E")); + connect( + action_p, &QAction::triggered, this, &ProgramWindow::showXicExtractionWnd); -void -ProgramWindow::showIsoSpecDlg() -{ - mp_isoSpecDlg = new IsoSpecDlg(this, m_moduleName); + mp_utilitiesMenu->addAction(action_p); - mp_isoSpecDlg->activateWindow(); - mp_isoSpecDlg->raise(); - mp_isoSpecDlg->show(); -} + action_p = new QAction("&Isotopic cluster calculations", + dynamic_cast(this)); + action_p->setStatusTip("Open the isotopic cluster calculation functionality"); + action_p->setShortcut(QKeySequence("Ctrl+I, C")); + connect(action_p, &QAction::triggered, this, &ProgramWindow::showIsoSpecDlg); -void -ProgramWindow::showMassPeakShaperDlg() -{ - mp_massPeakShaperDlg = new MassPeakShaperDlg(this, m_moduleName); + mp_utilitiesMenu->addAction(action_p); - mp_massPeakShaperDlg->activateWindow(); - mp_massPeakShaperDlg->raise(); - mp_massPeakShaperDlg->show(); -} + action_p = + new QAction("Mass peak &shape calculations", dynamic_cast(this)); + action_p->setStatusTip("Open the mass peak shape calculation functionality"); + action_p->setShortcut(QKeySequence("Ctrl+M, S")); + connect( + action_p, &QAction::triggered, this, &ProgramWindow::showMassPeakShaperDlg); -void -ProgramWindow::showTaskMonitorWnd() -{ - mp_taskMonitorWnd->activateWindow(); - mp_taskMonitorWnd->raise(); - mp_taskMonitorWnd->show(); -} + mp_utilitiesMenu->addAction(action_p); -void -ProgramWindow::showConsoleWnd() -{ - mp_consoleWnd->activateWindow(); - mp_consoleWnd->raise(); - mp_consoleWnd->show(); -} + // Preferences menu + mp_preferencesMenu = menuBar()->addMenu("&Preferences"); + action_p = + new QAction("Set max. thread count", dynamic_cast(this)); + action_p->setStatusTip( + "Set the maximum number of threads to be used for the integrations"); + action_p->setShortcut(tr("Ctrl+P, T")); -void -ProgramWindow::saveWorkspace() -{ - mp_openMsRunDataSetsDlg->writeSettings(); - mp_taskMonitorWnd->writeSettings(); - mp_consoleWnd->writeSettings(); + connect(action_p, &QAction::triggered, [this]() { + std::size_t ideal_thread_count = QThread::idealThreadCount(); - mp_ticXicChromPlotWnd->writeSettings(); - mp_massSpecPlotWnd->writeSettings(); - mp_driftSpecPlotWnd->writeSettings(); - mp_ticXicChromMassSpecColorMapWnd->writeSettings(); - mp_ticXicChromDriftSpecColorMapWnd->writeSettings(); - mp_driftSpecMassSpecColorMapWnd->writeSettings(); + m_maxThreadUseCount = QInputDialog::getInt(this, + "Set max. thread count", + "Count", + ideal_thread_count, + 1, + ideal_thread_count, + 1); - mp_xicExtractionWnd->writeSettings(); -} + // qDebug() << "Set the max. thread use count to : " << m_maxThreadUseCount; + }); + mp_preferencesMenu->addAction(action_p); -void -ProgramWindow::logTextToConsole(QString msg) -{ - mp_consoleWnd->logTextToConsole(msg); -} + // Help menu + mp_helpMenu = menuBar()->addMenu("&Help"); -void -ProgramWindow::logColoredTextToConsole(QString text, const QColor &color) -{ - mp_consoleWnd->logColoredTextToConsole(text, color); -} + action_p = new QAction(QIcon(":/images/svg/help-information-icon.svg"), + tr("&About"), + dynamic_cast(this)); + action_p->setStatusTip(tr("Show the &application's About box")); + action_p->setShortcut(QKeySequence("Ctrl+H, A")); + connect(action_p, &QAction::triggered, this, &ProgramWindow::showAboutDlg); + mp_helpMenu->addAction(action_p); -QColor -ProgramWindow::getColorForMsRunDataSet( - MsRunDataSetCstSPtr ms_run_data_set_csp) const -{ - return mp_openMsRunDataSetsDlg->colorForMsRunDataSet(ms_run_data_set_csp); + action_p = + new QAction(QIcon(":/images/svg/help-qt-information-icon.svg"), + tr("About &Qt"), + dynamic_cast(this)); + action_p->setStatusTip(tr("Show the Qt &library's About box")); + connect(action_p, &QAction::triggered, this, &Application::aboutQt); + action_p->setShortcut(QKeySequence("Ctrl+H, Q")); + + mp_helpMenu->addAction(action_p); } -//! Handler of the close event signal. void -ProgramWindow::closeEvent(QCloseEvent *event) +ProgramWindow::setupWindow() { - writeSettings(); - event->accept(); -} + // qDebug(); + QPixmap pixmap(":/images/icons/32x32/minexpert2.png"); + QIcon icon(pixmap); + setWindowIcon(icon); -int -ProgramWindow::selectMsRun(std::vector &ms_run_ids) -{ - MsRunSelectorDlg *dlg = new MsRunSelectorDlg(this, ms_run_ids, m_moduleName); + // This attribute make sure that the main window of the program is destroyed + // when it is closed. Effectively stopping the program. + setAttribute(Qt::WA_DeleteOnClose); + + statusBar()->setSizeGripEnabled(true); - return dlg->exec(); + createMenusAndActions(); + initializeAllWindows(); + readSettings(); } -BaseTracePlotWnd * -ProgramWindow::getPlotWndPtr(const QString &type_name) -{ - if(type_name != "mass spectrum" && type_name != "tic xic chromatogram" && - type_name != "drift spectrum") - qFatal("Error with the plot window type name."); - - if(type_name == "mass spectrum") - return mp_massSpecPlotWnd; - else if(type_name == "tic xic chromatogram") - return mp_ticXicChromPlotWnd; - else if(type_name == "drift spectrum") - return mp_driftSpecPlotWnd; - - qFatal("Should never encounter this point."); +int +ProgramWindow::selectMsRun(std::vector &ms_run_ids) +{ + MsRunSelectorDlg *dlg = new MsRunSelectorDlg(this, ms_run_ids, m_moduleName); - return nullptr; + return dlg->exec(); } -void -ProgramWindow::integrateToRt( - QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow) +AboutDlg * +ProgramWindow::showAboutDlg() { - // Each trace plot window handles the integration requests that produce - // their own type of data, so we delegate the integration to the - // relevant window. + // The application name will be set automatically by default parameter + // value. + AboutDlg *dlg = new AboutDlg(this, m_moduleName); - // qDebug().noquote() << "Integrating to rt with processing flow:" - //<< processing_flow.toString(); + dlg->show(); - mp_ticXicChromPlotWnd->integrateToRt( - parent_plottable_p, qualified_mass_spectra_sp, processing_flow); + return dlg; } void -ProgramWindow::integrateToMz( - QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow) +ProgramWindow::showOpenMsRunDataSetsWnd() { - // Each trace plot window handles the integration requests that produce - // their own type of data, so we delegate the integration to the - // relevant window. + mp_openMsRunDataSetsDlg->activateWindow(); + mp_openMsRunDataSetsDlg->raise(); + mp_openMsRunDataSetsDlg->show(); +} - // qDebug().noquote() << "Integrating to mz with processing flow:" - //<< processing_flow.toString(); - mp_massSpecPlotWnd->integrateToMz( - parent_plottable_p, qualified_mass_spectra_sp, processing_flow); +const OpenMsRunDataSetsDlg * +ProgramWindow::getOpenMsRunDataSetsDlg() const +{ + return mp_openMsRunDataSetsDlg; } void -ProgramWindow::integrateToDt( - QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow) +ProgramWindow::showTicXicChromatogramsWnd() { - // Each trace plot window handles the integration requests that produce - // their own type of data, so we delegate the integration to the - // relevant window. - - mp_driftSpecPlotWnd->integrateToDt( - parent_plottable_p, qualified_mass_spectra_sp, processing_flow); + mp_ticXicChromPlotWnd->showWindow(); } void -ProgramWindow::integrateToDtMz( - QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow) +ProgramWindow::showMassSpectraWnd() { - mp_driftSpecMassSpecColorMapWnd->integrateToDtMz( - parent_plottable_p, qualified_mass_spectra_sp, processing_flow); + mp_massSpecPlotWnd->showWindow(); } void -ProgramWindow::integrateToRtMz( - QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow) +ProgramWindow::showDriftSpectraWnd() { - mp_ticXicChromMassSpecColorMapWnd->integrateToRtMz( - parent_plottable_p, qualified_mass_spectra_sp, processing_flow); + mp_driftSpecPlotWnd->showWindow(); } void -ProgramWindow::integrateToRtDt( - QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow) +ProgramWindow::showTicXicChromMassSpecColorMapWnd() { - mp_ticXicChromDriftSpecColorMapWnd->integrateToRtDt( - parent_plottable_p, qualified_mass_spectra_sp, processing_flow); + mp_ticXicChromMassSpecColorMapWnd->showWindow(); } -const BasePlotCompositeWidget * -ProgramWindow::getPlotWidget( - [[maybe_unused]] MsRunDataSetCstSPtr ms_run_data_set_csp, - QCPAbstractPlottable *plottable_p) +void +ProgramWindow::showTicXicChromDriftSpecColorMapWnd() { - return m_dataPlottableTree.getPlotWidget(plottable_p); + mp_ticXicChromDriftSpecColorMapWnd->showWindow(); } void -ProgramWindow::documentMsRunDataPlottableFiliation( - MsRunDataSetCstSPtr ms_run_data_set_csp, - QCPAbstractPlottable *new_plottable_p, - QCPAbstractPlottable *parent_plottable_p, - BasePlotCompositeWidget *plot_widget_p) +ProgramWindow::showDriftSpecMassSpecColorMapWnd() { - // qDebug(); - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); - - // Now we need to document the filiation of the parent / child - // plottable. - - // qDebug() << "Before documenting: data plottable tree has" - //<< m_dataPlottableTree.depth() << "depth and" - //<< m_dataPlottableTree.size() << "size"; - - m_dataPlottableTree.addPlottable( - ms_run_data_set_csp, new_plottable_p, parent_plottable_p, plot_widget_p); - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); - - // qDebug() << "After documenting data plot plottable tree has" - //<< m_dataPlottableTree.depth() << "depth and" - //<< m_dataPlottableTree.size() << "size"; + mp_driftSpecMassSpecColorMapWnd->showWindow(); } void -ProgramWindow::plottableDestructionRequested( - BasePlotCompositeWidget *base_plot_composite_widget_p, - QCPAbstractPlottable *plottable_p, - bool recursively) +ProgramWindow::showXicExtractionWnd() { - // qDebug().noquote() << "Destruction of plottable:" - //<< pappso::Utils::pointerToString(plottable_p) - //<< "is being requested recursively:" << recursively; - - MsRunDataSetCstSPtr ms_run_data_set_csp = - base_plot_composite_widget_p->getMsRunDataSetCstSPtrForPlottable( - plottable_p); - - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); - - // When one plottable is on the verge of being deleted, we need to first - // check its node in the plottable data tree. This is because we need to - // at least remove that node ! - - // Further, there is another fact to keep in mind: if the user wanted to - // remove all the children plottable, then we would need to do that. - - // Another complexity: if the plottable that is removed had children, - // but the user does not want to remove them, we would need to reparent - // them to the parent of the plottable being deleted ! - - // How many children did that plottable have? - - // qDebug() << "Getting the right node for the plottable to be destroyed."; - - DataPlottableNode *plottable_node_p = - m_dataPlottableTree.findNode(plottable_p); - - if(plottable_node_p == nullptr) - qFatal( - "Could not find a node for plottable . This is a programming " - "error."); - - // qDebug() << "The plottable is in node:" - //<< plottable_node_p->toString(0, true); - std::size_t descendant_count = 0; - plottable_node_p->size(descendant_count); - - // qDebug() << "The plottable node has" << descendant_count << - // "descendants"; + mp_xicExtractionWnd->showWindow(); +} - // bool res = - m_dataPlottableTree.removeNodeAndPlottable(plottable_node_p, recursively); - // qDebug() << "Removal of node(s) and plottable(s) is success:" << res; +void +ProgramWindow::showIsoSpecDlg() +{ + mp_isoSpecDlg = new IsoSpecDlg(this, m_moduleName); - // Let's see the usage count of the MsRunDataSetCstSPtr. - // qDebug() << "Usage count:" << ms_run_data_set_csp.use_count(); + mp_isoSpecDlg->activateWindow(); + mp_isoSpecDlg->raise(); + mp_isoSpecDlg->show(); } void -ProgramWindow::plottableDestructionRequested( - BasePlotCompositeWidget *base_plot_composite_widget_p, - QCPAbstractPlottable *plottable_p, - const pappso::BasePlotContext &context) +ProgramWindow::showMassPeakShaperDlg() { - bool recursively = context.keyboardModifiers & Qt::ControlModifier; - - // If a recursive plottable destruction is requested, the the plottable - // and all its children, as documented by the main program's plottable - // tree nodes are to be destroyed. - - // if(recursively) - // qDebug() << "Destruction recursive of plottable:" << plottable_p - //<< "is being requested."; - // else - // qDebug() << "Destruction of plottable:" << plottable_p - //<< "is being requested."; + mp_massPeakShaperDlg = new MassPeakShaperDlg(this, m_moduleName); - return plottableDestructionRequested( - base_plot_composite_widget_p, plottable_p, recursively); + mp_massPeakShaperDlg->activateWindow(); + mp_massPeakShaperDlg->raise(); + mp_massPeakShaperDlg->show(); } void -ProgramWindow::plotCompositeWidgetDestructionRequested( - BasePlotCompositeWidget *base_plot_composite_widget_p) +ProgramWindow::showTaskMonitorWnd() { - // qDebug() << "Handling the destruction of the plot widget:" - //<< base_plot_composite_widget_p; - - // One plot widget and all the plottables that it contains need to be - // destroyed. We first need to get a list of all the data plot tree nodes - // that match the plot widget. Then we non-recursively destroy all the - // plottables and matching data tree nodes. Finally we destroy the widget. + mp_taskMonitorWnd->activateWindow(); + mp_taskMonitorWnd->raise(); + mp_taskMonitorWnd->show(); +} - std::vector plottable_nodes = - m_dataPlottableTree.findNodes(base_plot_composite_widget_p, true); - // qDebug() << "The number of nodes for plot widget:" - //<< base_plot_composite_widget_p << "is:" << plottable_nodes.size(); +void +ProgramWindow::showConsoleWnd() +{ + mp_consoleWnd->activateWindow(); + mp_consoleWnd->raise(); + mp_consoleWnd->show(); +} - // We want an orderly destruction of the plottable(s). - for(auto &&node_p : plottable_nodes) - { +void +ProgramWindow::saveWorkspace() +{ + mp_openMsRunDataSetsDlg->writeSettings(); + mp_taskMonitorWnd->writeSettings(); + mp_consoleWnd->writeSettings(); - plottableDestructionRequested( - base_plot_composite_widget_p, node_p->getPlottable(), false); - } + mp_ticXicChromPlotWnd->writeSettings(); + mp_massSpecPlotWnd->writeSettings(); + mp_driftSpecPlotWnd->writeSettings(); + mp_ticXicChromMassSpecColorMapWnd->writeSettings(); + mp_ticXicChromDriftSpecColorMapWnd->writeSettings(); + mp_driftSpecMassSpecColorMapWnd->writeSettings(); - // Once all the plottables have been destroyed, we need to destroy the plot - // widget itself. + mp_xicExtractionWnd->writeSettings(); +} - delete base_plot_composite_widget_p; - // qDebug() << "Done deleting the composite widget."; +//! Handler of the close event signal. +void +ProgramWindow::closeEvent(QCloseEvent *event) +{ + writeSettings(); + event->accept(); } diff -Nru minexpert2-7.4.1/src/gui/ProgramWindow.hpp minexpert2-8.1.1/src/gui/ProgramWindow.hpp --- minexpert2-7.4.1/src/gui/ProgramWindow.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ProgramWindow.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -152,95 +152,47 @@ void seedInitialTicChromatogramAndMsRunDataSetStatistics( MsRunDataSetSPtr &ms_run_data_set_sp); - void integrateToRt( + using QualifiedMassSpectraVector = + std::vector; + + // To trace integrations + void integrateToDt( QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, + std::shared_ptr qualified_mass_spectra_sp, const ProcessingFlow &processing_flow); void integrateToMz( QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, + std::shared_ptr qualified_mass_spectra_sp, const ProcessingFlow &processing_flow); - void integrateToDt( + void integrateToRt( QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, + std::shared_ptr qualified_mass_spectra_sp, const ProcessingFlow &processing_flow); + // To TIC intensity integration void integrateToTicIntensity( QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, + std::shared_ptr qualified_mass_spectra_sp, const ProcessingFlow &processing_flow); + // To color map integrations void integrateToDtMz( QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, + std::shared_ptr qualified_mass_spectra_sp, const ProcessingFlow &processing_flow); - void integrateToRtMz( + void integrateToDtRt( QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, + std::shared_ptr qualified_mass_spectra_sp, const ProcessingFlow &processing_flow); - void integrateToRtDt( + void integrateToMzRt( QCPAbstractPlottable *parent_plottable_p, - std::shared_ptr> - qualified_mass_spectra_sp, + std::shared_ptr qualified_mass_spectra_sp, const ProcessingFlow &processing_flow); - using QualifiedMassSpectraVector = - std::vector; - - void integrateFromMsRunDataSetTableViewToRt( - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr - vector_of_qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow, - const QColor &color); - - void integrateFromMsRunDataSetTableViewToDt( - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr - vector_of_qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow, - const QColor &color); - - void integrateFromMsRunDataSetTableViewToMz( - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr> - qualified_mass_spectra_vector_sp, - const ProcessingFlow &processing_flow, - const QColor &color); - - void integrateFromMsRunDataSetTableViewToTicIntensity( - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr - vector_of_qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow, - const QColor &color); - - void integrateFromMsRunDataSetTableViewToDtRtMz( - pappso::DataKind data_kind, - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr - vector_of_qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow, - const QColor &color); - - void integrateFromMsRunDataSetTableViewToRtDt( - pappso::DataKind data_kind, - MsRunDataSetCstSPtr ms_run_data_set_csp, - std::shared_ptr - vector_of_qualified_mass_spectra_sp, - const ProcessingFlow &processing_flow, - const QColor &color); - void xicIntegrationToRt(const ProcessingFlow &processing_flow); void displayMassSpectralTrace(pappso::Trace trace, @@ -277,31 +229,21 @@ void finishedSeedingInitialTicChromatogramAndMsRunDataSetStatistics( MassDataIntegrator *mass_data_integrator_p); - void finishedXicIntegrationToRt(MassDataIntegrator *mass_data_integrator_p); - - void finishedIntegratingQualifiedMassSpectrumVectorToRt( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p); - - void finishedIntegratingQualifiedMassSpectrumVectorToDt( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p); - - void finishedIntegratingQualifiedMassSpectrumVectorToMz( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p); - void finishedIntegratingQualifiedMassSpectrumVectorToTicIntensity( QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p); - void finishedIntegratingQualifiedMassSpectrumVectorToDtRtMz( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p); - - void finishedIntegratingQualifiedMassSpectrumVectorToRtDt( - QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p); + void finishedXicIntegrationToRt(MassDataIntegrator *mass_data_integrator_p); void logTextToConsole(QString msg); void logColoredTextToConsole(QString text, const QColor &color); QColor getColorForMsRunDataSet(MsRunDataSetCstSPtr ms_run_data_set_csp) const; + QFile *getAnalysisFilePtr(); + AnalysisPreferences *getAnalysisPreferences(); + + void recordAnalysisStanza(QString stanza, const QColor &color = Qt::black); + signals: void readMsRunDataSignal(MsRunReadTask *ms_run_read_task_p, @@ -328,13 +270,12 @@ *mass_data_integrator_p); void integrateQualifiedMassSpectrumVectorToRtDtSignal( - QualifiedMassSpectrumVectorMassDataIntegratorToRtDt *mass_data_integrator_p, - pappso::DataKind data_kind); + QualifiedMassSpectrumVectorMassDataIntegratorToRtDt + *mass_data_integrator_p); void integrateQualifiedMassSpectrumVectorToDtRtMzSignal( QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz - *mass_data_integrator_p, - pappso::DataKind data_kind); + *mass_data_integrator_p); void ticIntensityValueSignal(double tic_intensity); @@ -385,14 +326,10 @@ IsoSpecDlg *mp_isoSpecDlg = nullptr; AnalysisPreferences *mpa_analysisPreferences = nullptr; - AnalysisPreferences *getAnalysisPreferences(); AnalysisPreferencesDlg *mp_analysisPreferencesDlg = nullptr; QFile *mpa_analysisFile = nullptr; - QFile *getAnalysisFilePtr(); - - void recordAnalysisStanza(QString stanza, const QColor &color = Qt::black); AboutDlg *mp_aboutDlg = nullptr; @@ -404,7 +341,7 @@ QMenu *mp_fileMenu = nullptr; QMenu *mp_windowsMenu = nullptr; QMenu *mp_utilitiesMenu = nullptr; - QMenu *mp_preferencesMenu = nullptr; + QMenu *mp_preferencesMenu = nullptr; QMenu *mp_helpMenu = nullptr; QAction *mp_openFullMsFileAct = nullptr; QAction *mp_openStreamedMsFileAct = nullptr; diff -Nru minexpert2-7.4.1/src/gui/TicXicChromDriftSpecColorMapPlotCompositeWidget.cpp minexpert2-8.1.1/src/gui/TicXicChromDriftSpecColorMapPlotCompositeWidget.cpp --- minexpert2-7.4.1/src/gui/TicXicChromDriftSpecColorMapPlotCompositeWidget.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/TicXicChromDriftSpecColorMapPlotCompositeWidget.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -179,36 +179,53 @@ TicXicChromDriftSpecColorMapPlotCompositeWidget::integrationRequested( const pappso::BasePlotContext &context) { - // qDebug().noquote() << "context:" << context.toString(); + //qDebug().noquote() << "context:" << context.toString(); // We are getting that signal from a plot widget that operates as a - // tic xic chrom / mass spec color map plot widget. + // tic xic chrom / mass spec color map plot widget. By essence, the selected + // region needs to be two-dimensional, so the selection polygon needs to be + // so. + + // Check if the selection polygon contain meaninful data. We are in a colormap + // plot widget, so the selection polygon cannot be in the form of a + // mono-dimensional polygon. + + if(!context.m_selectionPolygon.is2D()) + { + qDebug() << "The selection polygon cannot be mono-dimensional when " + "selecting for integration from a color map"; + return; + } + else + { + if(context.m_selectionPolygon.isRectangle()) + qDebug() << "The selection polygon is rectangle."; + else + qDebug() << "The selection polygon is oblique (skewed)."; + } + + // Sanity check. // Immediately check if the selection range makes sense. For example, having // both the start/end values in the negative values does not mean anything // with respect to tic|xic chrom vs mass spectrum data! - // Remember that the xregion start and end are not sorted. - double x_range_start = - std::min(context.xRegionRangeStart, context.xRegionRangeEnd); - double x_range_end = - std::max(context.xRegionRangeStart, context.xRegionRangeEnd); + double x_range_start; + double x_range_end; + + context.m_selectionPolygon.rangeX(x_range_start, x_range_end); if(x_range_start < 0 && x_range_end < 0) return; - qDebug() << "x_range:" << x_range_start << "-" << x_range_end; + double y_range_start; + double y_range_end; - double y_range_start = - std::min(context.yRegionRangeStart, context.yRegionRangeEnd); - double y_range_end = - std::max(context.yRegionRangeStart, context.yRegionRangeEnd); + context.m_selectionPolygon.rangeY(y_range_start, y_range_end); if(y_range_start < 0 && y_range_end < 0) return; - qDebug() << "y_range:" << y_range_start << "-" << y_range_end; - // We need check which destination button is currently checked. // The widget does not handle the integrations. There are the @@ -222,7 +239,6 @@ // selected is the right one. If there are more than one traces selected, then // we cannot do anything. Display an error message. - // The QCustomPlot-based widget might contain more than one graph, and we // need to know on what graph the user is willing to perform the // integration. @@ -241,39 +257,24 @@ return; } - // Create a local copy of the processing flow. + // Create a local copy of the processing flow so that we can modify it by + // adding the new processing step that describes what we are doing now. ProcessingFlow local_processing_flow = getProcessingFlowForPlottable(plottable_p); - // qDebug().noquote() << "Processing flow for graph:" - //<< local_processing_flow.toString(); + //qDebug().noquote() << "Processing flow for graph:" + //<< local_processing_flow.toString(); MsRunDataSetCstSPtr ms_run_data_set_csp = getMsRunDataSetCstSPtrForPlottable(plottable_p); // qDebug() << ms_run_data_set_csp->getMsRunDataSetStats().toString(); - // Now we need to add a new step in that processing flow so that we document - // this new integration that we are performing. + // Create a processing step to document the specifics of this new integration. ProcessingStep *processing_step_p = new ProcessingStep(); - // The step has a multi-map of pairs that each relate a processing type with a - // processing spec. So we need to document a new pair type/spec, let's start - // with the spec that documents the range of the data we are willing to - // integrate, that is, the selected region of the graph. - - // The ProcessingSpec has the range start/end values, an optional ms - // fragmentation specification and a date time that is set automatically at - // construction time. - - // Allocate a new spec that will hold the RT dimension range. - ProcessingSpec *rt_processing_spec_p = new ProcessingSpec(); - - // And another one for the DT dimension range. - ProcessingSpec *dt_processing_spec_p = new ProcessingSpec(); - // If the user had set ms fragmentation specifications, all these are listed // in the various ProcessingSpec instances, so we do not loose any. However, // the user is entitled to define any new ms fragmentation specifications @@ -291,113 +292,132 @@ // flow " "is valid, using it:" //<< ms_fragmentation_spec.toString(); - // Any processing spec should do. - rt_processing_spec_p->setMsFragmentationSpec(ms_fragmentation_spec); + processing_step_p->setMsFragmentationSpec(ms_fragmentation_spec); } else { // qDebug() << "The default ms frag spec from the processing flow is not " //"valid. Not using it."; } - // Now define the graph ranges for the integration operation. - // Remember that the region start and end are not sorted. Also, the colormap - // can have its axes transposed, so we need to ensure that we use the proper - // axis for mz and the proper axis for the other dimension (rt or dt). + // Now define which selection polygon sides have which data kind. - if(static_cast(mp_plotWidget) - ->xAxisDataKind() == pappso::DataKind::rt) - { - rt_processing_spec_p->setRange(x_range_start, x_range_end); - dt_processing_spec_p->setRange(y_range_start, y_range_end); + // Sanity check. - qDebug() << "x axis data kind is rt:" - << "RT range:" << x_range_start << "-" << x_range_end - << "DT range:" << y_range_start << "-" << y_range_end; + pappso::DataKind x_axis_data_kind = + static_cast(mp_plotWidget) + ->xAxisDataKind(); + pappso::DataKind y_axis_data_kind = + static_cast(mp_plotWidget) + ->yAxisDataKind(); + + if(x_axis_data_kind == pappso::DataKind::dt) + qDebug() << "X axis: dt"; + else if(x_axis_data_kind == pappso::DataKind::rt) + qDebug() << "X axis: rt"; + + if(x_axis_data_kind == pappso::DataKind::dt && + y_axis_data_kind != pappso::DataKind::rt) + { + qFatal("Programming error."); } - else if(static_cast(mp_plotWidget) - ->xAxisDataKind() == pappso::DataKind::dt) + else if(x_axis_data_kind == pappso::DataKind::rt && + y_axis_data_kind != pappso::DataKind::dt) + { + qFatal("Programming error."); + } + + // The colormap can have its axes transposed, so we need to ensure that we + // document the axis/data-kind relation properly. Note that we want the + // processing step to be documented according to the alpha numerical ordering. + // So, if we are working in a DT_RT colormap, then, x axis needs to be DT and + // y axis needs to be RT. + // Make a local copy of the selection polygon because we might need to + // transpose it. + + pappso::SelectionPolygon local_selection_polygon = context.m_selectionPolygon; + + //qDebug() << "The selection polygon:" << local_selection_polygon.toString(); + + if(x_axis_data_kind == pappso::DataKind::rt) { - rt_processing_spec_p->setRange(y_range_start, y_range_end); - dt_processing_spec_p->setRange(x_range_start, x_range_end); + // qDebug() + //<< "The selection polygon has x:rt, transposing the selection polygon."; - qDebug() << "x axis data kind is mz:" - << "RT range:" << y_range_start << "-" << y_range_end - << "DT range:" << x_range_start << "-" << x_range_end; + // We have to transpose the selection rectangle so that x:DT and y:RT. + local_selection_polygon = local_selection_polygon.transpose(); + + // qDebug() << "After transposition, the selection polygon:" + //<< local_selection_polygon.toString(); } - else - qFatal("Programming error."); + // else + // No need to tranpose, we deal with data in the right x:DT y:RT. + + // Now we know we have the right selection polygon for x:DT and y:RT. + + processing_step_p->setDataKind(pappso::Axis::x, pappso::DataKind::dt); + processing_step_p->setDataKind(pappso::Axis::y, pappso::DataKind::rt); + + + // And now actually set the selection polygon to the step. + + processing_step_p->setSelectionPolygon(local_selection_polygon); + + // qDebug() << "Selection polygon as set to the step:" + //<< processing_step_p->getSelectionPolygon().toString(); + + // We must say what is the data source processing type. + processing_step_p->setSrcProcessingType(pappso::Axis::x, "DT"); + processing_step_p->setSrcProcessingType(pappso::Axis::y, "RT"); + + // Now we need to document not the source but the destination. What kind of + // integration are we about to perform? if(m_ui.integrateToRtPushButton->isChecked()) { - // qDebug() << "Integration to XIC chromatogram."; + qDebug() << "Integrating to XIC chromatogram."; - // We need to set two specs to the step. - - processing_step_p->newSpec(ProcessingType("RT_DT_RT_TO_RT"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_DT_DT_TO_RT"), - dt_processing_spec_p); + processing_step_p->setDestProcessingType("RT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) ->integrateToRt(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtDtPushButton->isChecked()) + else if(m_ui.integrateToDtRtPushButton->isChecked()) { - qDebug() << "Integrating to rt / dt color map."; - - // We need to set two specs to the step. + qDebug() << "Integrating to dt / rt color map."; - processing_step_p->newSpec(ProcessingType("RT_DT_RT_TO_RT_DT"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_DT_DT_TO_RT_DT"), - dt_processing_spec_p); + processing_step_p->setDestProcessingType("DT_RT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) - ->integrateToRtDt(plottable_p, local_processing_flow); + ->integrateToDtRt(plottable_p, local_processing_flow); } // Handle all the integrations to MZ in one place else if(m_ui.integrateToMzPushButton->isChecked() || m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { if(m_ui.integrateToMzPushButton->isChecked()) { - qDebug() << "Integrating to mass spectrum."; + qDebug() << "Integrating to mass spectrum."; - // We need to set two specs to the step. - - processing_step_p->newSpec(ProcessingType("RT_DT_RT_TO_MZ"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_DT_DT_TO_MZ"), - dt_processing_spec_p); + processing_step_p->setDestProcessingType("MZ"); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { - qDebug() << "Integrating to rt / m/z color map."; - - // We need to set two specs to the step. + qDebug() << "Integrating to m/z / rt color map."; - processing_step_p->newSpec(ProcessingType("RT_DT_RT_TO_RT_MZ"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_DT_DT_TO_RT_MZ"), - dt_processing_spec_p); + processing_step_p->setDestProcessingType("MZ_RT"); } else if(m_ui.integrateToDtMzPushButton->isChecked()) { qDebug() << "Integrating to dt / m/z color map."; - // We need to set two specs to the step. - - processing_step_p->newSpec(ProcessingType("RT_DT_RT_TO_DT_MZ"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_DT_DT_TO_DT_MZ"), - dt_processing_spec_p); + processing_step_p->setDestProcessingType("DT_MZ"); } // At this point we need to define how the mass data integrator will @@ -440,7 +460,7 @@ // Note that we cannot integrate mass spectra with a high resolution // here. We need to reduce the resolution to integer resolution. if(m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { mz_integration_params.setBinningType(pappso::BinningType::NONE); mz_integration_params.setDecimalPlaces(0); @@ -471,22 +491,17 @@ static_cast(mp_parentWnd) ->integrateToDtMz(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { static_cast(mp_parentWnd) - ->integrateToRtMz(plottable_p, local_processing_flow); + ->integrateToMzRt(plottable_p, local_processing_flow); } } else if(m_ui.integrateToDtPushButton->isChecked()) { - qDebug() << "Integrating to drift spectrum."; + qDebug() << "Integrating to drift spectrum."; - // We need to set two specs to the step. - - processing_step_p->newSpec(ProcessingType("RT_DT_RT_TO_DT"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_DT_DT_TO_DT"), - dt_processing_spec_p); + processing_step_p->setDestProcessingType("DT"); local_processing_flow.push_back(processing_step_p); @@ -497,12 +512,7 @@ { qDebug() << "Integrating to TIC intensity."; - // We need to set two specs to the step. - - processing_step_p->newSpec(ProcessingType("RT_DT_RT_TO_INT"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_DT_DT_TO_INT"), - dt_processing_spec_p); + processing_step_p->setDestProcessingType("INT"); local_processing_flow.push_back(processing_step_p); diff -Nru minexpert2-7.4.1/src/gui/TicXicChromDriftSpecColorMapWnd.cpp minexpert2-8.1.1/src/gui/TicXicChromDriftSpecColorMapWnd.cpp --- minexpert2-7.4.1/src/gui/TicXicChromDriftSpecColorMapWnd.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/TicXicChromDriftSpecColorMapWnd.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -78,7 +78,7 @@ QCPColorMap * TicXicChromDriftSpecColorMapWnd::addColorMapPlot( - std::shared_ptr> &double_map_trace_map_sp, + std::shared_ptr> &rt_maptrace_map, const pappso::ColorMapPlotConfig &color_map_plot_config, MsRunDataSetCstSPtr ms_run_data_set_csp, const ProcessingFlow &processing_flow, @@ -105,7 +105,7 @@ } return finalNewColorMapPlotConfiguration(composite_widget_p, - double_map_trace_map_sp, + rt_maptrace_map, color_map_plot_config, ms_run_data_set_csp, processing_flow, @@ -115,13 +115,13 @@ void -TicXicChromDriftSpecColorMapWnd::integrateToRtDt( +TicXicChromDriftSpecColorMapWnd::integrateToDtRt( QCPAbstractPlottable *parent_plottable_p, std::shared_ptr> qualified_mass_spectra_sp, const ProcessingFlow &processing_flow) { - // qDebug().noquote() << "Integrating to rt | mz with processing flow:" + //qDebug().noquote() << "Integrating to dt | rt with processing flow:" //<< processing_flow.toString(); // Get the ms run data set that for the graph we are going to base the @@ -131,30 +131,40 @@ if(ms_run_data_set_csp == nullptr) qFatal("Cannot be that the pointer is nullptr."); - // We will try to limit the number of mass spectra to iterate through with the - // integration visitor. + // FIXME: BEGIN Sanity check that might be removed when the program is stabilized. + std::pair range_pair; - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); - - bool integration_rt = processing_flow.innermostRtRange(start_rt, end_rt); + bool integration_rt = processing_flow.innermostRange("ANY_RT", range_pair); if(!integration_rt) qFatal("Programming error."); - qDebug() << "Innermost RT range:" << start_rt << "-" << end_rt; + qDebug() << qSetRealNumberPrecision(10) << "Innermost RT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + + bool integration_dt = processing_flow.innermostRange("ANY_DT", range_pair); + + if(integration_dt) + qDebug() << qSetRealNumberPrecision(10) << "Innermost DT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; - // First prepare a vector of QualifiedMassSpectrumCstSPtr + // FIXME: END Sanity check that might be removed when the program is stabilized. + + // First prepare a vector of QualifiedMassSpectrumCstSPtr. If the + // qualified_mass_spectra_sp is not empty, the + // fillInQualifiedMassSpectraVector() function below does not change the + // vector and returns its size. std::size_t qualified_mass_spectra_count = fillInQualifiedMassSpectraVector( ms_run_data_set_csp, qualified_mass_spectra_sp, processing_flow); + qDebug() + << "The number of selected mass spectra on the basis of rough RT/DT values:" + << qualified_mass_spectra_count; + if(!qualified_mass_spectra_count) return; - qDebug() << "The number of remaining mass spectra:" - << qualified_mass_spectra_count; - // Now start the actual integration work. // Allocate a mass data integrator to integrate the data. @@ -163,7 +173,8 @@ new QualifiedMassSpectrumVectorMassDataIntegratorToRtDt( ms_run_data_set_csp, processing_flow, qualified_mass_spectra_sp); - mass_data_integrator_p->setMaxThreadUseCount(mp_programWindow->getMaxThreadUseCount()); + mass_data_integrator_p->setMaxThreadUseCount( + mp_programWindow->getMaxThreadUseCount()); // Ensure the mass data integrator messages are used. @@ -176,24 +187,20 @@ MassDataIntegratorTask *mass_data_integrator_task_p = new MassDataIntegratorTask(); + qRegisterMetaType("std::size_t"); qRegisterMetaType("pappso::DataKind"); // This signal starts the computation in the MassDataIntegratorTask object. - connect( - this, + connect(this, - static_cast( - &TicXicChromDriftSpecColorMapWnd::integrateToRtDtSignal), + &TicXicChromDriftSpecColorMapWnd::integrateToDtRtSignal, - mass_data_integrator_task_p, + mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::integrateToRtDt), + &MassDataIntegratorTask::integrateToDtRt, - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); + // Fundamental for signals that travel across QThread instances... + Qt::QueuedConnection); // Allocate the thread in which the integrator task will run. QThread *thread_p = new QThread; @@ -227,7 +234,7 @@ // the thread and ask for it to also be deleted later. thread_p->deleteLater(), thread_p->quit(); thread_p->wait(); - this->finishedIntegratingToRtDt(mass_data_integrator_p, + this->finishedIntegratingToDtRt(mass_data_integrator_p, parent_plottable_p); }); @@ -281,11 +288,11 @@ task_monitor_composite_widget_p->makeMassDataIntegratorConnections( mass_data_integrator_p); - // qDebug() << "going to emit integrateToRtDtMzSignal with mass " + // qDebug() << "going to emit integrateToDtRtMzSignal with mass " //"data integrator:" //<< mass_data_integrator_p; - emit integrateToRtDtSignal(mass_data_integrator_p, pappso::DataKind::rt); + emit integrateToDtRtSignal(mass_data_integrator_p); // We do not want to make signal/slot calls more than once. This is because // one user might well trigger more than one integration from this window to a @@ -297,20 +304,16 @@ disconnect( this, - static_cast( - &TicXicChromDriftSpecColorMapWnd::integrateToRtDtSignal), + &TicXicChromDriftSpecColorMapWnd::integrateToDtRtSignal, mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::integrateToRtDt)); + &MassDataIntegratorTask::integrateToDtRt); } void -TicXicChromDriftSpecColorMapWnd::finishedIntegratingToRtDt( +TicXicChromDriftSpecColorMapWnd::finishedIntegratingToDtRt( QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p, QCPAbstractPlottable *parent_plottable_p) { @@ -337,14 +340,24 @@ // Get a pointer to the double maptrace map that will serve as the data to // fill-in the color map. - std::shared_ptr> double_map_trace_map_sp = - mass_data_integrator_to_dtrt_p->getDoubleMapTraceMapSPtr(); + + // The logic here is that in IM-MS experiments, for a given retention time + // (rt), the might be hundrds of drift time-resolvec mass spectra. So we + // create a map that relates rt values with a MapTrace, itself relating dt + // values (map key) and TICint values (map value). During iterating in all the + // mass spectra, we look at the rt value of the mass spectrum, we then look at + // its dt value. We compute a TICint of the mass spectrum that we set in the + // MapTrace, associated with the dt value. That MapTrace is then set the + // member map that maps the rt value (map key) with the MapTrace (map value). - // qDebug() << "rt / mz map size:" << double_map_trace_map_sp->size(); + std::shared_ptr> rt_maptrace_map = + mass_data_integrator_to_dtrt_p->getRtMapTraceMapSPtr(); - if(!double_map_trace_map_sp->size()) + // qDebug() << "rt / maptrace map size:" << rt_maptrace_map->size(); + + if(!rt_maptrace_map->size()) { - qDebug() << "There is not a single item in the dt / rt map."; + qDebug() << "There is not a single item in the dt / maptrace map."; return; } @@ -353,23 +366,40 @@ // the minimum/maximum mz value. pappso::ColorMapPlotConfig color_map_plot_config( + // x data kind pappso::DataKind::rt, + // y data kind pappso::DataKind::dt, + + // x axis scale pappso::AxisScale::orig, + // y axis scale pappso::AxisScale::orig, + // z axis scale pappso::AxisScale::orig, + mass_data_integrator_to_dtrt_p->getColorMapKeyCellCount(), mass_data_integrator_to_dtrt_p->getColorMapMzCellCount(), + + // min rt value mass_data_integrator_to_dtrt_p->getColorMapMinKey(), + // max rt value mass_data_integrator_to_dtrt_p->getColorMapMaxKey(), + + // smallest m/z value mass_data_integrator_to_dtrt_p->getColorMapMinMz(), - mass_data_integrator_to_dtrt_p->getColorMapMaxMz()); + // greatest m/z value + mass_data_integrator_to_dtrt_p->getColorMapMaxMz(), + /*the min Z value will be determined later*/ 0, + /*the max Z value will be determined later*/ 0); // Also, do not forget to copy the processing flow from the integrator. This // processing flow will be set into the plot widget ! ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); + //qDebug() << "The processing flow after integration to dt|rt:" << processing_flow.toString(); + // Sanity check if(ms_run_data_set_csp != processing_flow.getMsRunDataSetCstSPtr()) qFatal("Cannot be that the ms run data set pointers be different."); @@ -396,7 +426,7 @@ // Note that we do not support multiple color maps stacked one on top of the // other. - addColorMapPlot(double_map_trace_map_sp, + addColorMapPlot(rt_maptrace_map, color_map_plot_config, ms_run_data_set_csp, processing_flow, diff -Nru minexpert2-7.4.1/src/gui/TicXicChromDriftSpecColorMapWnd.hpp minexpert2-8.1.1/src/gui/TicXicChromDriftSpecColorMapWnd.hpp --- minexpert2-7.4.1/src/gui/TicXicChromDriftSpecColorMapWnd.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/TicXicChromDriftSpecColorMapWnd.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -77,7 +77,7 @@ const QColor &color, QCPAbstractPlottable *parent_plottable_p) override; - virtual void integrateToRtDt( + virtual void integrateToDtRt( QCPAbstractPlottable *plottable_p, std::shared_ptr> qualified_mass_spectra_sp, @@ -85,15 +85,14 @@ public slots: - void finishedIntegratingToRtDt( + void finishedIntegratingToDtRt( QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p, QCPAbstractPlottable *parent_plottable_p); signals: - void integrateToRtDtSignal( - QualifiedMassSpectrumVectorMassDataIntegratorToRtDt *mass_data_integrator_p, - pappso::DataKind data_kind); + void integrateToDtRtSignal( + QualifiedMassSpectrumVectorMassDataIntegratorToRtDt *mass_data_integrator_p); protected: }; diff -Nru minexpert2-7.4.1/src/gui/TicXicChromMassSpecColorMapPlotCompositeWidget.cpp minexpert2-8.1.1/src/gui/TicXicChromMassSpecColorMapPlotCompositeWidget.cpp --- minexpert2-7.4.1/src/gui/TicXicChromMassSpecColorMapPlotCompositeWidget.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/TicXicChromMassSpecColorMapPlotCompositeWidget.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -41,6 +41,7 @@ /////////////////////// pappsomspp includes +#include #include @@ -181,25 +182,50 @@ // qDebug().noquote() << "context:" << context.toString(); // We are getting that signal from a plot widget that operates as a - // tic xic chrom / mass spec color map plot widget. + // tic xic chrom / mass spec color map plot widget. By essence, the selected + // region needs to be two-dimensional, so the selection polygon needs to be + // so. + + // Check if the selection polygon contain meaninful data. We are in a colormap + // plot widget, so the selection polygon cannot be in the form of a + // mono-dimensional polygon. + + if(!context.m_selectionPolygon.is2D()) + { + qDebug() << "The selection polygon cannot be mono-dimensional when " + "selecting for integration from color map"; + return; + } + else + { + if(context.m_selectionPolygon.isRectangle()) + qDebug() << "The selection polygon is rectangle."; + else + qDebug() << "The selection polygon is oblique (skewed)."; + } + + // Sanity check. // Immediately check if the selection range makes sense. For example, having // both the start/end values in the negative values does not mean anything // with respect to tic|xic chrom vs mass spectrum data! - // Remember that the xregion start and end are not sorted. - double x_range_start = - std::min(context.xRegionRangeStart, context.xRegionRangeEnd); - double x_range_end = - std::max(context.xRegionRangeStart, context.xRegionRangeEnd); + double x_range_start; + double x_range_end; + + context.m_selectionPolygon.rangeX(x_range_start, x_range_end); + + qDebug() << "X axis range:" << x_range_start << "-" << x_range_end; if(x_range_start < 0 && x_range_end < 0) return; - double y_range_start = - std::min(context.yRegionRangeStart, context.yRegionRangeEnd); - double y_range_end = - std::max(context.yRegionRangeStart, context.yRegionRangeEnd); + double y_range_start; + double y_range_end; + + context.m_selectionPolygon.rangeY(y_range_start, y_range_end); + + qDebug() << "Y axis range:" << y_range_start << "-" << y_range_end; if(y_range_start < 0 && y_range_end < 0) return; @@ -217,7 +243,6 @@ // selected is the right one. If there are more than one traces selected, then // we cannot do anything. Display an error message. - // The QCustomPlot-based widget might contain more than one graph, and we // need to know on what graph the user is willing to perform the // integration. @@ -236,7 +261,8 @@ return; } - // Create a local copy of the processing flow. + // Create a local copy of the processing flow so that we can modify it by + // adding the new processing step that describes what we are doing now. ProcessingFlow local_processing_flow = getProcessingFlowForPlottable(plottable_p); @@ -254,21 +280,6 @@ ProcessingStep *processing_step_p = new ProcessingStep(); - // The step has a multi-map of pairs that each relate a processing type with a - // processing spec. So we need to document a new pair type/spec, let's start - // with the spec that documents the range of the data we are willing to - // integrate, that is, the selected region of the graph. - - // The ProcessingSpec has the range start/end values, an optional ms - // fragmentation specification and a date time that is set automatically at - // construction time. - - // Allocate a new spec that will hold the RT dimension range. - ProcessingSpec *rt_processing_spec_p = new ProcessingSpec(); - - // And another one for the MZ dimension range. - ProcessingSpec *mz_processing_spec_p = new ProcessingSpec(); - // If the user had set ms fragmentation specifications, all these are listed // in the various ProcessingSpec instances, so we do not loose any. However, // the user is entitled to define any new ms fragmentation specifications @@ -286,7 +297,7 @@ // flow " "is valid, using it:" //<< ms_fragmentation_spec.toString(); - mz_processing_spec_p->setMsFragmentationSpec(ms_fragmentation_spec); + processing_step_p->setMsFragmentationSpec(ms_fragmentation_spec); } else { @@ -294,100 +305,115 @@ //"valid. Not using it."; } - // Now define the graph ranges for the integration operation. + // Now define which selection polygon sides have which data kind. - // Remember that the region start and end are not sorted. Also, the colormap - // can have its axes transposed, so we need to ensure that we use the proper - // axis for mz and the proper axis for the other dimension (rt or dt). + // Sanity check. - if(static_cast(mp_plotWidget) - ->xAxisDataKind() == pappso::DataKind::rt) - { - rt_processing_spec_p->setRange(x_range_start, x_range_end); - mz_processing_spec_p->setRange(y_range_start, y_range_end); + pappso::DataKind x_axis_data_kind = + static_cast(mp_plotWidget) + ->xAxisDataKind(); + pappso::DataKind y_axis_data_kind = + static_cast(mp_plotWidget) + ->yAxisDataKind(); + + if(x_axis_data_kind == pappso::DataKind::mz) + qDebug() << "X axis: mz"; + else if(x_axis_data_kind == pappso::DataKind::rt) + qDebug() << "X axis: rt"; - qDebug() << "x axis data kind is rt" - << "RT range:" << x_range_start << "-" << x_range_end - << "MZ range:" << y_range_start << "-" << y_range_end; + if(x_axis_data_kind == pappso::DataKind::mz && + y_axis_data_kind != pappso::DataKind::rt) + { + qFatal("Programming error."); } - else + else if(x_axis_data_kind == pappso::DataKind::rt && + y_axis_data_kind != pappso::DataKind::mz) { - rt_processing_spec_p->setRange(y_range_start, y_range_end); - mz_processing_spec_p->setRange(x_range_start, x_range_end); + qFatal("Programming error."); + } - qDebug() << "x axis data kind is mz" - << "RT range:" << y_range_start << "-" << y_range_end - << "MZ range:" << x_range_start << "-" << x_range_end; + // The colormap can have its axes transposed, so we need to ensure that we + // document the axis/data-kind relation properly. Note that we want the + // processing step to be documented according to the alpha numerical ordering. + // So, if we are working in a DT_RT colormap, then, x axis needs to be DT and + // y axis needs to be RT. + + // Make a local copy of the selection polygon because we might need to + // transpose it. + + pappso::SelectionPolygon local_selection_polygon = context.m_selectionPolygon; + + if(x_axis_data_kind == pappso::DataKind::rt) + { + // We have to transpose the selection rectangle so that x:DT and y:RT. + local_selection_polygon = local_selection_polygon.transpose(); } + // else + // No need to tranpose, we deal with data in the right x:MZ y:RT. + + qDebug() << "The selection polygon:" << local_selection_polygon.toString(); + + // Now we know we have the right selection polygon for x:MZ and y:RT. + + processing_step_p->setDataKind(pappso::Axis::x, pappso::DataKind::mz); + processing_step_p->setDataKind(pappso::Axis::y, pappso::DataKind::rt); + + + // And now actually set the selection polygon to the step. + + processing_step_p->setSelectionPolygon(local_selection_polygon); + + // We must say what is the data source processing type. + processing_step_p->setSrcProcessingType(pappso::Axis::x, "MZ"); + processing_step_p->setSrcProcessingType(pappso::Axis::y, "RT"); + + // Now we need to document not the source but the destination. What kind of + // integration are we about to perform? if(m_ui.integrateToRtPushButton->isChecked()) { - // qDebug() << "Integration to XIC chromatogram."; - - // We need to set two specs to the step. + qDebug() << "Integrating to XIC chromatogram."; - processing_step_p->newSpec(ProcessingType("RT_MZ_RT_TO_RT"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_MZ_MZ_TO_RT"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("RT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) ->integrateToRt(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtDtPushButton->isChecked()) + else if(m_ui.integrateToDtRtPushButton->isChecked()) { - qDebug() << "Integrating to rt / dt color map."; + qDebug() << "Integrating to dt / rt color map."; - // We need to set two specs to the step. - - processing_step_p->newSpec(ProcessingType("RT_MZ_RT_TO_RT_DT"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_MZ_MZ_TO_RT_DT"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("DT_RT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) - ->integrateToRtDt(plottable_p, local_processing_flow); + ->integrateToDtRt(plottable_p, local_processing_flow); } + // Handle all the integrations to MZ in one place else if(m_ui.integrateToMzPushButton->isChecked() || m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { if(m_ui.integrateToMzPushButton->isChecked()) { - qDebug() << "Integrating to mass spectrum."; - - // We need to set two specs to the step. + qDebug() << "Integrating to mass spectrum."; - processing_step_p->newSpec(ProcessingType("RT_MZ_RT_TO_MZ"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_MZ_MZ_TO_MZ"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("MZ"); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { - qDebug() << "Integrating to rt / m/z color map."; + qDebug() << "Integrating to m/z / rt color map."; - // We need to set two specs to the step. - - processing_step_p->newSpec(ProcessingType("RT_MZ_RT_TO_RT_MZ"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_MZ_MZ_TO_RT_MZ"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("MZ_RT"); } else if(m_ui.integrateToDtMzPushButton->isChecked()) { - qDebug() << "Integrating to dt / m/z color map."; - - // We need to set two specs to the step. + qDebug() << "Integrating to dt / m/z color map."; - processing_step_p->newSpec(ProcessingType("RT_MZ_RT_TO_DT_MZ"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_MZ_MZ_TO_DT_MZ"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("DT_MZ"); } // At this point we need to define how the mass data integrator will @@ -430,7 +456,7 @@ // Note that we cannot integrate mass spectra with a high resolution // here. We need to reduce the resolution to integer resolution. if(m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { mz_integration_params.setBinningType(pappso::BinningType::NONE); mz_integration_params.setDecimalPlaces(0); @@ -461,22 +487,17 @@ static_cast(mp_parentWnd) ->integrateToDtMz(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { static_cast(mp_parentWnd) - ->integrateToRtMz(plottable_p, local_processing_flow); + ->integrateToMzRt(plottable_p, local_processing_flow); } } else if(m_ui.integrateToDtPushButton->isChecked()) { qDebug() << "Integrating to drift spectrum."; - // We need to set two specs to the step. - - processing_step_p->newSpec(ProcessingType("RT_MZ_RT_TO_DT"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_MZ_MZ_TO_DT"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("DT"); local_processing_flow.push_back(processing_step_p); @@ -487,12 +508,7 @@ { qDebug() << "Integrating to TIC intensity."; - // We need to set two specs to the step. - - processing_step_p->newSpec(ProcessingType("RT_MZ_RT_TO_INT"), - rt_processing_spec_p); - processing_step_p->newSpec(ProcessingType("RT_MZ_MZ_TO_INT"), - mz_processing_spec_p); + processing_step_p->setDestProcessingType("INT"); local_processing_flow.push_back(processing_step_p); diff -Nru minexpert2-7.4.1/src/gui/TicXicChromMassSpecColorMapWnd.cpp minexpert2-8.1.1/src/gui/TicXicChromMassSpecColorMapWnd.cpp --- minexpert2-7.4.1/src/gui/TicXicChromMassSpecColorMapWnd.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/TicXicChromMassSpecColorMapWnd.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -105,7 +105,7 @@ void -TicXicChromMassSpecColorMapWnd::integrateToRtMz( +TicXicChromMassSpecColorMapWnd::integrateToMzRt( QCPAbstractPlottable *parent_plottable_p, std::shared_ptr> qualified_mass_spectra_sp, @@ -121,18 +121,28 @@ if(ms_run_data_set_csp == nullptr) qFatal("Cannot be that the pointer is nullptr."); - // We will try to limit the number of mass spectra to iterate through with the - // integration visitor. + // FIXME: BEGIN Sanity check that might be removed when the program is stabilized. + std::pair range_pair; - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); - - bool integration_rt = processing_flow.innermostRtRange(start_rt, end_rt); + bool integration_rt = processing_flow.innermostRange("ANY_RT", range_pair); if(!integration_rt) qFatal("Programming error."); - // First prepare a vector of QualifiedMassSpectrumCstSPtr + qDebug() << qSetRealNumberPrecision(10) << "Innermost RT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + + bool integration_dt = processing_flow.innermostRange("ANY_DT", range_pair); + + if(integration_dt) + qDebug() << qSetRealNumberPrecision(10) << "Innermost DT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + // FIXME: END Sanity check that might be removed when the program is stabilized. + + // First prepare a vector of QualifiedMassSpectrumCstSPtr. If the + // qualified_mass_spectra_sp is not empty, the + // fillInQualifiedMassSpectraVector() function below does not change the + // vector and returns its size. std::size_t qualified_mass_spectra_count = fillInQualifiedMassSpectraVector( ms_run_data_set_csp, qualified_mass_spectra_sp, processing_flow); @@ -152,7 +162,8 @@ new QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz( ms_run_data_set_csp, processing_flow, qualified_mass_spectra_sp); - mass_data_integrator_p->setMaxThreadUseCount(mp_programWindow->getMaxThreadUseCount()); + mass_data_integrator_p->setMaxThreadUseCount( + mp_programWindow->getMaxThreadUseCount()); // Ensure the mass data integrator messages are used. @@ -165,21 +176,17 @@ MassDataIntegratorTask *mass_data_integrator_task_p = new MassDataIntegratorTask(); + qRegisterMetaType("std::size_t"); qRegisterMetaType("pappso::DataKind"); // This signal starts the computation in the MassDataIntegratorTask object. connect(this, - static_cast( - &TicXicChromMassSpecColorMapWnd::integrateToDtRtMzSignal), + &TicXicChromMassSpecColorMapWnd::integrateToDtRtMzSignal, mass_data_integrator_task_p, - static_cast(&MassDataIntegratorTask::integrateToDtRtMz), + &MassDataIntegratorTask::integrateToDtRtMz, // Fundamental for signals that travel across QThread instances... Qt::QueuedConnection); @@ -274,7 +281,7 @@ //"data integrator:" //<< mass_data_integrator_p; - emit integrateToDtRtMzSignal(mass_data_integrator_p, pappso::DataKind::rt); + emit integrateToDtRtMzSignal(mass_data_integrator_p); // We do not want to make signal/slot calls more than once. This is because // one user might well trigger more than one integration from this window to a @@ -285,16 +292,11 @@ // to a this/mass_data_integrator_task_p specific signal/slot pair. disconnect(this, - static_cast( - &TicXicChromMassSpecColorMapWnd::integrateToDtRtMzSignal), + &TicXicChromMassSpecColorMapWnd::integrateToDtRtMzSignal, mass_data_integrator_task_p, - static_cast(&MassDataIntegratorTask::integrateToDtRtMz)); + &MassDataIntegratorTask::integrateToDtRtMz); } @@ -352,7 +354,9 @@ mass_data_integrator_to_rtdtmz_p->getColorMapMinKey(), mass_data_integrator_to_rtdtmz_p->getColorMapMaxKey(), mass_data_integrator_to_rtdtmz_p->getColorMapMinMz(), - mass_data_integrator_to_rtdtmz_p->getColorMapMaxMz()); + mass_data_integrator_to_rtdtmz_p->getColorMapMaxMz(), + /*the min Z value will be determined later*/ 0, + /*the max Z value will be determined later*/ 0); // Also, do not forget to copy the processing flow from the integrator. This // processing flow will be set into the plot widget ! diff -Nru minexpert2-7.4.1/src/gui/TicXicChromMassSpecColorMapWnd.hpp minexpert2-8.1.1/src/gui/TicXicChromMassSpecColorMapWnd.hpp --- minexpert2-7.4.1/src/gui/TicXicChromMassSpecColorMapWnd.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/TicXicChromMassSpecColorMapWnd.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -77,7 +77,7 @@ const QColor &color, QCPAbstractPlottable *parent_plottable_p) override; - virtual void integrateToRtMz( + virtual void integrateToMzRt( QCPAbstractPlottable *plottable_p, std::shared_ptr> qualified_mass_spectra_sp, @@ -92,8 +92,7 @@ signals: void integrateToDtRtMzSignal( - QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz *mass_data_integrator_p, - pappso::DataKind data_kind); + QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz *mass_data_integrator_p); protected: }; diff -Nru minexpert2-7.4.1/src/gui/TicXicChromTracePlotCompositeWidget.cpp minexpert2-8.1.1/src/gui/TicXicChromTracePlotCompositeWidget.cpp --- minexpert2-7.4.1/src/gui/TicXicChromTracePlotCompositeWidget.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/TicXicChromTracePlotCompositeWidget.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -163,9 +163,9 @@ // char was pressed. BaseTracePlotCompositeWidget::plotWidgetKeyPressEvent(context); - m_plotWidgetPressedKeyCode = context.pressedKeyCode; + m_plotWidgetPressedKeyCode = context.m_pressedKeyCode; - if(context.pressedKeyCode == Qt::Key_Space) + if(context.m_pressedKeyCode == Qt::Key_Space) { QCPAbstractPlottable *plottable_p = plottableToBeUsedAsIntegrationSource(); @@ -204,7 +204,7 @@ mp_parentWnd->recordAnalysisStanza(stanza, plottable_p->pen().color()); } // End of - // if(context.pressedKeyCode == Qt::Key_Space) + // if(context.m_pressedKeyCode == Qt::Key_Space) } @@ -231,8 +231,8 @@ // in the base class function. pappso::BasePlotContext local_context = context; - local_context.xRegionRangeStart = m_integrationRange.lower; - local_context.xRegionRangeEnd = m_integrationRange.upper; + local_context.m_xRegionRangeStart = m_integrationRange.lower; + local_context.m_xRegionRangeEnd = m_integrationRange.upper; if(m_isSinglePointIntegrationMode) integrationRequested(local_context); @@ -243,18 +243,37 @@ TicXicChromTracePlotCompositeWidget::integrationRequested( const pappso::BasePlotContext &context) { - // qDebug().noquote() << "context:" << context.toString(); + qDebug().noquote() << "context:" << context.toString(); - // Immediately check if the selection range makes sense. For example, having - // both the start/end values in the negative values does not mean anything - // with respect to TIC | XIC chromatogram data! - - // Remember that the xregion start and end are not sorted. - double range_start = - std::min(context.xRegionRangeStart, context.xRegionRangeEnd); - double range_end = - std::max(context.xRegionRangeStart, context.xRegionRangeEnd); + // Make a local copy of the context because we may need to modify it. + pappso::BasePlotContext local_context = context; + + // Check if the selection polygon contain meaningful data. We are in trace + // plot widget, so the selection polygon might be in the form of a + // mono-dimensional polygon, although this is not mandatory. But we rely on + // the selection polygon to be of 1 or 2 dimension for some optimizations. So, + // if the polygon is 2D, convert it to 1D. + + if(local_context.m_selectionPolygon.is2D()) + qDebug() << "Odd situation where the selection polygon is two-dimensional " + "and the trace plot selection is mono-dimensional. Converting " + "it to a 1D selection polygon."; + + local_context.m_selectionPolygon.convertTo1D(); + + // Sanity check. + + // The user may select at the left of the x=0, but that does not make sense if + // the whole selected region is in the x axis negative space. + double range_start; + double range_end; + local_context.m_selectionPolygon.rangeX(range_start, range_end); + + qDebug() << "selection polygon:" << local_context.m_selectionPolygon.toString(); + //qDebug() << "X axis range:" << range_start << "-" << range_end; + + // Having negative retention times does not make any sense. if(range_start < 0 && range_end < 0) return; @@ -293,35 +312,28 @@ return; } - // Create a local copy of the processing flow. + // Create a local copy of the processing flow so that we can modify it by + // adding the new processing step that describes what we are doing now. + + qDebug(); ProcessingFlow local_processing_flow = getProcessingFlowForPlottable(plottable_p); - // qDebug().noquote() << "Processing flow for graph:" - //<< local_processing_flow.toString(); + qDebug() << local_processing_flow.getMsRunDataSetCstSPtr()->getMsRunId()->getFileName(); + + qDebug().noquote() << "Processing flow for graph:" + << local_processing_flow.toString(); MsRunDataSetCstSPtr ms_run_data_set_csp = getMsRunDataSetCstSPtrForPlottable(plottable_p); // qDebug() << ms_run_data_set_csp->getMsRunDataSetStats().toString(); - // Now we need to add a new step in that processing flow so that we document - // this new integration that we are performing. + // Create a processing step to document the specifics of this new integration. ProcessingStep *processing_step_p = new ProcessingStep(); - // The step has a multi-map of pairs that each relate a processing type with a - // processing spec. So we need to document a new pair type/spec, let's start - // with the spec that documents the range of the data we are willing to - // integrate, that is, the selected region of the graph. - - // The ProcessingSpec has the range start/end values, an optional ms - // fragmentation specification and a date time that is set automatically at - // construction time. - - ProcessingSpec *processing_spec_p = new ProcessingSpec(); - // If the user had set ms fragmentation specifications, all these are listed // in the various ProcessingSpec instances, so we do not loose any. However, // the user is entitled to define any new ms fragmentation specifications @@ -339,7 +351,7 @@ // flow " "is valid, using it:" //<< ms_fragmentation_spec.toString(); - processing_spec_p->setMsFragmentationSpec(ms_fragmentation_spec); + processing_step_p->setMsFragmentationSpec(ms_fragmentation_spec); } else { @@ -348,13 +360,24 @@ //<< ms_fragmentation_spec.toString(); } + // Now make sure we document the selection polygon. // Now define the graph range for the integration operation. - processing_spec_p->setRange(range_start, range_end); + qDebug(); + + processing_step_p->setSelectionPolygon(local_context.m_selectionPolygon); + + qDebug(); - // qDebug() << "Range:" << range_start << "-" << range_end; + // We must say what is the data source processing type. + processing_step_p->setSrcProcessingType(pappso::Axis::x, "RT"); - // Now handle the specific part of the ProcessingSpec, that part that depends + // It is essential that we document the relation between the axes and the + // corresponding data type. + processing_step_p->setDataKind(pappso::Axis::x, pappso::DataKind::rt); + processing_step_p->setDataKind(pappso::Axis::y, pappso::DataKind::unset); + + // Now handle the specific part of the ProcessingStep, that part that depends // on the kind of integration the user is willing to perform. Note below that // we gather all the integrations to destinations that involve integration // mass spectra. This is because we factorize the requriement to have proper @@ -364,7 +387,7 @@ { // qDebug() << "Integration to XIC chromatogram."; - processing_step_p->newSpec(ProcessingType("RT_TO_RT"), processing_spec_p); + processing_step_p->setDestProcessingType("RT"); local_processing_flow.push_back(processing_step_p); @@ -373,25 +396,25 @@ } else if(m_ui.integrateToMzPushButton->isChecked() || m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { if(m_ui.integrateToMzPushButton->isChecked()) { - // qDebug() << "Integrating to mass spectrum."; - processing_step_p->newSpec(ProcessingType("RT_TO_MZ"), - processing_spec_p); - } - else if(m_ui.integrateToRtMzPushButton->isChecked()) - { - // qDebug() << "Integrating to rt|m/z color map."; - processing_step_p->newSpec(ProcessingType("RT_TO_RT_MZ"), - processing_spec_p); + qDebug() << "Integrating to mass spectrum."; + processing_step_p->setDestProcessingType("MZ"); + + qDebug() << "Currently elaborating processing_step_p: " + << processing_step_p->toString(); + } + else if(m_ui.integrateToMzRtPushButton->isChecked()) + { + qDebug() << "Integrating to rt|m/z color map."; + processing_step_p->setDestProcessingType("MZ_RT"); } else if(m_ui.integrateToDtMzPushButton->isChecked()) { - // qDebug() << "Integrating to dt|m/z color map."; - processing_step_p->newSpec(ProcessingType("RT_TO_DT_MZ"), - processing_spec_p); + qDebug() << "Integrating to dt|m/z color map."; + processing_step_p->setDestProcessingType("DT_MZ"); } // At this point we need to define how the mass data integrator will @@ -437,7 +460,7 @@ // Note that we cannot integrate mass spectra with a high resolution // here. We need to reduce the resolution to integer resolution. if(m_ui.integrateToDtMzPushButton->isChecked() || - m_ui.integrateToRtMzPushButton->isChecked()) + m_ui.integrateToMzRtPushButton->isChecked()) { mz_integration_params.setBinningType(pappso::BinningType::NONE); mz_integration_params.setDecimalPlaces(0); @@ -452,8 +475,7 @@ // last one. local_processing_flow.push_back(processing_step_p); - // qDebug().noquote() << "Pushed back new processing step:" - //<< processing_step_p->toString(); + qDebug(); // The local processing flow contains all the previous steps and the last // one that documents this current integration. @@ -468,48 +490,39 @@ static_cast(mp_parentWnd) ->integrateToDtMz(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtMzPushButton->isChecked()) + else if(m_ui.integrateToMzRtPushButton->isChecked()) { static_cast(mp_parentWnd) - ->integrateToRtMz(plottable_p, local_processing_flow); + ->integrateToMzRt(plottable_p, local_processing_flow); } } else if(m_ui.integrateToDtPushButton->isChecked()) { - // qDebug() << "Integrating to drift spectrum."; + qDebug() << "Integrating to drift spectrum."; - processing_step_p->newSpec(ProcessingType("RT_TO_DT"), processing_spec_p); + processing_step_p->setDestProcessingType("DT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) ->integrateToDt(plottable_p, local_processing_flow); } - else if(m_ui.integrateToRtDtPushButton->isChecked()) + else if(m_ui.integrateToDtRtPushButton->isChecked()) { - // qDebug() << "Integrating to TIC|XIC chromatogram / drift spectrum - // colormap."; - - ProcessingSpec *spec_p = new ProcessingSpec(); - - processing_step_p->newSpec(ProcessingType("RT_TO_RT_DT"), spec_p); + qDebug() << "Integrating to dt/rt colormap."; - // We now need to specify the RT range. - - processing_step_p->newSpec(ProcessingType("RT_TO_ANY"), - processing_spec_p); + processing_step_p->setDestProcessingType("DT_RT"); local_processing_flow.push_back(processing_step_p); static_cast(mp_parentWnd) - ->integrateToRtDt(plottable_p, local_processing_flow); + ->integrateToDtRt(plottable_p, local_processing_flow); } else if(m_ui.integrateToIntPushButton->isChecked()) { - // qDebug() << "Integrating to TIC intensity."; + qDebug() << "Integrating to TIC intensity."; - processing_step_p->newSpec(ProcessingType("RT_TO_INT"), - processing_spec_p); + processing_step_p->setDestProcessingType("INT"); local_processing_flow.push_back(processing_step_p); @@ -528,6 +541,8 @@ QMessageBox::StandardButton::NoButton); } + qDebug(); + return; } @@ -663,7 +678,7 @@ if(curChar == 'X') { stanza += QString("%1").arg( - context.lastCursorHoveredPoint.x(), 0, 'g', 6); + context.m_lastCursorHoveredPoint.x(), 0, 'g', 6); prevChar = ' '; continue; } @@ -674,7 +689,7 @@ // of the point at X. stanza += QString("%1").arg( static_cast(mp_plotWidget) - ->getYatX(context.lastCursorHoveredPoint.x(), + ->getYatX(context.m_lastCursorHoveredPoint.x(), static_cast(plottable_p)), 0, 'g', @@ -685,13 +700,13 @@ } if(curChar == 'x') { - stanza += QString("%1").arg(context.xDelta, 0, 'g', 6); + stanza += QString("%1").arg(context.m_xDelta, 0, 'g', 6); prevChar = ' '; continue; } if(curChar == 'y') { - stanza += QString("%1").arg(context.yDelta, 0, 'g', 6); + stanza += QString("%1").arg(context.m_yDelta, 0, 'g', 6); prevChar = ' '; continue; @@ -705,14 +720,15 @@ } if(curChar == 'b') { - stanza += QString("%1").arg(context.xRegionRangeStart, 0, 'f', 3); + stanza += + QString("%1").arg(context.m_xRegionRangeStart, 0, 'f', 3); prevChar = ' '; continue; } if(curChar == 'e') { - stanza += QString("%1").arg(context.xRegionRangeEnd, 0, 'f', 3); + stanza += QString("%1").arg(context.m_xRegionRangeEnd, 0, 'f', 3); prevChar = ' '; continue; diff -Nru minexpert2-7.4.1/src/gui/TicXicChromTracePlotWnd.cpp minexpert2-8.1.1/src/gui/TicXicChromTracePlotWnd.cpp --- minexpert2-7.4.1/src/gui/TicXicChromTracePlotWnd.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/TicXicChromTracePlotWnd.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -100,10 +100,6 @@ TicXicChromTracePlotWnd::finishedIntegratingToInitialTicChromatogram( MsRunDataSetTreeMassDataIntegratorToRt *mass_data_integrator_p) { - - - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - // We get back the integrator that was made to work in another thread. Now get // the obtained data and work with them. @@ -140,20 +136,31 @@ "the mining session from there.\n", QMessageBox::Ok); } + else if(integrated_trace.size() < 2) + { - // Note that if the mass data file that was loaded contained a single mass - // spectrum, then there would be no TIC. So we need to craft a fake one with - // two points: (0,TIC) and (1,TIC). - if(integrated_trace.size() < 2) - { + // Note that if the mass data file that was loaded contained a single mass + // spectrum, or if the integration yielded a single TIC value for a single + // retention time, then there would be no TIC. So we need to craft a fake + // one with two points: (current,TIC) and (current+1,TIC). + + // This situation might be encountered when the user integration to RT: + // + // 1. a single spectrum for a given RT + // + // 2. multiple spectra for a single RT (that is, multiple specra of + // different DT values but of a single RT value). + + // In this situation the single data point that is there has x = ; + // so just create a new one with x = . - // In this situation the single data point that is there has x = 0 ; so - // just create a new one with x = 1. + pappso::DataPoint unique_data_point = integrated_trace.back(); // qDebug() << "tic trace:" << integrated_trace.toString(); - integrated_trace.push_back(pappso::DataPoint(1, integrated_trace.sumY())); + integrated_trace.push_back( + pappso::DataPoint(unique_data_point.x + 1, unique_data_point.y)); // qDebug() << "tic trace:" << integrated_trace.toString(); } @@ -163,8 +170,6 @@ ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); - // qDebug() << "Got processing_flow:" << processing_flow.toString(); - // Note that we are in special situation: we are now handling a TIC // chromatogram that was computed as a very first integration right after // having read data from file. We did set MS level to 1, because, by @@ -174,21 +179,23 @@ // thus replace that MS level to 0, that means that all the data (whatever the // MS level) will be handled from there. - ProcessingStep *most_recent_step_p = - const_cast(processing_flow.mostRecentStep()); + const ProcessingStep *most_recent_step_p = processing_flow.mostRecentStep(); - std::vector processing_specs = - most_recent_step_p->allProcessingSpecsMatching(ProcessingType("FILE_TO_RT"), - true); - - if(processing_specs.size() != 1) + if(most_recent_step_p->destMatches("FILE_RT")) qFatal( - "Cannot be that there are either no or more than one processing step fo " - "type " - "FILE_TO_RT"); + "Cannot be that there are either no or more than one processing step for " + "type FILE_RT"); + // We need to const_cast the step in order to overwrite is + // MsFragmentationSpec. MsFragmentationSpec *fragmentation_spec_p = - processing_specs.front()->getMsFragmentationSpecPtr(); + const_cast(most_recent_step_p) + ->getMsFragmentationSpecPtr(); + + // While we had set the MS level to 1 because when computing a TIC + // chromatogram we only do that with MS1 data, we now want to set it to 0 + // because all the later integrations need to be capable of involving any + // MS level. 0 states that MS level matches. fragmentation_spec_p->setMsLevel(0); @@ -246,250 +253,6 @@ plot_color); } -#if 0 -// Old version -void -TicXicChromTracePlotWnd::integrateToRt(QCPAbstractPlottable *parent_plottable_p, - const ProcessingFlow &processing_flow) - -{ - qDebug(); - - // qDebug().noquote() << "Integrating to rt with processing flow:" - //<< processing_flow.toString(); - - // Get the ms run data set that for the graph we are going to base the - // integration on. - MsRunDataSetCstSPtr ms_run_data_set_csp = - processing_flow.getMsRunDataSetCstSPtr(); - if(ms_run_data_set_csp == nullptr) - qFatal("Cannot be that the pointer is nullptr."); - - // Pass the integrator the flow we got as param and that describes in its most - // recent step the integration that it should perform. - MsRunDataSetTreeMassDataIntegratorToRt *mass_data_integrator_p = - new MsRunDataSetTreeMassDataIntegratorToRt(ms_run_data_set_csp, - processing_flow); - - // Ensure the mass data integrator messages are used. - - connect(mass_data_integrator_p, - &MassDataIntegrator::logTextToConsoleSignal, - mp_programWindow, - &ProgramWindow::logTextToConsole); - - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - - // Allocate a mass data integrator to integrate the data. - - MassDataIntegratorTask *mass_data_integrator_task_p = - new MassDataIntegratorTask(); - - // This signal starts the computation in the MassDataIntegratorTask object. - connect( - this, - // SIGNAL(integrateToRtSignal(MsRunDataSetTreeMassDataIntegratorToRt - // *)), - static_cast( - &TicXicChromTracePlotWnd::integrateToRtSignal), - mass_data_integrator_task_p, // SLOT(integrateToRt(MsRunDataSetTreeMassDataIntegratorToRt - // *)), - static_cast( - &MassDataIntegratorTask::integrateToRt), - // Fundamental for signals that travel across QThread instances... - Qt::QueuedConnection); - - // Allocate the thread in which the integrator task will run. - QThread *thread_p = new QThread; - - // Move the task to the matching thread. - mass_data_integrator_task_p->moveToThread(thread_p); - thread_p->start(); - - // When the read task finishes, it sends a signal that we trap to go on with - // the plot widget creation stuff. - - // Since we allocated the QThread dynamically we need to be able to destroy it - // later, so make the connection. - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - this, - [this, - thread_p, - mass_data_integrator_p, - parent_plottable_p, - mass_data_integrator_task_p]() { - // Do not forget that we have to delete the MassDataIntegratorTask - // allocated instance. - mass_data_integrator_task_p->deleteLater(); - // Once the task has been labelled to be deleted later, we can stop - // the thread and ask for it to also be deleted later. - thread_p->deleteLater(), thread_p->quit(); - thread_p->wait(); - this->finishedIntegratingToRt(mass_data_integrator_p, - parent_plottable_p); - }); - - - // Allocate a new TaskMonitorCompositeWidget that will receive all the - // integrator's signals and provide feedback to the user about the ongoing - // integration. - - TaskMonitorCompositeWidget *task_monitor_composite_widget_p = - mp_programWindow->getTaskMonitorWnd()->addTaskMonitorWidget(Qt::red); - - // Initialize the monitor composite widget's widgets and make all the - // connections mass data integrator <--> widget. - - task_monitor_composite_widget_p->setMsRunIdText( - ms_run_data_set_csp->getMsRunId()->getSampleName()); - task_monitor_composite_widget_p->setTaskDescriptionText( - "Integrating to XIC chromatogram."); - task_monitor_composite_widget_p->setProgressBarMinValue(0); - - // Make the connections - - // When the integrator task instance has finished working, it will send a - // signal that we trap to finally destroy (after a time lag of some seconds, - // the monitor widget. - - connect(mass_data_integrator_task_p, - static_cast( - &MassDataIntegratorTask::finishedIntegratingDataSignal), - task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::taskFinished, - Qt::QueuedConnection); - - // If the user clicks the cancel button, relay the signal to the loader. - connect(task_monitor_composite_widget_p, - &TaskMonitorCompositeWidget::cancelTaskSignal, - mass_data_integrator_p, - &MassDataIntegrator::cancelOperation); - - // We need to register the meta type for std::size_t because otherwise it - // cannot be shipped though signals. - - qRegisterMetaType("std::size_t"); - - // Now make all the connections that will allow the integrator to provide - // dynamic feedback to the user via the task monitor widget. - task_monitor_composite_widget_p->makeMassDataIntegratorConnections( - mass_data_integrator_p); - - // qDebug() << "going to emit integrateToMzSignal with mass " - //"data integrator:" - //<< mass_data_integrator_p; - - emit integrateToRtSignal(mass_data_integrator_p); - - // We do not want to make signal/slot calls more than once. This is because - // one user might well trigger more than one integration from this window to a - // mass spectrum. Thus we do not want that *this window be still connected to - // the specific mass_data_integrator_task_p when a new integration is - // triggered. We want the signal/slot pairs to be contained to specific - // objects. Each TicXicChromTracePlotWnd::integrateToMz() call must be contained - // to a this/mass_data_integrator_task_p specific signal/slot pair. - disconnect( - this, - // SIGNAL(integrateToRtSignal(MsRunDataSetTreeMassDataIntegratorToRt *)), - static_cast( - &TicXicChromTracePlotWnd::integrateToRtSignal), - mass_data_integrator_task_p, - // SLOT(integrateToRt(MsRunDataSetTreeMassDataIntegratorToRt *))); - static_cast( - &MassDataIntegratorTask::integrateToRt)); -} - - -// Old version -void -TicXicChromTracePlotWnd::finishedIntegratingToRt( - MsRunDataSetTreeMassDataIntegratorToRt *mass_data_integrator_p, - QCPAbstractPlottable *parent_plottable_p) -{ - // This function is actually a slot that is called when the integration - // is terminated in a QThread. - - // qDebug() << "the integrator pointer:" << mass_data_integrator_p; - - // We get back the integrator that was made to work in another thread. Now get - // the obtained data and work with them. - - // Store the MsRunDataSetSPtr for later use before deleting the integrattor. - - MsRunDataSetCstSPtr ms_run_data_set_csp = - mass_data_integrator_p->getMsRunDataSet(); - - pappso::Trace integrated_trace = - mass_data_integrator_p->getMapTrace().toTrace(); - // qDebug() << "mass spectrum trace size:" << integrated_trace.size(); - - if(!integrated_trace.size()) - { - qDebug() << "There is not a single point in the integrated trace."; - - return; - } - - // Also, do not forget to copy the processing flow from the integrator. This - // processing flow will be set into the plot widget ! - - ProcessingFlow processing_flow = mass_data_integrator_p->getProcessingFlow(); - - // Sanity check - if(ms_run_data_set_csp != processing_flow.getMsRunDataSetCstSPtr()) - qFatal("Cannot be that the ms run data set pointers be different."); - - // Finally, do not forget that we need to delete the integrator now that the - // calculation is finished. - delete mass_data_integrator_p; - mass_data_integrator_p = nullptr; - - // At this point, we need to get a color for the plot. That color needs to be - // that of the parent. - QColor plot_color = parent_plottable_p->pen().color(); - - // We need to establish what widget is the destination of the integration. If - // one or more than a widget is/are pinned-down, then that/these should be the - // destinations. If no widget is pinned-down, then a new plot widget needs to - // be created. - - std::vector pinned_down_widgets = - pinnedDownWidgets(); - - if(pinned_down_widgets.size()) - { - for(auto &&pinned_down_widget : pinned_down_widgets) - static_cast(pinned_down_widget) - ->addTrace(integrated_trace, - static_cast(parent_plottable_p), - ms_run_data_set_csp, - ms_run_data_set_csp->getMsRunId()->getSampleName(), - processing_flow, - plot_color); - } - else - addTracePlot(integrated_trace, - ms_run_data_set_csp, - processing_flow, - plot_color, - static_cast(parent_plottable_p)); - - // At this point, if the window is really not visible, then show it, otherwise - // I was told that the user does not think that they can ask for the window to - // show up in the main program window. - - if(!isVisible()) - { - showWindow(); - } -} -#endif void TicXicChromTracePlotWnd::integrateToRt( @@ -498,9 +261,6 @@ qualified_mass_spectra_sp, const ProcessingFlow &processing_flow) { - //qDebug().noquote() << "Integrating to RT with processing flow:" - //<< processing_flow.toString(); - // Get the ms run data set that for the graph we are going to base the // integration on. MsRunDataSetCstSPtr ms_run_data_set_csp = @@ -508,28 +268,41 @@ if(ms_run_data_set_csp == nullptr) qFatal("Cannot be that the pointer is nullptr."); - // We will try to limit the number of mass spectra to iterate through with the - // integration visitor. + // FIXME: BEGIN Sanity check that might be removed when the program is + // stabilized. + std::pair range_pair; - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); - - bool integration_rt = processing_flow.innermostRtRange(start_rt, end_rt); + bool integration_rt = processing_flow.innermostRange("ANY_RT", range_pair); if(!integration_rt) qFatal("Programming error."); - // First prepare a vector of QualifiedMassSpectrumCstSPtr + qDebug() << qSetRealNumberPrecision(10) << "Innermost RT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + + bool integration_dt = processing_flow.innermostRange("ANY_DT", range_pair); + + if(integration_dt) + qDebug() << qSetRealNumberPrecision(10) << "Innermost DT range:" + << "for y axis: " << range_pair.first << "-" << range_pair.second; + // FIXME: END Sanity check that might be removed when the program is + // stabilized. + + // First prepare a vector of QualifiedMassSpectrumCstSPtr. If the + // qualified_mass_spectra_sp is not empty, the + // fillInQualifiedMassSpectraVector() function below does not change the + // vector and returns its size. std::size_t qualified_mass_spectra_count = fillInQualifiedMassSpectraVector( ms_run_data_set_csp, qualified_mass_spectra_sp, processing_flow); + qDebug() + << "The number of selected mass spectra on the basis of rough RT/DT values:" + << qualified_mass_spectra_count; + if(!qualified_mass_spectra_count) return; - //qDebug() << "The number of remaining mass spectra:" - //<< qualified_mass_spectra_count; - // Now start the actual integration work. // Allocate a mass data integrator to integrate the data. @@ -538,7 +311,8 @@ new QualifiedMassSpectrumVectorMassDataIntegratorToRt( ms_run_data_set_csp, processing_flow, qualified_mass_spectra_sp); - mass_data_integrator_p->setMaxThreadUseCount(mp_programWindow->getMaxThreadUseCount()); + mass_data_integrator_p->setMaxThreadUseCount( + mp_programWindow->getMaxThreadUseCount()); // Ensure the mass data integrator messages are used. @@ -548,8 +322,6 @@ mp_programWindow, &ProgramWindow::logTextToConsole); - qDebug() << "Receiving processing flow:" << processing_flow.toString(); - MassDataIntegratorTask *mass_data_integrator_task_p = new MassDataIntegratorTask(); @@ -682,8 +454,6 @@ QualifiedMassSpectrumVectorMassDataIntegrator *mass_data_integrator_p, QCPAbstractPlottable *parent_plottable_p) { - qDebug(); - // This function is actually a slot that is called when the integration to mz // is terminated in a QThread. @@ -707,6 +477,34 @@ return; } + // Note that if the mass data file that was loaded contained a single mass + // spectrum, or if the integration yielded a single TIC value for a single + // retention time, then there would be no TIC. So we need to craft a fake one + // with two points: (current,TIC) and (current+1,TIC). + + if(integrated_trace.size() < 2) + { + + // This situation might be encountered when the user integration to RT: + // + // 1. a single spectrum for a given RT + // + // 2. multiple spectra for a single RT (that is, multiple specra of + // different DT values but of a single RT value). + + // In this situation the single data point that is there has x = ; + // so just create a new one with x = . + + pappso::DataPoint unique_data_point = integrated_trace.back(); + + // qDebug() << "tic trace:" << integrated_trace.toString(); + + integrated_trace.push_back( + pappso::DataPoint(unique_data_point.x + 1, unique_data_point.y)); + + // qDebug() << "tic trace:" << integrated_trace.toString(); + } + // Also, do not forget to copy the processing flow from the integrator. This // processing flow will be set into the plot widget ! @@ -807,27 +605,27 @@ void -TicXicChromTracePlotWnd::integrateToRtMz( +TicXicChromTracePlotWnd::integrateToMzRt( QCPAbstractPlottable *parent_plottable_p, const ProcessingFlow &processing_flow) { if(parent_plottable_p == nullptr) qFatal("Cannot be that pointer is nullptr."); - mp_programWindow->integrateToRtMz( + mp_programWindow->integrateToMzRt( parent_plottable_p, nullptr, processing_flow); } void -TicXicChromTracePlotWnd::integrateToRtDt( +TicXicChromTracePlotWnd::integrateToDtRt( QCPAbstractPlottable *parent_plottable_p, const ProcessingFlow &processing_flow) { if(parent_plottable_p == nullptr) qFatal("Cannot be that pointer is nullptr."); - mp_programWindow->integrateToRtDt( + mp_programWindow->integrateToDtRt( parent_plottable_p, nullptr, processing_flow); } diff -Nru minexpert2-7.4.1/src/gui/TicXicChromTracePlotWnd.hpp minexpert2-8.1.1/src/gui/TicXicChromTracePlotWnd.hpp --- minexpert2-7.4.1/src/gui/TicXicChromTracePlotWnd.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/TicXicChromTracePlotWnd.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -90,9 +90,9 @@ const ProcessingFlow &processing_flow); void integrateToDtMz(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); - void integrateToRtMz(QCPAbstractPlottable *plottable_p, + void integrateToMzRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); - void integrateToRtDt(QCPAbstractPlottable *plottable_p, + void integrateToDtRt(QCPAbstractPlottable *plottable_p, const ProcessingFlow &processing_flow); public slots: diff -Nru minexpert2-7.4.1/src/gui/ui/AboutDlg.ui minexpert2-8.1.1/src/gui/ui/AboutDlg.ui --- minexpert2-7.4.1/src/gui/ui/AboutDlg.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/AboutDlg.ui 2021-04-26 11:28:25.000000000 +0000 @@ -9,7 +9,7 @@ 0 0 - 631 + 639 786 @@ -129,8 +129,8 @@ PDF local - - :/images/icons/32x32/pdf-file-icon-32x32.png:/images/icons/32x32/pdf-file-icon-32x32.png + + :/images/svg/pdf-file-icon.svg:/images/svg/pdf-file-icon.svg @@ -151,8 +151,8 @@ PDF msXpertSuite.org file - - :/images/icons/32x32/pdf-file-icon-32x32.png:/images/icons/32x32/pdf-file-icon-32x32.png + + :/images/svg/pdf-file-icon.svg:/images/svg/pdf-file-icon.svg @@ -185,8 +185,8 @@ HTML local - - :/images/icons/32x32/html-file-icon-32x32.png:/images/icons/32x32/html-file-icon-32x32.png + + :/images/svg/html-file-icon.svg:/images/svg/html-file-icon.svg @@ -207,8 +207,8 @@ HTML msXpertSuite.org file - - :/images/icons/32x32/html-file-icon-32x32.png:/images/icons/32x32/html-file-icon-32x32.png + + :/images/svg/html-file-icon.svg:/images/svg/html-file-icon.svg @@ -284,14 +284,16 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Noto Sans'; font-size:8pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'Noto Sans, '; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:11pt;">Dear User of the </span><span style=" font-family:'Sans Serif'; font-size:11pt; font-style:italic; color:#ae0002;">mineXpert2</span><span style=" font-family:'Sans Serif'; font-size:11pt;"> software,</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:11pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:11pt; font-style:italic; color:#ae0002;">mineXpert2</span><span style=" font-family:'Sans Serif'; font-size:11pt;"> was developed as part of my work as a staff research scientist at the French national research council (Centre national de la Recherche scientifique, CNRS, France). </span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:11pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:11pt;">If </span><span style=" font-family:'Sans Serif'; font-size:11pt; font-style:italic; color:#ae0002;">mineXpert2</span><span style=" font-family:'Sans Serif'; font-size:11pt;"> is of some use to you, please, do not forget to cite the software in your publications, using the following citation: </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:11pt;">If </span><span style=" font-family:'Sans Serif'; font-size:11pt; font-style:italic; color:#ae0002;">mineXpert2</span><span style=" font-family:'Sans Serif'; font-size:11pt;"> is of some use to you, please, do not forget to cite the software in your publications, using the following citations: </span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:7pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;">Rusconi, F. mineXpert: </span><span style=" font-size:10pt; font-weight:600; color:#117e56;">Biological Mass Spectrometry Data Visualization and Mining with Full JavaScript Ability.</span><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;"> Journal of Proteome Research (ACS), 2019, </span><span style=" font-size:10pt; font-weight:600; color:#117e56;">18, 5, 2254–2259 (</span><a href="https://doi.org/10.1021/acs.jproteome.9b00099"><span style=" text-decoration: underline; color:#2980b9;">https://doi.org/10.1021/acs.jproteome.9b00099</span></a><a href="https://doi.org/10.1021/acs.jproteome.9b00099"><span style=" font-weight:600; text-decoration: underline; color:#117e56;">)</span></a><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;">.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;">Langella, O. and Rusconi, F. </span><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; font-style:italic; color:#117e56;">mineXpert2</span><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;">: Full-Depth Visualization and Exploration of MS</span><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56; vertical-align:super;">n</span><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;"> Mass Spectrometry Data</span><span style=" font-family:'Noto Sans'; font-size:10pt; font-weight:600; color:#117e56;">.</span><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;"> </span><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; font-style:italic; color:#117e56;">Journal of the American Society for Mass Spectrometry</span><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;">, 2021 </span><span style=" font-family:'Noto Sans'; font-size:10pt; font-weight:600; color:#117e56;">(</span><a href="https://doi.org/10.1021/jasms.0c00402"><span style=" text-decoration: underline; color:#0000ff;">https://doi.org/10.1021/jasms.0c00402</span></a><a href="https://doi.org/10.1021/acs.jproteome.9b00099"><span style=" font-family:'Noto Sans'; font-size:8pt; font-weight:600; text-decoration: underline; color:#117e56;">)</span></a><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;">.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:7pt;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;">Rusconi, F. mineXpert: </span><span style=" font-family:'Noto Sans'; font-size:10pt; font-weight:600; color:#117e56;">Biological Mass Spectrometry Data Visualization and Mining with Full JavaScript Ability.</span><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;"> Journal of Proteome Research (ACS), 2019, </span><span style=" font-family:'Noto Sans'; font-size:10pt; font-weight:600; color:#117e56;">18, 5, 2254–2259 (</span><a href="https://doi.org/10.1021/acs.jproteome.9b00099"><span style=" font-family:'Noto Sans'; font-size:8pt; text-decoration: underline; color:#2980b9;">https://doi.org/10.1021/acs.jproteome.9b00099</span></a><a href="https://doi.org/10.1021/acs.jproteome.9b00099"><span style=" font-family:'Noto Sans'; font-size:8pt; font-weight:600; text-decoration: underline; color:#117e56;">)</span></a><span style=" font-family:'Sans Serif'; font-size:10pt; font-weight:600; color:#117e56;">.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:11pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:11pt;">To tell me your appreciation, either positive or negative, please, send an email to maintainer@msxpertsuite.org.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:11pt;">To make feature requests, please write to request@msxpertsuite.org.</span></p> @@ -391,7 +393,7 @@ - + diff -Nru minexpert2-7.4.1/src/gui/ui/BasePlotCompositeWidget.ui minexpert2-8.1.1/src/gui/ui/BasePlotCompositeWidget.ui --- minexpert2-7.4.1/src/gui/ui/BasePlotCompositeWidget.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/BasePlotCompositeWidget.ui 2021-04-26 11:28:25.000000000 +0000 @@ -94,7 +94,7 @@ - :/images/mobile-phone-like-menu-button.svg:/images/mobile-phone-like-menu-button.svg + :/images/svg/mobile-phone-like-menu-button.svg:/images/svg/mobile-phone-like-menu-button.svg @@ -135,8 +135,8 @@ - :/images/green-pushpin-off-16x16.png - :/images/red-pushpin-on-16x16.png:/images/green-pushpin-off-16x16.png + :/images/svg/pushpin-green-off.svg + :/images/svg/pushpin-red-on.svg:/images/svg/pushpin-green-off.svg true @@ -178,7 +178,7 @@ - :/images/erase-trace-and-create-new-one-32x32.png:/images/erase-trace-and-create-new-one-32x32.png + :/images/svg/erase-trace-and-create-new-one.svg:/images/svg/erase-trace-and-create-new-one.svg @@ -240,8 +240,9 @@ - - :/images/keep-trace-and-create-new-one-32x32.png:/images/keep-trace-and-create-new-one-32x32.png + + :/images/keep-trace-and-create-new-one-32x32.png + :/images/svg/keep-trace-and-create-new-one.svg:/images/keep-trace-and-create-new-one-32x32.png @@ -294,8 +295,9 @@ - - :/images/close-trace-plot-widget.png:/images/close-trace-plot-widget.png + + :/images/close-trace-plot-widget.png + :/images/svg/close-trace-plot-widget.svg:/images/close-trace-plot-widget.png false @@ -446,7 +448,7 @@ - :/images/integrate-to-mz-pushbutton-32x32.png:/images/integrate-to-mz-pushbutton-32x32.png + :/images/svg/integrate-to-mz.svg:/images/svg/integrate-to-mz.svg @@ -490,7 +492,7 @@ - :/images/integrate-to-dt-pushbutton-32x32.png:/images/integrate-to-dt-pushbutton-32x32.png + :/images/svg/integrate-to-dt.svg:/images/svg/integrate-to-dt.svg @@ -547,7 +549,7 @@ - :/images/integrate-to-dt-mz-pushbutton-32x32.png:/images/integrate-to-dt-mz-pushbutton-32x32.png + :/images/svg/integrate-to-dt-mz.svg:/images/svg/integrate-to-dt-mz.svg @@ -591,7 +593,7 @@ - :/images/integrate-to-rt-pushbutton-32x32.png:/images/integrate-to-rt-pushbutton-32x32.png + :/images/svg/integrate-to-rt.svg:/images/svg/integrate-to-rt.svg @@ -614,7 +616,7 @@ - + 0 @@ -635,7 +637,7 @@ - :/images/integrate-to-rt-mz-pushbutton-32x32.png:/images/integrate-to-rt-mz-pushbutton-32x32.png + :/images/svg/integrate-to-mz-rt.svg:/images/svg/integrate-to-mz-rt.svg @@ -691,7 +693,7 @@ - :/images/duplicate-trace-pushbutton-32x32.png:/images/duplicate-trace-pushbutton-32x32.png + :/images/svg/duplicate-trace.svg:/images/svg/duplicate-trace.svg @@ -735,7 +737,7 @@ - :/images/integrate-to-int-pushbutton-32x32.png:/images/integrate-to-int-pushbutton-32x32.png + :/images/svg/integrate-to-int.svg:/images/svg/integrate-to-int.svg @@ -758,7 +760,7 @@ - + 0 @@ -779,7 +781,7 @@ - :/images/integrate-to-dt-rt-pushbutton-32x32.png:/images/integrate-to-dt-rt-pushbutton-32x32.png + :/images/svg/integrate-to-dt-rt.svg:/images/svg/integrate-to-dt-rt.svg diff -Nru minexpert2-7.4.1/src/gui/ui/ConsoleWnd.ui minexpert2-8.1.1/src/gui/ui/ConsoleWnd.ui --- minexpert2-7.4.1/src/gui/ui/ConsoleWnd.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/ConsoleWnd.ui 2021-04-26 11:28:25.000000000 +0000 @@ -14,7 +14,7 @@ mineXpert2 - Console - + :/images/icons/32x32/minexpert2.png:/images/icons/32x32/minexpert2.png @@ -31,7 +31,7 @@ - + diff -Nru minexpert2-7.4.1/src/gui/ui/ElementGroupBoxWidget.ui minexpert2-8.1.1/src/gui/ui/ElementGroupBoxWidget.ui --- minexpert2-7.4.1/src/gui/ui/ElementGroupBoxWidget.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/ElementGroupBoxWidget.ui 2021-04-26 11:28:25.000000000 +0000 @@ -34,7 +34,7 @@ - + 0 @@ -48,8 +48,8 @@ - - :/images/minus.svg:/images/minus.svg + + :/images/svg/remove-chemical-element.svg:/images/svg/remove-chemical-element.svg @@ -77,7 +77,7 @@ - + 0 @@ -91,13 +91,13 @@ - - :/images/plus.svg:/images/plus.svg + + :/images/svg/add-isotope.svg:/images/svg/add-isotope.svg - + 0 @@ -111,8 +111,8 @@ - - :/images/minus.svg:/images/minus.svg + + :/images/svg/remove-isotope.svg:/images/svg/remove-isotope.svg @@ -123,7 +123,7 @@ - + diff -Nru minexpert2-7.4.1/src/gui/ui/IsoSpecDlg.ui minexpert2-8.1.1/src/gui/ui/IsoSpecDlg.ui --- minexpert2-7.4.1/src/gui/ui/IsoSpecDlg.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/IsoSpecDlg.ui 2021-04-26 11:28:25.000000000 +0000 @@ -14,7 +14,7 @@ Dialog - + :/images/icons/32x32/minexpert2.png:/images/icons/32x32/minexpert2.png @@ -284,8 +284,8 @@ 0 0 - 443 - 372 + 431 + 387 @@ -364,7 +364,7 @@ - + diff -Nru minexpert2-7.4.1/src/gui/ui/MassPeakShaperDlg.ui minexpert2-8.1.1/src/gui/ui/MassPeakShaperDlg.ui --- minexpert2-7.4.1/src/gui/ui/MassPeakShaperDlg.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/MassPeakShaperDlg.ui 2021-04-26 11:28:25.000000000 +0000 @@ -6,7 +6,7 @@ 0 0 - 522 + 556 683 @@ -14,7 +14,7 @@ mineXpert2 - Peak shaper (Gaussian or Lorentzian) - + :/images/icons/32x32/minexpert2.png:/images/icons/32x32/minexpert2.png @@ -425,7 +425,7 @@ runPushButton - + diff -Nru minexpert2-7.4.1/src/gui/ui/MsRunDataSetTableViewWnd.ui minexpert2-8.1.1/src/gui/ui/MsRunDataSetTableViewWnd.ui --- minexpert2-7.4.1/src/gui/ui/MsRunDataSetTableViewWnd.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/MsRunDataSetTableViewWnd.ui 2021-04-26 11:28:25.000000000 +0000 @@ -20,7 +20,7 @@ Qt::Vertical - + @@ -295,7 +295,7 @@ - + 0 @@ -336,7 +336,7 @@ - :/images/integrate-to-mz-pushbutton-32x32.png:/images/integrate-to-mz-pushbutton-32x32.png + :/images/svg/integrate-to-mz.svg:/images/svg/integrate-to-mz.svg @@ -380,7 +380,7 @@ - :/images/integrate-to-dt-pushbutton-32x32.png:/images/integrate-to-dt-pushbutton-32x32.png + :/images/svg/integrate-to-dt.svg:/images/svg/integrate-to-dt.svg @@ -424,7 +424,7 @@ - :/images/integrate-to-rt-pushbutton-32x32.png:/images/integrate-to-rt-pushbutton-32x32.png + :/images/svg/integrate-to-rt.svg:/images/svg/integrate-to-rt.svg @@ -468,7 +468,7 @@ - :/images/integrate-to-int-pushbutton-32x32.png:/images/integrate-to-int-pushbutton-32x32.png + :/images/svg/integrate-to-int.svg:/images/svg/integrate-to-int.svg @@ -491,7 +491,7 @@ - + 0 @@ -512,7 +512,7 @@ - :/images/integrate-to-rt-mz-pushbutton-32x32.png:/images/integrate-to-rt-mz-pushbutton-32x32.png + :/images/svg/integrate-to-mz-rt.svg:/images/svg/integrate-to-mz-rt.svg @@ -556,7 +556,7 @@ - :/images/integrate-to-dt-mz-pushbutton-32x32.png:/images/integrate-to-dt-mz-pushbutton-32x32.png + :/images/svg/integrate-to-dt-mz.svg:/images/svg/integrate-to-dt-mz.svg @@ -579,7 +579,7 @@ - + 0 @@ -600,7 +600,7 @@ - :/images/integrate-to-dt-rt-pushbutton-32x32.png:/images/integrate-to-dt-rt-pushbutton-32x32.png + :/images/svg/integrate-to-dt-rt.svg:/images/svg/integrate-to-dt-rt.svg @@ -640,7 +640,7 @@ 0 0 785 - 28 + 22 diff -Nru minexpert2-7.4.1/src/gui/ui/OpenMsRunDataSetsDlg.ui minexpert2-8.1.1/src/gui/ui/OpenMsRunDataSetsDlg.ui --- minexpert2-7.4.1/src/gui/ui/OpenMsRunDataSetsDlg.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/OpenMsRunDataSetsDlg.ui 2021-04-26 11:28:25.000000000 +0000 @@ -73,7 +73,7 @@ - :/images/mobile-phone-like-menu-button.svg:/images/mobile-phone-like-menu-button.svg + :/images/svg/mobile-phone-like-menu-button.svg:/images/svg/mobile-phone-like-menu-button.svg diff -Nru minexpert2-7.4.1/src/gui/ui/SaveToGraphicsFileDlg.ui minexpert2-8.1.1/src/gui/ui/SaveToGraphicsFileDlg.ui --- minexpert2-7.4.1/src/gui/ui/SaveToGraphicsFileDlg.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/SaveToGraphicsFileDlg.ui 2021-04-26 11:28:25.000000000 +0000 @@ -6,7 +6,7 @@ 0 0 - 407 + 419 474 @@ -20,7 +20,7 @@ mineXpert2 - save to graphics file - + :/images/icons/32x32/minexpert2.png:/images/icons/32x32/minexpert2.png @@ -275,7 +275,7 @@ fileNameLineEdit - + diff -Nru minexpert2-7.4.1/src/gui/ui/TaskMonitorCompositeWidget.ui minexpert2-8.1.1/src/gui/ui/TaskMonitorCompositeWidget.ui --- minexpert2-7.4.1/src/gui/ui/TaskMonitorCompositeWidget.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/TaskMonitorCompositeWidget.ui 2021-04-26 11:28:25.000000000 +0000 @@ -78,8 +78,8 @@ - - :/images/red-cross-cancel.png:/images/red-cross-cancel.png + + :/images/svg/red-cross-cancel.svg:/images/svg/red-cross-cancel.svg @@ -94,7 +94,7 @@ - + diff -Nru minexpert2-7.4.1/src/gui/ui/TaskMonitorWnd.ui minexpert2-8.1.1/src/gui/ui/TaskMonitorWnd.ui --- minexpert2-7.4.1/src/gui/ui/TaskMonitorWnd.ui 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/ui/TaskMonitorWnd.ui 2021-04-26 11:28:25.000000000 +0000 @@ -6,8 +6,8 @@ 0 0 - 800 - 600 + 531 + 425 @@ -27,8 +27,8 @@ 0 0 - 782 - 533 + 509 + 359 @@ -62,8 +62,8 @@ 0 0 - 800 - 28 + 531 + 22 diff -Nru minexpert2-7.4.1/src/gui/XicExtractionWnd.cpp minexpert2-8.1.1/src/gui/XicExtractionWnd.cpp --- minexpert2-7.4.1/src/gui/XicExtractionWnd.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/gui/XicExtractionWnd.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -160,8 +160,8 @@ double delta = mp_precision->delta(mz); - double mzStart = mz - delta; - double mzEnd = mz + delta; + double mz_start = mz - delta; + double mz_end = mz + delta; // At this point, get the list of all the mass data files that have their // item selected in the OpenSpectraDlg window. @@ -179,25 +179,47 @@ return; } + // Craft a 2D selection polygon that will be used to specify the RT and MZ + // ranges. + + pappso::SelectionPolygon selection_polygon; + for(auto &&ms_run_data_set_csp : vector_of_ms_run_data_set_csp) { ProcessingFlow processing_flow(ms_run_data_set_csp); - ProcessingStep *processing_step_p = new ProcessingStep; + ProcessingStep *processing_step_p = new ProcessingStep(); - ProcessingSpec *processing_spec_p = new ProcessingSpec(mzStart, mzEnd); + processing_step_p->setSrcProcessingType(pappso::Axis::x, "RT"); + processing_step_p->setSrcProcessingType(pappso::Axis::y, "DATA_XIC_MZ"); - processing_step_p->newSpec("MZ_TO_ANY", processing_spec_p); + processing_step_p->setDataKind(pappso::Axis::x, pappso::DataKind::rt); + processing_step_p->setDataKind(pappso::Axis::y, pappso::DataKind::mz); - processing_flow.push_back(processing_step_p); + double rt_start = ms_run_data_set_csp->getMsRunDataSetTreeCstSPtr() + ->getRootNodes() + .front() + ->getQualifiedMassSpectrum() + ->getRtInMinutes(); + double rt_end = ms_run_data_set_csp->getMsRunDataSetTreeCstSPtr() + ->getRootNodes() + .back() + ->getQualifiedMassSpectrum() + ->getRtInMinutes(); + + // Craft the selection polygon as a 2D rectangle with x:RT and y:MZ. + selection_polygon.set2D(QPointF(rt_start, mz_end), + QPointF(rt_end, mz_end), + QPointF(rt_end, mz_start), + QPointF(rt_start, mz_start)); - processing_spec_p = new ProcessingSpec(); + processing_step_p->setDestProcessingType("RT"); - processing_step_p->newSpec("DATA_TO_RT", processing_spec_p); + processing_step_p->setSelectionPolygon(selection_polygon); processing_flow.push_back(processing_step_p); - mp_programWindow->xicIntegrationToRt(processing_flow); + mp_programWindow->integrateToRt(nullptr, nullptr, processing_flow); } return; diff -Nru minexpert2-7.4.1/src/nongui/BaseMsRunDataSetTreeNodeVisitor.cpp minexpert2-8.1.1/src/nongui/BaseMsRunDataSetTreeNodeVisitor.cpp --- minexpert2-7.4.1/src/nongui/BaseMsRunDataSetTreeNodeVisitor.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/BaseMsRunDataSetTreeNodeVisitor.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -43,6 +43,8 @@ /////////////////////// Local includes #include "BaseMsRunDataSetTreeNodeVisitor.hpp" +#include "ProcessingStep.hpp" +#include namespace msxps @@ -56,7 +58,8 @@ const ProcessingFlow &processing_flow) : mcsp_msRunDataSet(ms_run_data_set_csp), m_processingFlow(processing_flow) { - // qDebug() << "Processing flow has" << m_processingFlow.size() << "steps"; + // qDebug() << "Going to call setInnermostRanges()."; + setInnermostRanges(); } @@ -65,12 +68,12 @@ : QObject(), mcsp_msRunDataSet(other.mcsp_msRunDataSet), m_processingFlow(other.m_processingFlow), - m_limitMzRangeStart(other.m_limitMzRangeStart), - m_limitMzRangeEnd(other.m_limitMzRangeEnd) + m_dtRange(other.m_dtRange), + m_mzRange(other.m_mzRange), + m_rtRange(other.m_rtRange) { } - BaseMsRunDataSetTreeNodeVisitor::~BaseMsRunDataSetTreeNodeVisitor() { } @@ -81,35 +84,9 @@ const ProcessingFlow &processing_flow) { m_processingFlow = processing_flow; -} - -void -BaseMsRunDataSetTreeNodeVisitor::setLimitMzRangeStart( - double limit_mz_range_start) -{ - m_limitMzRangeStart = limit_mz_range_start; -} - - -double -BaseMsRunDataSetTreeNodeVisitor::getLimitMzRangeStart() const -{ - return m_limitMzRangeStart; -} - - -void -BaseMsRunDataSetTreeNodeVisitor::setLimitMzRangeEnd(double limit_mz_range_end) -{ - m_limitMzRangeEnd = limit_mz_range_end; -} - - -double -BaseMsRunDataSetTreeNodeVisitor::getLimitMzRangeEnd() const -{ - return m_limitMzRangeEnd; + // qDebug() << "Going to call setInnermostRanges()."; + setInnermostRanges(); } @@ -123,8 +100,9 @@ mcsp_msRunDataSet = other.mcsp_msRunDataSet; m_processingFlow = other.m_processingFlow; - m_limitMzRangeStart = other.m_limitMzRangeStart; - m_limitMzRangeEnd = other.m_limitMzRangeEnd; + m_dtRange = other.m_dtRange; + m_rtRange = other.m_rtRange; + m_mzRange = other.m_mzRange; return *this; } @@ -161,15 +139,16 @@ } if(qualified_mass_spectrum_csp == nullptr) - qFatal("QualifiedMassSpectrum cannot be nullptr."); - - //qDebug() << "Retention time is:" << qualified_mass_spectrum_csp->getRtInMinutes(); - - // In some cases this might happen, for example with the Leptocheline_MS3_DDA_IT_1.mzml - // test file. - - //if(!qualified_mass_spectrum_csp->size()) - //qFatal("The qualified mass spectrum is empty (size is 0)."); + qFatal("QualifiedMassSpectrum cannot be nullptr."); + + // qDebug() << "Retention time is:" << + // qualified_mass_spectrum_csp->getRtInMinutes(); + + // In some cases this might happen, for example with the + // Leptocheline_MS3_DDA_IT_1.mzml test file. + + // if(!qualified_mass_spectrum_csp->size()) + // qFatal("The qualified mass spectrum is empty (size is 0)."); return qualified_mass_spectrum_csp; } @@ -177,33 +156,30 @@ bool BaseMsRunDataSetTreeNodeVisitor::checkMsLevel( - const pappso::MsRunDataSetTreeNode &node) + pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) { - // Immediately get a pointer to the qualified mass spectrum that is stored - // in the node. + if(qualified_mass_spectrum_csp == nullptr) + qFatal("Cannot be nullptr"); + if(qualified_mass_spectrum_csp.get() == nullptr) + qFatal("Cannot be nullptr"); - // qDebug().noquote() << "Visiting node:" << &node << "text format:" << - // node.toString() - //<< "with quaified mass spectrum:" - //<< node.getQualifiedMassSpectrum()->toString(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); + //qDebug().noquote() << "Checking MS level for qualified mass spectrum:" + //<< qualified_mass_spectrum_csp->toString(); uint spectrum_ms_level = qualified_mass_spectrum_csp->getMsLevel(); - // qDebug().noquote() << "Current mass spectrum has ms level:" - //<< spectrum_ms_level; + //qDebug().noquote() << "Current mass spectrum has ms level:" + //<< spectrum_ms_level; // Get the greatest MS level that is requested amongst all the steps/specs in // the processing flow. We are not going going to accept a mass spectrum with // a differing MS level. - size_t greatest_ms_level = m_processingFlow.greatestMsLevel(); + std::size_t greatest_ms_level = m_processingFlow.greatestMsLevel(); - // qDebug().noquote() << "Greatest ms level in the processing flow:" - //<< greatest_ms_level; + //qDebug().noquote() << "Greatest ms level in the processing flow:" + //<< greatest_ms_level; // Check if the mass spectrum matches the requirement about the MS level. Note // that if the greatest MS level is 0, then we account for all data because @@ -214,23 +190,179 @@ { if(spectrum_ms_level != greatest_ms_level) { - // qDebug().noquote() - //<< "Spectrum ms level:" << spectrum_ms_level - //<< "does *not* match greatestest ms level:" << greatest_ms_level; + //qDebug().noquote() + //<< "Spectrum ms level:" << spectrum_ms_level + //<< "does *not* match greatestest ms level (returning false):" + //<< greatest_ms_level; return false; } else { - // qDebug().noquote() - //<< "Spectrum ms level:" << spectrum_ms_level - //<< "*does* match greatestest ms level:" << greatest_ms_level; + //qDebug().noquote() + //<< "Spectrum ms level:" << spectrum_ms_level + //<< "*does* match greatest ms level:" << greatest_ms_level; } } + //else + //{ + //qDebug() << "The greatest ms level is 0, accounting all the spectra."; + //// Just go on, we do take into consideration any MS level. + //} + + //qDebug() << "Returning true."; + + return true; +} + + +void +BaseMsRunDataSetTreeNodeVisitor::setInnermostRanges() +{ + // qDebug(); + + std::pair range_pair; + + // The RT_TO_ANY processing type mask is the most generic mask involving RT + // data, that encompasses both the 1D RT_ONLY_TO_ANY, but also the 2D + // XX_RT_TO_ANY types. + + // There are two situations: + // + // 1. when the processing step has a source type that matches the ANY_RT mask + // is 1D, then we only are interested in the innermost RT range values. + + // 2. when the processing step is 2D, that is, the selection polygon is + // rectangle, if any one of the source types matches the mask, then the + // correct selection polygon axis range is used. + + // No that when asking that relevant 2D steps be stored in the vector + // m_innermostSteps2D, we specify two options: + // + // 1. That 2D steps be stored *only*. 2. That only 2D steps that have a + // skewed selection polygon be stored. This option is easily understood: if a + // rectangle is squared, then it is fully described using two ranges, one + // range for one axis and another range for the other axis. Only skewed + // selection polygons are a challenge for the analysis of the data. The + // checkXxRange() functions do monitor the m_innermostSteps2D vector for + // skewed selection polygon rectangles. + + m_dtRange.first = std::numeric_limits::quiet_NaN(); + m_dtRange.second = std::numeric_limits::quiet_NaN(); + + // true: only 2D steps + // true: only skewed 2D steps + if(m_processingFlow.innermostRange("ANY_DT", range_pair)) + { + //qDebug() << "innermost DT range:" << range_pair.first << "-" + //<< range_pair.second; + + m_dtRange.first = range_pair.first; + m_dtRange.second = range_pair.second; + } + + m_mzRange.first = std::numeric_limits::quiet_NaN(); + m_mzRange.second = std::numeric_limits::quiet_NaN(); + + // true: only 2D steps + // true: only skewed 2D steps + if(m_processingFlow.innermostRange("ANY_MZ", range_pair)) + { + //qDebug() << "innermost MZ range:" << range_pair.first << "-" + //<< range_pair.second; + + m_mzRange.first = range_pair.first; + m_mzRange.second = range_pair.second; + } + + m_rtRange.first = std::numeric_limits::quiet_NaN(); + m_rtRange.second = std::numeric_limits::quiet_NaN(); + + // true: only 2D steps + // true: only skewed 2D steps + if(m_processingFlow.innermostRange("ANY_RT", range_pair)) + { + //qDebug() << "innermost RT range:" << range_pair.first << "-" + //<< range_pair.second; + + m_rtRange.first = range_pair.first; + m_rtRange.second = range_pair.second; + } + // Sanity check. + // It it not possible that not a single step provides a range for RT, given + // that such a range should have been created upon reading the data from the + // disk followed by the computation of the TIC chromatogram. else { - // qDebug() << "The greatest ms level is 0, accounting all the spectra."; - // Just go on, we do take into consideration any MS level. + qFatal( + "Programming error. Not possible that a processing flow has not a " + "single step with a retention range-specifying step."); + } +} + + +bool +BaseMsRunDataSetTreeNodeVisitor::checkDtRange( + pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) +{ + // qDebug(); + + // We are asked to check if the mass spectrum matches the DT range. This + // means that we can quickly check that agains all DT range that was + // determined during the construction time of this integrator. + + // Attention, all this is useful only if the processing flow was seen + // containings steps involving the DT data kind. + + if(std::isnan(m_dtRange.first) || std::isnan(m_dtRange.second)) + { + // There is no DT range data, which means DT is not a criterion to + // filter mass spectra. Return true so that the mass spectrum is + // accounted for. + return true; + } + + double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); + + // qDebug() << qSetRealNumberPrecision(10) << "dt range:" << m_dtRange.first + //<< "-" << m_dtRange.second << "The mass spectrum dt value:" << dt; + + if(dt == -1) + { + // There is no DT range data in the mass spectrum, which means DT cannot + // be a criterion to filter mass spectra. Return true so that the mass + // spectrum is accounted for. + return true; + } + + if(!(dt >= m_dtRange.first && dt <= m_dtRange.second)) + { + //qDebug() << "Returning false on the check of the dt range."; + return false; + } + + return true; +} + + +bool +BaseMsRunDataSetTreeNodeVisitor::checkRtRange( + pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) +{ + // qDebug(); + + // We are asked to check if the mass spectrum matches the RT range. This + // means that we can quickly check that agains all RT range that was + // determined during the construction time of this integrator. + + double rt = qualified_mass_spectrum_csp->getRtInMinutes(); + + if(!(rt >= m_rtRange.first && rt <= m_rtRange.second)) + { + // qDebug() << "rt:" << rt << "failed to check range:" + //<< "[" << m_rtRange.first << "-" << m_rtRange.second << "]"; + + return false; } return true; diff -Nru minexpert2-7.4.1/src/nongui/BaseMsRunDataSetTreeNodeVisitor.hpp minexpert2-8.1.1/src/nongui/BaseMsRunDataSetTreeNodeVisitor.hpp --- minexpert2-7.4.1/src/nongui/BaseMsRunDataSetTreeNodeVisitor.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/BaseMsRunDataSetTreeNodeVisitor.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -82,41 +82,12 @@ void setProcessingFlow(const ProcessingFlow &processing_flow); - void setLimitMzRangeStart(double limit_mz_range_start); - double getLimitMzRangeStart() const; - - void setLimitMzRangeEnd(double limit_mz_range_end); - double getLimitMzRangeEnd() const; - BaseMsRunDataSetTreeNodeVisitor & operator=(const BaseMsRunDataSetTreeNodeVisitor &other); virtual pappso::QualifiedMassSpectrumCstSPtr checkQualifiedMassSpectrum(const pappso::MsRunDataSetTreeNode &node); - virtual bool checkMsLevel(const pappso::MsRunDataSetTreeNode &node); - - // Pure virtual functions - virtual bool - checkProcessingStep(const ProcessingStep &step, - const pappso::MsRunDataSetTreeNode &node) = 0; - - virtual bool checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) = 0; - - virtual bool checkProcessingTypeByRt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) = 0; - - virtual bool checkProcessingTypeByMz( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) = 0; - - virtual bool checkProcessingTypeByDt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) = 0; - virtual void setNodesToProcessCount(std::size_t nodes_to_process); virtual bool shouldStop() const; virtual void silenceFeedback(bool silence_feedback = false); @@ -144,14 +115,29 @@ protected: MsRunDataSetCstSPtr mcsp_msRunDataSet; ProcessingFlow m_processingFlow; + + std::pair m_dtRange = + std::pair(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); + std::pair m_mzRange = + std::pair(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); + std::pair m_rtRange = + std::pair(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); + + virtual void setInnermostRanges(); + + virtual bool checkMsLevel(pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); + + virtual bool checkRtRange( + pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); + + virtual bool checkDtRange( + pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); + bool m_isOperationCancelled = false; bool m_isProgressFeedbackSilenced = false; - - // We almost systematically need these m/z range values when making visits: - // one criterium might be that the m/z value of data points (the x member of - // DataPoint) be contained within the limit m/z range. - double m_limitMzRangeStart = std::numeric_limits::max(); - double m_limitMzRangeEnd = std::numeric_limits::max(); }; diff -Nru minexpert2-7.4.1/src/nongui/DriftSpectrumTreeNodeCombinerVisitor.cpp minexpert2-8.1.1/src/nongui/DriftSpectrumTreeNodeCombinerVisitor.cpp --- minexpert2-7.4.1/src/nongui/DriftSpectrumTreeNodeCombinerVisitor.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/DriftSpectrumTreeNodeCombinerVisitor.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -164,16 +164,8 @@ for(auto &&step : m_processingFlow) { - if(checkProcessingStep(*step, node)) - { - // qDebug() << "The node matches the iterated step."; - } - else - { - // qDebug() << "The node does not match the iterated step."; - - return false; - } + if(!checkProcessingStep(*step, node)) + return false; } // qDebug() << "The qualified mass spectrum:" @@ -224,250 +216,6 @@ return true; } - - -bool -DriftSpectrumTreeNodeCombinerVisitor::checkProcessingStep( - const ProcessingStep &step, const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // A processing step is a collection of mapped items: - // std::map m_processingTypeSpecMap; - // - // For each item, we need to check if the node matches the spec. - - for(auto &&pair : step.getProcessingTypeSpecMap()) - { - if(checkProcessingSpec(pair, node)) - { - // qDebug() << "The node matches the iterated spec."; - } - else - { - // qDebug() << "The node does not match the iterated - // spec."; - - return false; - } - } - - return true; -} - - -bool -DriftSpectrumTreeNodeCombinerVisitor::checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // This is the most elemental component of a ProcessingFlow, so here we - // actually look into the node. - - const ProcessingSpec *spec_p = type_spec_pair.second; - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - if(qualified_mass_spectrum_csp == nullptr) - qFatal("Cannot be nullptr"); - - if(qualified_mass_spectrum_csp.get() == nullptr) - qFatal("Cannot be nullptr"); - - const MsFragmentationSpec fragmentation_spec = - spec_p->getMsFragmentationSpec(); - - if(fragmentation_spec.isValid()) - { - // qDebug() << "The fragmentation spec *is* valid."; - - // For each member of the MsFragmentationSpec structure, check if it is to - // be used for the check. - - - // Logically, if the currently handled mass spectrum has a ms level - // that is greater than the fragmentation spec ms level, then that - // means that it should be visited: in the process of making data - // mining, one goes from the lowest ms level to higher ms levels, so - // we need to keep the mass spectrum. At some point down the - // processing datetime, a process spec will limit the mass spectra - // that are actually validated. - - if(fragmentation_spec.getMsLevel()) - { - - if(qualified_mass_spectrum_csp->getMsLevel() >= - fragmentation_spec.getMsLevel()) - { - // qDebug() << "Node:" << &node - //<< "The ms level matches, with fragspec level:" - //<< fragmentation_spec.msLevelsToString() - //<< "and the node spectrum level:" - //<< qualified_mass_spectrum_csp->getMsLevel(); - } - else - { - // qDebug() << "Node:" << &node - //<< "The ms level does not match, with fragspec level:" - //<< fragmentation_spec.msLevelsToString() - //<< "and the node spectrum level:" - //<< qualified_mass_spectrum_csp->getMsLevel(); - - return false; - } - } - - if(fragmentation_spec.precursorMzValuesCount()) - { - const std::vector - &precursor_ion_data_vector = - qualified_mass_spectrum_csp->getPrecursorIonData(); - - if(!fragmentation_spec.containsMzPrecursors( - precursor_ion_data_vector)) - { - return false; - } - } - - if(fragmentation_spec.precursorSpectrumIndicesCount()) - { - if(!fragmentation_spec.containsSpectrumPrecursorIndex( - qualified_mass_spectrum_csp->getPrecursorSpectrumIndex())) - { - // qDebug() << "The precursor spectrum index does not match."; - - return false; - } - } - } - else - { - // Else, fragmentation is not a criterion for filtering data. So go on. - // qDebug() << "The fragmentation spec is *not* valid."; - } - - // qDebug() << "Frag spec ok, going on with the spec check."; - - ProcessingType type = type_spec_pair.first; - - // Because we are working on the TIC chromatogram visitor, we need to match - // the corresponding processing type that creates a TIC chromatogram right - // from the data file, apart from other processes that create a TIC chrom from - // other data settings, which in truth are called XIC chrom. - - if(type.bitMatches("RT_TO_ANY") || type.bitMatches("FILE_TO_RT")) - { - // qDebug(); - if(!checkProcessingTypeByRt(type_spec_pair, node)) - return false; - } - else if(type.bitMatches("MZ_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByMz(type_spec_pair, node)) - return false; - } - else if(type.bitMatches("FILE_TO_DT") || type.bitMatches("DT_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByDt(type_spec_pair, node)) - return false; - } - - // At this point we seem to understand that the node matched! - - return true; -} - - -bool -DriftSpectrumTreeNodeCombinerVisitor::checkProcessingTypeByRt( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(spec_p->hasValidRange()) - { - double rt = qualified_mass_spectrum_csp->getRtInMinutes(); - - if(rt >= spec_p->getStart() && rt <= spec_p->getEnd()) - { - // qDebug() << "Returning true for Rt."; - return true; - } - else - return false; - } - - return true; -} - - -bool -DriftSpectrumTreeNodeCombinerVisitor::checkProcessingTypeByMz( - const std::pair &type_spec_pair, - [[maybe_unused]] const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // Are there specs about the m/z range to be accounted for in the - // computation? - - std::pair pair(type_spec_pair); - - if(m_processingFlow.innermostMzRange(pair)) - { - m_limitMzRangeStart = pair.second->getStart(); - m_limitMzRangeEnd = pair.second->getEnd(); - } - else - { - // At this point there is no mz range-based criterion. - m_limitMzRangeStart = -1; - m_limitMzRangeEnd = -1; - } - - // Return true because we'll account that node whatever the mz range - // criterion. - - return true; -} - - -bool -DriftSpectrumTreeNodeCombinerVisitor::checkProcessingTypeByDt( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(type_spec_pair.second->hasValidRange()) - { - double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); - - if(dt >= spec_p->getStart() && dt <= spec_p->getEnd()) - return true; - else - return false; - } - - return true; -} } // namespace minexpert diff -Nru minexpert2-7.4.1/src/nongui/DriftSpectrumTreeNodeCombinerVisitor.hpp minexpert2-8.1.1/src/nongui/DriftSpectrumTreeNodeCombinerVisitor.hpp --- minexpert2-7.4.1/src/nongui/DriftSpectrumTreeNodeCombinerVisitor.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/DriftSpectrumTreeNodeCombinerVisitor.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -88,26 +88,6 @@ // Overrides the base class. virtual bool visit(const pappso::MsRunDataSetTreeNode &node) override; - virtual bool - checkProcessingStep(const ProcessingStep &step, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByRt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByMz( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByDt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - protected: pappso::MapTrace m_driftSpectrumMapTrace; }; diff -Nru minexpert2-7.4.1/src/nongui/IntensityTreeNodeCombinerVisitor.cpp minexpert2-8.1.1/src/nongui/IntensityTreeNodeCombinerVisitor.cpp --- minexpert2-7.4.1/src/nongui/IntensityTreeNodeCombinerVisitor.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/IntensityTreeNodeCombinerVisitor.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -146,15 +146,8 @@ for(auto &&step : m_processingFlow) { - if(checkProcessingStep(*step, node)) - { - // qDebug() << "The node matches the iterated step."; - } - else - { - // qDebug() << "The node does not match the iterated step."; - return false; - } + if(!checkProcessingStep(*step, node)) + return false; } // At this point we know that the current node matches all the flow's steps' @@ -220,258 +213,6 @@ return true; } - - -bool -IntensityTreeNodeCombinerVisitor::checkProcessingStep( - const ProcessingStep &step, const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // A processing step is a collection of mapped items: - // std::map m_processingTypeSpecMap; - // - // For each item, we need to check if the node matches the spec. - - for(auto &&pair : step.getProcessingTypeSpecMap()) - { - if(checkProcessingSpec(pair, node)) - { - // qDebug() << "The node matches the iterated spec."; - } - else - { - // qDebug() << "The node does not match the iterated - // spec."; - - return false; - } - } - - return true; -} - - -bool -IntensityTreeNodeCombinerVisitor::checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // This is the most elemental component of a ProcessingFlow, so here we - // actually look into the node. - - const ProcessingSpec *spec_p = type_spec_pair.second; - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - if(qualified_mass_spectrum_csp == nullptr) - qFatal("Cannot be nullptr"); - - if(qualified_mass_spectrum_csp.get() == nullptr) - qFatal("Cannot be nullptr"); - - const MsFragmentationSpec fragmentation_spec = - spec_p->getMsFragmentationSpec(); - - if(fragmentation_spec.isValid()) - { - // qDebug() << "Node:" << &node << "Spec's fragmentation spec *is* valid:" - //<< fragmentation_spec.toString(); - - // For each member of the MsFragmentationSpec structure, check if it is to - // be used for the check. - - if(fragmentation_spec.getMsLevel()) - { - // qDebug() << "Node:" << &node - //<< "The fragmentation spec has ms levels."; - - // Logically, if the currently handled mass spectrum has a ms level - // that is greater than the fragmentation spec ms level, then that - // means that it should be visited: in the process of making data - // mining, one goes from the lowest ms level to higher ms levels, so - // we need to keep the mass spectrum. At some point down the - // processing datetime, a process spec will limit the mass spectra - // that are actually validated. - - if(qualified_mass_spectrum_csp->getMsLevel() >= - fragmentation_spec.getMsLevel()) - { - // qDebug() << "Node:" << &node - //<< "The ms level matches, with fragspec level:" - //<< fragmentation_spec.msLevelsToString() - //<< "and the node spectrum level:" - //<< qualified_mass_spectrum_csp->getMsLevel(); - } - else - { - // qDebug() << "Node:" << &node - //<< "The ms level does not match, with fragspec level:" - //<< fragmentation_spec.msLevelsToString() - //<< "and the node spectrum level:" - //<< qualified_mass_spectrum_csp->getMsLevel(); - - return false; - } - } - - if(fragmentation_spec.precursorMzValuesCount()) - { - const std::vector - &precursor_ion_data_vector = - qualified_mass_spectrum_csp->getPrecursorIonData(); - - if(!fragmentation_spec.containsMzPrecursors( - precursor_ion_data_vector)) - { - return false; - } - } - - if(fragmentation_spec.precursorSpectrumIndicesCount()) - { - if(!fragmentation_spec.containsSpectrumPrecursorIndex( - qualified_mass_spectrum_csp->getPrecursorSpectrumIndex())) - { - // qDebug() << "The precursor spectrum index does not match."; - - return false; - } - } - } - else - { - // Else, fragmentation is not a criterion for filtering data. So go on. - // qDebug() << "The fragmentation spec is *not* valid."; - } - - // qDebug() << "Frag spec ok, going on with the spec check."; - - ProcessingType type = type_spec_pair.first; - - // Because we are working on the TIC chromatogram visitor, we need to match - // the corresponding processing type that creates a TIC chromatogram right - // from the data file, apart from other processes that create a TIC chrom from - // other data settings, which in truth are called XIC chrom. - - if(type.bitMatches("RT_TO_ANY") || type.bitMatches("FILE_TO_RT")) - { - // qDebug(); - if(!checkProcessingTypeByRt(type_spec_pair, node)) - return false; - } - else if(type.bitMatches("MZ_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByMz(type_spec_pair, node)) - return false; - } - else if(type.bitMatches("DT_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByDt(type_spec_pair, node)) - return false; - } - - // At this point we seem to understand that the node matched! - - return true; -} // namespace minexpert - - -bool -IntensityTreeNodeCombinerVisitor::checkProcessingTypeByRt( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(spec_p->hasValidRange()) - { - double rt = qualified_mass_spectrum_csp->getRtInMinutes(); - - if(rt >= spec_p->getStart() && rt <= spec_p->getEnd()) - { - // qDebug() << "Returning true for Rt."; - return true; - } - else - return false; - } - - return true; -} - - -bool -IntensityTreeNodeCombinerVisitor::checkProcessingTypeByMz( - const std::pair &type_spec_pair, - [[maybe_unused]] const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // Are there specs about the m/z range to be accounted for in the - // computation? - - // Make a local copy of the type_spec_pair - std::pair local_type_spec_pair( - type_spec_pair); - - // Provide that copy for setting values in it to the function that gives the - // innmermost m/z range of all ProcessingSpec instances contained in the - // ProcessingFlow. - - if(m_processingFlow.innermostMzRange(local_type_spec_pair)) - { - m_limitMzRangeStart = local_type_spec_pair.second->getStart(); - m_limitMzRangeEnd = local_type_spec_pair.second->getEnd(); - } - else - { - // At this point there is no mz range-based criterion. - m_limitMzRangeStart = -1; - m_limitMzRangeEnd = -1; - } - - // Return true because we'll account that node whatever the mz range - // criterion. - - return true; -} - - -bool -IntensityTreeNodeCombinerVisitor::checkProcessingTypeByDt( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(spec_p->hasValidRange()) - { - double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); - - if(dt >= spec_p->getStart() && dt <= spec_p->getEnd()) - return true; - else - return false; - } - - return true; -} } // namespace minexpert diff -Nru minexpert2-7.4.1/src/nongui/IntensityTreeNodeCombinerVisitor.hpp minexpert2-8.1.1/src/nongui/IntensityTreeNodeCombinerVisitor.hpp --- minexpert2-7.4.1/src/nongui/IntensityTreeNodeCombinerVisitor.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/IntensityTreeNodeCombinerVisitor.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -89,26 +89,6 @@ // Overrides the base class. virtual bool visit(const pappso::MsRunDataSetTreeNode &node) override; - virtual bool - checkProcessingStep(const ProcessingStep &step, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByRt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByMz( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByDt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - protected: double m_ticIntensity = 0; }; diff -Nru minexpert2-7.4.1/src/nongui/MassDataIntegrator.cpp minexpert2-8.1.1/src/nongui/MassDataIntegrator.cpp --- minexpert2-7.4.1/src/nongui/MassDataIntegrator.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MassDataIntegrator.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -50,12 +50,7 @@ #include "MassDataIntegrator.hpp" #include "BaseMsRunDataSetTreeNodeVisitor.hpp" #include "TicChromTreeNodeCombinerVisitor.hpp" -#include "IntensityTreeNodeCombinerVisitor.hpp" -#include "RtDtMzColorMapsTreeNodeCombinerVisitor.hpp" -#include "TraceTreeNodeCombinerVisitor.hpp" #include "MsRunStatisticsTreeNodeVisitor.hpp" -#include "MassSpectrumTreeNodeCombinerVisitor.hpp" -#include "DriftSpectrumTreeNodeCombinerVisitor.hpp" #include "MultiTreeNodeCombinerVisitor.hpp" diff -Nru minexpert2-7.4.1/src/nongui/MassDataIntegratorTask.cpp minexpert2-8.1.1/src/nongui/MassDataIntegratorTask.cpp --- minexpert2-7.4.1/src/nongui/MassDataIntegratorTask.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MassDataIntegratorTask.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -99,7 +99,7 @@ MassDataIntegratorTask::integrateToRt( QualifiedMassSpectrumVectorMassDataIntegratorToRt *mass_data_integrator_p) { - mass_data_integrator_p->integrateToRt(); + mass_data_integrator_p->integrate(); // At this point, emit the signal that we did the job. @@ -112,28 +112,13 @@ void MassDataIntegratorTask::integrateToMz( - MsRunDataSetTreeMassDataIntegratorToMz *mass_data_integrator_p) -{ - // qDebug() << "integrating data to a mass spectrum from thread:" - //<< QThread::currentThread() - //<< "with the integrator pointer:" << mass_data_integrator_p; - - mass_data_integrator_p->integrateToMz(); - - // At this point, emit the signal that we did the job. - emit finishedIntegratingDataSignal(mass_data_integrator_p); -} - - -void -MassDataIntegratorTask::integrateToMz( QualifiedMassSpectrumVectorMassDataIntegratorToMz *mass_data_integrator_p) { // qDebug() << "integrating data to a mass spectrum from thread:" //<< QThread::currentThread() //<< "with the integrator pointer:" << mass_data_integrator_p; - mass_data_integrator_p->integrateToMz(); + mass_data_integrator_p->integrate(); // At this point, emit the signal that we did the job. @@ -146,24 +131,9 @@ void MassDataIntegratorTask::integrateToDt( - MsRunDataSetTreeMassDataIntegratorToDt *mass_data_integrator_p) -{ - // qDebug() << "integrating data to a drift spectrum from thread:" - //<< QThread::currentThread() - //<< "with the integrator pointer:" << mass_data_integrator_p; - - mass_data_integrator_p->integrateToDt(); - - // At this point, emit the signal that we did the job. - emit finishedIntegratingDataSignal(mass_data_integrator_p); -} - - -void -MassDataIntegratorTask::integrateToDt( QualifiedMassSpectrumVectorMassDataIntegratorToDt *mass_data_integrator_p) { - mass_data_integrator_p->integrateToDt(); + mass_data_integrator_p->integrate(); // At this point, emit the signal that we did the job. @@ -176,24 +146,9 @@ void MassDataIntegratorTask::integrateToTicIntensity( - MsRunDataSetTreeMassDataIntegratorToTicInt *mass_data_integrator_p) -{ - // qDebug() << "integrating data to a xic chromatogram from thread:" - //<< QThread::currentThread() - //<< "with the integrator pointer:" << mass_data_integrator_p; - - mass_data_integrator_p->integrateToTicIntensity(); - - // At this point, emit the signal that we did the job. - emit finishedIntegratingDataSignal(mass_data_integrator_p); -} - - -void -MassDataIntegratorTask::integrateToTicIntensity( QualifiedMassSpectrumVectorMassDataIntegratorToTicInt *mass_data_integrator_p) { - mass_data_integrator_p->integrateToTicIntensity(); + mass_data_integrator_p->integrate(); // At this point, emit the signal that we did the job. @@ -206,28 +161,11 @@ void MassDataIntegratorTask::integrateToDtRtMz( - MsRunDataSetTreeMassDataIntegratorToDtRtMz *mass_data_integrator_p, - pappso::DataKind data_kind) -{ - // qDebug() << "integrating data to a drift spectrum from thread:" - //<< QThread::currentThread() - //<< "with the integrator pointer:" << mass_data_integrator_p; - - mass_data_integrator_p->integrateToDtRtMz(data_kind); - - // At this point, emit the signal that we did the job. - emit finishedIntegratingDataSignal(mass_data_integrator_p); -} - - -void -MassDataIntegratorTask::integrateToDtRtMz( - QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz *mass_data_integrator_p, - pappso::DataKind data_kind) + QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz *mass_data_integrator_p) { // qDebug() << "Data kind:" << static_cast(data_kind); - mass_data_integrator_p->integrate(data_kind); + mass_data_integrator_p->integrate(); // At this point, emit the signal that we did the job. @@ -239,11 +177,10 @@ void -MassDataIntegratorTask::integrateToRtDt( - QualifiedMassSpectrumVectorMassDataIntegratorToRtDt *mass_data_integrator_p, - pappso::DataKind data_kind) +MassDataIntegratorTask::integrateToDtRt( + QualifiedMassSpectrumVectorMassDataIntegratorToRtDt *mass_data_integrator_p) { - mass_data_integrator_p->integrate(data_kind); + mass_data_integrator_p->integrate(); // qDebug() << "integrating with kind:" << static_cast(data_kind); diff -Nru minexpert2-7.4.1/src/nongui/MassDataIntegratorTask.hpp minexpert2-8.1.1/src/nongui/MassDataIntegratorTask.hpp --- minexpert2-7.4.1/src/nongui/MassDataIntegratorTask.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MassDataIntegratorTask.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -51,10 +51,6 @@ // Visitors. #include "MsRunDataSetTreeMassDataIntegratorToRt.hpp" -#include "MsRunDataSetTreeMassDataIntegratorToDt.hpp" -#include "MsRunDataSetTreeMassDataIntegratorToMz.hpp" -#include "MsRunDataSetTreeMassDataIntegratorToDtRtMz.hpp" -#include "MsRunDataSetTreeMassDataIntegratorToTicInt.hpp" // All the integrators that are based on the use of Qualified Mass Spectrum // Vector Visitors. @@ -93,37 +89,21 @@ void integrateToRt( QualifiedMassSpectrumVectorMassDataIntegratorToRt *mass_data_integrator_p); - - void - integrateToMz(MsRunDataSetTreeMassDataIntegratorToMz *mass_data_integrator_p); - void integrateToMz( QualifiedMassSpectrumVectorMassDataIntegratorToMz *mass_data_integrator_p); - void - integrateToDt(MsRunDataSetTreeMassDataIntegratorToDt *mass_data_integrator_p); - void integrateToDt( QualifiedMassSpectrumVectorMassDataIntegratorToDt *mass_data_integrator_p); - void integrateToTicIntensity( - MsRunDataSetTreeMassDataIntegratorToTicInt *mass_data_integrator_p); - void integrateToTicIntensity(QualifiedMassSpectrumVectorMassDataIntegratorToTicInt *mass_data_integrator_p); - void integrateToDtRtMz( - MsRunDataSetTreeMassDataIntegratorToDtRtMz *mass_data_integrator_p, - pappso::DataKind data_kind); - void integrateToDtRtMz(QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz - *mass_data_integrator_p, - pappso::DataKind data_kind); + *mass_data_integrator_p); - void integrateToRtDt(QualifiedMassSpectrumVectorMassDataIntegratorToRtDt - *mass_data_integrator_p, - pappso::DataKind data_kind); + void integrateToDtRt(QualifiedMassSpectrumVectorMassDataIntegratorToRtDt + *mass_data_integrator_p); signals: void diff -Nru minexpert2-7.4.1/src/nongui/MassSpectrumTreeNodeCombinerVisitor.cpp minexpert2-8.1.1/src/nongui/MassSpectrumTreeNodeCombinerVisitor.cpp --- minexpert2-7.4.1/src/nongui/MassSpectrumTreeNodeCombinerVisitor.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MassSpectrumTreeNodeCombinerVisitor.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -400,7 +400,7 @@ const ProcessingSpec *spec_p = type_spec_pair.second; - if(spec_p->hasValidRange()) + if(spec_p->hasValidOneDimensionRange()) { double rt = qualified_mass_spectrum_csp->getRtInMinutes(); @@ -431,7 +431,7 @@ const ProcessingSpec *spec_p = type_spec_pair.second; - if(spec_p->hasValidRange()) + if(spec_p->hasValidOneDimensionRange()) { // qDebug() << "Needed a m/z range filtering:" << spec_p->toString(); @@ -474,7 +474,7 @@ const ProcessingSpec *spec_p = type_spec_pair.second; - if(spec_p->hasValidRange()) + if(spec_p->hasValidOneDimensionRange()) { double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSet.cpp minexpert2-8.1.1/src/nongui/MsRunDataSet.cpp --- minexpert2-7.4.1/src/nongui/MsRunDataSet.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSet.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -346,7 +346,7 @@ //! Return mass spectrum at index \p index. pappso::QualifiedMassSpectrumCstSPtr -MsRunDataSet::massSpectrumAtIndex(std::size_t spectrum_index) +MsRunDataSet::massSpectrumAtIndex(std::size_t spectrum_index) const { pappso::MsRunDataSetTreeNode *node = msp_msRunDataSetTree->findNode(spectrum_index); diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSet.hpp minexpert2-8.1.1/src/nongui/MsRunDataSet.hpp --- minexpert2-7.4.1/src/nongui/MsRunDataSet.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSet.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -123,7 +123,7 @@ using Map = std::map; - pappso::QualifiedMassSpectrumCstSPtr massSpectrumAtIndex(std::size_t index); + pappso::QualifiedMassSpectrumCstSPtr massSpectrumAtIndex(std::size_t index) const; int size() const; diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetStats.cpp minexpert2-8.1.1/src/nongui/MsRunDataSetStats.cpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetStats.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetStats.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -360,19 +360,17 @@ const pappso::MassSpectrum &mass_spectrum) { - // qDebug(); - std::size_t mass_spectrum_size = mass_spectrum.size(); if(!mass_spectrum_size) { - // qDebug() << "The mass spectrum is empty, nothing to do, returning."; + //qDebug() << "The mass spectrum is empty, nothing to do, returning."; return; } - else - { - // qDebug() << "The mass spectrum has size:" << mass_spectrum_size; - } + //else + //{ + //qDebug() << "The mass spectrum has size:" << mass_spectrum_size; + //} // We can actually handle this spectrum, so increase the counter. ++m_spectrumCount; @@ -416,8 +414,19 @@ double last_mz = mass_spectrum.back().x; m_lastMzs.push_back(last_mz); // The maximum m/z value + + //qDebug() << "Mass spectrum's last m/z:" << last_mz; + if(last_mz > m_maxMz) - m_maxMz = last_mz; + { + //qDebug() << "Will update the precendent m_maxMz:" << m_maxMz << "value"; + m_maxMz = last_mz; + } + //else + //{ + //qDebug() << "Not changing current m_maxMz:" << m_maxMz + //<< "because last_mz:" << last_mz; + //} // The current mass spectrum has data in it, as they were loaded from file // (that is, unmodified in any way). We want to compute some of the various @@ -494,8 +503,15 @@ if(other.m_minMz < m_minMz) m_minMz = other.m_minMz; + //qDebug() << "The stats to merge have m_maxMz:" << other.m_maxMz + //<< "and the current is:" << m_maxMz; if(other.m_maxMz > m_maxMz) - m_maxMz = other.m_maxMz; + { + m_maxMz = other.m_maxMz; + + //qDebug() << "Since other.m_maxMz > m_maxMz, updated m_maxMz to:" + //<< m_maxMz; + } if(other.m_smallestMzShift < m_smallestMzShift) m_smallestMzShift = other.m_smallestMzShift; @@ -746,9 +762,9 @@ m_spectrumSizeAvg, m_spectrumSizeStdDev, m_minMz, + m_maxMz, m_firstMzAvg, m_firstMzStdDev, - m_maxMz, m_lastMzAvg, m_lastMzStdDev, m_smallestMzShift, diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDt.cpp minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDt.cpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDt.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDt.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,418 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright (C) 2009--2020 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -/////////////////////// StdLib includes -#include -#include - -/////////////////////// OpenMP include -#include - -/////////////////////// Qt includes -#include -#include - -/////////////////////// pappsomspp includes -#include - - -/////////////////////// Local includes -#include "MsRunDataSetTreeMassDataIntegratorToDt.hpp" -#include "ProcessingSpec.hpp" -#include "ProcessingStep.hpp" -#include "ProcessingType.hpp" -#include "BaseMsRunDataSetTreeNodeVisitor.hpp" -#include "TicChromTreeNodeCombinerVisitor.hpp" -#include "IntensityTreeNodeCombinerVisitor.hpp" -#include "RtDtMzColorMapsTreeNodeCombinerVisitor.hpp" -#include "TraceTreeNodeCombinerVisitor.hpp" -#include "MsRunStatisticsTreeNodeVisitor.hpp" -#include "MassSpectrumTreeNodeCombinerVisitor.hpp" -#include "DriftSpectrumTreeNodeCombinerVisitor.hpp" -#include "MultiTreeNodeCombinerVisitor.hpp" - - -int msRunDataSetTreeMassDataIntegratorToDtMetaTypeId = - qRegisterMetaType( - "msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDt"); - -int msRunDataSetTreeMassDataIntegratorToDtSPtrMetaTypeId = qRegisterMetaType< - msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDtSPtr>( - "msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDtSPtr"); - - -namespace msxps -{ -namespace minexpert -{ - - -MsRunDataSetTreeMassDataIntegratorToDt::MsRunDataSetTreeMassDataIntegratorToDt() -{ - qFatal("Cannot be that the default constructor be used."); - // qDebug() << "Allocating new integrator:" << this; -} - - -MsRunDataSetTreeMassDataIntegratorToDt::MsRunDataSetTreeMassDataIntegratorToDt( - MsRunDataSetCstSPtr ms_run_data_set_csp) - : MassDataIntegrator(ms_run_data_set_csp) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - - m_processingFlow.setMsRunDataSetCstSPtr(ms_run_data_set_csp); -} - - -MsRunDataSetTreeMassDataIntegratorToDt::MsRunDataSetTreeMassDataIntegratorToDt( - MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow) - : MassDataIntegrator(ms_run_data_set_csp, processing_flow) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - if(ms_run_data_set_csp != m_processingFlow.getMsRunDataSetCstSPtr()) - qFatal("The pointers should be identical."); -} - - -MsRunDataSetTreeMassDataIntegratorToDt::MsRunDataSetTreeMassDataIntegratorToDt( - const MsRunDataSetTreeMassDataIntegratorToDt &other) - : MassDataIntegrator(other) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - if(other.mcsp_msRunDataSet != m_processingFlow.getMsRunDataSetCstSPtr()) - qFatal("The pointers should be identical."); -} - - -MsRunDataSetTreeMassDataIntegratorToDt:: - ~MsRunDataSetTreeMassDataIntegratorToDt() -{ - // qDebug() << "Destroying integrator:" << this; -} - - -const ProcessingFlow & -MsRunDataSetTreeMassDataIntegratorToDt::getProcessingFlow() const -{ - return m_processingFlow; -} - - -void -MsRunDataSetTreeMassDataIntegratorToDt::appendProcessingStep( - ProcessingStep *processing_step_p) -{ - if(processing_step_p == nullptr) - qFatal("The pointer cannot be nullptr."); - - m_processingFlow.push_back(processing_step_p); -} - - -bool -MsRunDataSetTreeMassDataIntegratorToDt::integrateToDt() -{ - // qDebug(); - - std::chrono::system_clock::time_point chrono_start_time = - std::chrono::system_clock::now(); - - // We need to clear the map trace! - m_mapTrace.clear(); - - // We need a processing flow to work, and, in particular, a processing step - // from which to find the specifics of the calculation. The processing flow - // must have been set by the caller either at construction time or later - // before using the integrator, that is, calling this function. - - if(!m_processingFlow.size()) - qFatal("The processing flow cannot be empty. Program aborted."); - - // Get the most recent step that holds all the specifics of this integration. - const ProcessingStep *processing_step_p = m_processingFlow.mostRecentStep(); - - // Now get a list of the integration types that are stored in the step's - // map. - - std::vector processing_types = - processing_step_p->processingTypes(); - - if(!processing_types.size()) - qFatal("The processing step cannot be empty. Program aborted."); - - if(!processing_step_p->matches("ANY_TO_DT")) - qFatal("There should be one ProcessingType = ANY_TO_DT. Program aborted."); - - // Try to limit the range of MS run data set tree nodes to be iterated through - // by looking from what node to what other node we need to go to ensure that - // our integration encompasses the right RT range. - - std::vector root_nodes = - mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->getRootNodes(); - - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); - - bool integration_rt = m_processingFlow.innermostRtRange(start_rt, end_rt); - - using Iterator = std::vector::const_iterator; - using Pair = std::pair; - - Pair pair; - - Iterator begin_iterator = root_nodes.begin(); - Iterator end_iterator = root_nodes.end(); - - std::size_t node_count = 0; - - if(integration_rt) - { - pair = - mcsp_msRunDataSet->treeNodeIteratorRangeForRtRange(start_rt, end_rt); - - begin_iterator = pair.first; - end_iterator = pair.second; - - node_count = std::distance(begin_iterator, end_iterator); - - qDebug() << "node_count:" << node_count; - } - else - qDebug() << "Not integration_rt"; - - if(begin_iterator == root_nodes.end()) - { - qDebug() << "There is nothing to integrate."; - return false; - } - - // Now that we know the non-0 count of nodes to be processed: - emit setProgressBarMaxValueSignal(node_count); - - // At this point, allocate a visitor that is specific for the calculation of - // the drift spectrum. - - // But we want to parallelize the computation. - - // In the pair below, first is the ideal number of threads and second is the - // number of nodes per thread. - std::pair best_parallel_params = - bestParallelIntegrationParams(node_count); - - // qDebug() << "nodes_per_thread:" << best_parallel_params.second; - - using Iterator = std::vector::const_iterator; - - std::vector visitors; - std::vector> iterators = - calculateMsRunDataSetTreeNodeIteratorPairs(begin_iterator, - end_iterator, - best_parallel_params.first, - best_parallel_params.second); - - // For each available thread, allocate a new visitor. We also configure - // which root nodes it should handle as two (begin,end) iterators to the ms - // run data set tree. We push back the pair of iterators to the vector of - // iterators. - - for(std::size_t iter = 0; iter < iterators.size(); ++iter) - { - // qDebug() << "thread index:" << iter; - - DriftSpectrumTreeNodeCombinerVisitorSPtr visitor_sp = - std::make_shared( - mcsp_msRunDataSet, m_processingFlow); - - // We want to be able to intercept any cancellation of the operation. - - connect(this, - &MsRunDataSetTreeMassDataIntegratorToDt::cancelOperationSignal, - [visitor_sp]() { visitor_sp->cancelOperation(); }); - // visitor_sp.get(), - //&DriftSpectrumTreeNodeCombinerVisitor::cancelOperation, - // Qt::QueuedConnection); - - // The visitor gets the number of nodes to process from the data set - // tree node. Capture that number and relay it. - - connect( - visitor_sp.get(), - &DriftSpectrumTreeNodeCombinerVisitor::setProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - // qDebug() << "Should emit numberOfNodesToProcessSignal"; - emit setProgressBarMaxValueSignal(number_of_nodes_to_process); - }); - - // The visitor emits the signal to tell that the currently iterated node - // has number_of_nodes_to_process children to process. Because the visitor - // might operate in a thread and that there might be other threads - // handling other nodes, we do not consider that the - // number_of_nodes_to_process value is the total number of nodes to - // process but only the number of nodes that the visitor is handling. We - // thus update the max progress bar value by number_of_nodes_to_process. - // In a typical setting, the user of the signal is the monitoring object, - // be it a non-gui object or the TaskMonitorCompositeWidget. - connect(visitor_sp.get(), - &DriftSpectrumTreeNodeCombinerVisitor:: - incrementProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - emit incrementProgressBarMaxValueSignal( - number_of_nodes_to_process); - }); - - connect( - visitor_sp.get(), - &DriftSpectrumTreeNodeCombinerVisitor::setProgressBarCurrentValueSignal, - [this](std::size_t number_of_processed_nodes) { - // qDebug() << "Should emit setProgressBarCurrentValue"; - emit setProgressBarCurrentValueSignal(number_of_processed_nodes); - }); - - connect(visitor_sp.get(), - &DriftSpectrumTreeNodeCombinerVisitor:: - incrementProgressBarCurrentValueAndSetStatusTextSignal, - [this](std::size_t increment, QString text) { - emit incrementProgressBarCurrentValueAndSetStatusTextSignal( - increment, text); - }); - - connect(visitor_sp.get(), - &DriftSpectrumTreeNodeCombinerVisitor::setStatusTextSignal, - [this](QString text) { - // qDebug() << "Should emit text:" << text; - emit setStatusTextSignal(text); - }); - - connect(visitor_sp.get(), - &DriftSpectrumTreeNodeCombinerVisitor:: - setStatusTextAndCurrentValueSignal, - [this](QString text, std::size_t value) { - // qDebug() << "Should emit text:" << text; - emit setStatusTextAndCurrentValueSignal(text, value); - }); - - visitors.push_back(visitor_sp); - } - - // Now perform a parallel iteration in the various visitors and ask them to - // work on the matching ms run data set iterators pair. - omp_set_num_threads(visitors.size()); -#pragma omp parallel for - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - auto visitor_sp = visitors.at(iter); - - // qDebug() << "Visitor:" << visitor_sp.get() << "at index:" << iter - //<< "Executing from thread:" << QThread::currentThreadId(); - - mcsp_msRunDataSet->msp_msRunDataSetTree->accept( - *(visitor_sp.get()), - iterators.at(iter).first, - iterators.at(iter).second); - } - // End of - // #pragma omp parallel for - - // In the loop above, the m_driftSpecMapTrace object (map , - // that is, (dt, tic)) has been filled with the various TIC values for the - // different drift times. - // - // At this point we need to combine all the visitor-contained map traces - // into a single trace. We make the combination into the member MapTrace - // object. - - // qDebug() << "End of the iteration in the visitors"; - - // If the task was cancelled, the monitor widget was locked. We need to - // unlock it. - emit unlockTaskMonitorCompositeWidgetSignal(); - emit setupProgressBarSignal(0, visitors.size() - 1); - - // We might be here because the user cancelled the operation in the for loop - // above (visiting all the visitors). In this case m_isOperationCancelled is - // true. We want to set it back to false, so that the following loop is gone - // through. The user can ask that the operation be cancelled once more. But we - // want that at least the performed work be used to show the trace. - - m_isOperationCancelled = false; - - pappso::TracePlusCombiner trace_plus_combiner; - - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - if(m_isOperationCancelled) - break; - - auto &&visitor_sp = visitors.at(iter); - - // const pappso::MapTrace &map_trace = - // visitor_sp->getDriftSpectrumMapTrace(); - // qDebug() << "In the consolidating loop, iter:" << iter - //<< "with a map trace of this size : " - //<< map_trace.toTrace().size(); - - emit setStatusTextSignal( - QString("Consolidating drift spectra from thread %1").arg(iter + 1)); - - emit setProgressBarCurrentValueSignal(iter + 1); - - trace_plus_combiner.combine(m_mapTrace, - visitor_sp->getDriftSpectrumMapTrace()); - } - - // qDebug() << "The consolidated integrator map trace has size:" - //<< m_mapTrace.size(); - - // At this point, we have really combined all the traces into a single map - // trace! - - std::chrono::system_clock::time_point chrono_end_time = - std::chrono::system_clock::now(); - - QString chrono_string = pappso::Utils::chronoIntervalDebugString( - "Integration to drift spectrum took:", chrono_start_time, chrono_end_time); - - emit logTextToConsoleSignal(chrono_string); - // qDebug().noquote() << chrono_string; - - return true; -} - - -} // namespace minexpert - -} // namespace msxps diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDt.hpp minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDt.hpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDt.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDt.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright (C) 2009--2020 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -#pragma once - -/////////////////////// StdLib includes -#include - - -/////////////////////// Qt includes - - -/////////////////////// pappsomspp includes -#include - - -/////////////////////// Local includes -#include "globals.hpp" -#include "MsRunDataSet.hpp" -#include "ProcessingStep.hpp" -#include "ProcessingFlow.hpp" -#include "MassDataIntegrator.hpp" - - -namespace msxps -{ -namespace minexpert -{ - -class MsRunDataSetTreeMassDataIntegratorToDt; - -typedef std::shared_ptr - MsRunDataSetTreeMassDataIntegratorToDtSPtr; - -class MsRunDataSetTreeMassDataIntegratorToDt : public MassDataIntegrator -{ - Q_OBJECT - - public: - MsRunDataSetTreeMassDataIntegratorToDt(); - - MsRunDataSetTreeMassDataIntegratorToDt( - MsRunDataSetCstSPtr ms_run_data_set_csp); - - MsRunDataSetTreeMassDataIntegratorToDt( - MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow); - - MsRunDataSetTreeMassDataIntegratorToDt( - const MsRunDataSetTreeMassDataIntegratorToDt &other); - - virtual ~MsRunDataSetTreeMassDataIntegratorToDt(); - - const ProcessingFlow &getProcessingFlow() const; - void appendProcessingStep(ProcessingStep *processing_step_p); - - public slots: - - bool integrateToDt(); - - signals: - - protected: -}; - -} // namespace minexpert - -} // namespace msxps - -Q_DECLARE_METATYPE(msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDt) -extern int msRunDataSetTreeMassDataIntegratorToDtMetaTypeId; - -Q_DECLARE_METATYPE( - msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDtSPtr) -extern int msRunDataSetTreeMassDataIntegratorToDtSPtrMetaTypeId; diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDtRtMz.cpp minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDtRtMz.cpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDtRtMz.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDtRtMz.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,598 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright (C) 2009--2020 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -/////////////////////// StdLib includes -#include -#include - -/////////////////////// OpenMP include -#include - -/////////////////////// Qt includes -#include -#include - -/////////////////////// pappsomspp includes -#include - - -/////////////////////// Local includes -#include "MsRunDataSetTreeMassDataIntegratorToDtRtMz.hpp" -#include "ProcessingSpec.hpp" -#include "ProcessingStep.hpp" -#include "ProcessingType.hpp" -#include "BaseMsRunDataSetTreeNodeVisitor.hpp" -#include "TicChromTreeNodeCombinerVisitor.hpp" -#include "IntensityTreeNodeCombinerVisitor.hpp" -#include "RtDtMzColorMapsTreeNodeCombinerVisitor.hpp" -#include "TraceTreeNodeCombinerVisitor.hpp" -#include "MsRunStatisticsTreeNodeVisitor.hpp" -#include "MassSpectrumTreeNodeCombinerVisitor.hpp" -#include "DriftSpectrumTreeNodeCombinerVisitor.hpp" -#include "MultiTreeNodeCombinerVisitor.hpp" - - -int msRunDataSetTreeMassDataIntegratorToDtRtMzMetaTypeId = qRegisterMetaType< - msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDtRtMz>( - "msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDtRtMz"); - -int msRunDataSetTreeMassDataIntegratorToDtRtMzSPtrMetaTypeId = - qRegisterMetaType< - msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDtRtMzSPtr>( - "msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDtRtMzSPtr"); - - -namespace msxps -{ -namespace minexpert -{ - - -MsRunDataSetTreeMassDataIntegratorToDtRtMz:: - MsRunDataSetTreeMassDataIntegratorToDtRtMz() -{ - qFatal("Cannot be that the default constructor be used."); - // qDebug() << "Allocating new integrator:" << this; -} - - -MsRunDataSetTreeMassDataIntegratorToDtRtMz:: - MsRunDataSetTreeMassDataIntegratorToDtRtMz( - MsRunDataSetCstSPtr ms_run_data_set_csp) - : MassDataIntegrator(ms_run_data_set_csp) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - - m_processingFlow.setMsRunDataSetCstSPtr(ms_run_data_set_csp); -} - - -MsRunDataSetTreeMassDataIntegratorToDtRtMz:: - MsRunDataSetTreeMassDataIntegratorToDtRtMz( - MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow) - : MassDataIntegrator(ms_run_data_set_csp, processing_flow) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - if(ms_run_data_set_csp != m_processingFlow.getMsRunDataSetCstSPtr()) - qFatal("The pointers should be identical."); -} - - -MsRunDataSetTreeMassDataIntegratorToDtRtMz:: - MsRunDataSetTreeMassDataIntegratorToDtRtMz( - const MsRunDataSetTreeMassDataIntegratorToDtRtMz &other) - : MassDataIntegrator(other) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - if(other.mcsp_msRunDataSet != m_processingFlow.getMsRunDataSetCstSPtr()) - qFatal("The pointers should be identical."); -} - - -MsRunDataSetTreeMassDataIntegratorToDtRtMz:: - ~MsRunDataSetTreeMassDataIntegratorToDtRtMz() -{ - // qDebug() << "Destroying integrator:" << this; -} - -const ProcessingFlow & -MsRunDataSetTreeMassDataIntegratorToDtRtMz::getProcessingFlow() const -{ - return m_processingFlow; -} - - -void -MsRunDataSetTreeMassDataIntegratorToDtRtMz::appendProcessingStep( - ProcessingStep *processing_step_p) -{ - if(processing_step_p == nullptr) - qFatal("The pointer cannot be nullptr."); - - m_processingFlow.push_back(processing_step_p); -} - - -std::size_t -MsRunDataSetTreeMassDataIntegratorToDtRtMz::getColorMapKeyCellCount() const -{ - return m_colorMapKeyCellCount; -} - - -std::size_t -MsRunDataSetTreeMassDataIntegratorToDtRtMz::getColorMapMzCellCount() const -{ - return m_colorMapMzCellCount; -} - - -double -MsRunDataSetTreeMassDataIntegratorToDtRtMz::getColorMapMinKey() const -{ - return m_colorMapMinKey; -} - - -double -MsRunDataSetTreeMassDataIntegratorToDtRtMz::getColorMapMaxKey() const -{ - return m_colorMapMaxKey; -} - - -double -MsRunDataSetTreeMassDataIntegratorToDtRtMz::getColorMapMinMz() const -{ - return m_colorMapMinMz; -} - - -double -MsRunDataSetTreeMassDataIntegratorToDtRtMz::getColorMapMaxMz() const -{ - return m_colorMapMaxMz; -} - - -// Performs integrations to colormap data, like the dt/mz or rt/mz color maps. -bool -MsRunDataSetTreeMassDataIntegratorToDtRtMz::integrateToDtRtMz( - pappso::DataKind data_kind) -{ - // qDebug(); - - std::chrono::system_clock::time_point chrono_start_time = - std::chrono::system_clock::now(); - - // Using a shared pointer make it easy to handle the copying of the map to - // users of that map without bothering. - - if(m_doubleMapTraceMapSPtr == nullptr) - m_doubleMapTraceMapSPtr = - std::make_shared>(); - else - m_doubleMapTraceMapSPtr->clear(); - - // We need a processing flow to work, and, in particular, a processing step - // from which to find the specifics of the calculation. The processing flow - // must have been set by the caller either at construction time or later - // before using the integrator, that is, calling this function. - - if(!m_processingFlow.size()) - qFatal("The processing flow cannot be empty. Program aborted."); - - // Get the most recent step that holds all the specifics of this integration. - const ProcessingStep *processing_step_p = m_processingFlow.mostRecentStep(); - - // Now get a list of the integration types that are stored in the step's - // map. - - std::vector processing_types = - processing_step_p->processingTypes(); - - if(!processing_types.size()) - qFatal("The processing step cannot be empty. Program aborted."); - - if(data_kind == pappso::DataKind::rt) - { - if(!processing_step_p->matches("ANY_TO_RT")) - qFatal( - "There should be one ProcessingType = ANY_TO_RT. Program aborted."); - } - else if(data_kind == pappso::DataKind::dt) - { - if(!processing_step_p->matches("ANY_TO_DT")) - qFatal( - "There should be one ProcessingType = ANY_TO_DT. Program aborted."); - } - else - qFatal("Should never encounter this point."); - - // Try to limit the range of MS run data set tree nodes to be iterated through - // by looking from what node to what other node we need to go to ensure that - // our integration encompasses the right RT range. - - std::vector root_nodes = - mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->getRootNodes(); - - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); - - bool integration_rt = m_processingFlow.innermostRtRange(start_rt, end_rt); - - using Iterator = std::vector::const_iterator; - using Pair = std::pair; - - Pair pair; - - Iterator begin_iterator = root_nodes.begin(); - Iterator end_iterator = root_nodes.end(); - - std::size_t node_count = 0; - - if(integration_rt) - { - pair = - mcsp_msRunDataSet->treeNodeIteratorRangeForRtRange(start_rt, end_rt); - - begin_iterator = pair.first; - end_iterator = pair.second; - - node_count = std::distance(begin_iterator, end_iterator); - - qDebug() << "node_count:" << node_count; - } - else - qDebug() << "Not integration_rt"; - - if(begin_iterator == root_nodes.end()) - { - qDebug() << "There is nothing to integrate."; - return false; - } - - // Now that we know the non-0 count of nodes to be processed: - emit setProgressBarMaxValueSignal(node_count); - - // At this point, allocate a visitor that is specific for the calculation of - // the drift spectrum. - - // But we want to parallelize the computation. - - // In the pair below, first is the ideal number of threads and second is the - // number of nodes per thread. - std::pair best_parallel_params = - bestParallelIntegrationParams(node_count); - - // qDebug() << "nodes_per_thread:" << best_parallel_params.second; - - using Iterator = std::vector::const_iterator; - - std::vector visitors; - std::vector> iterators = - calculateMsRunDataSetTreeNodeIteratorPairs(begin_iterator, - end_iterator, - best_parallel_params.first, - best_parallel_params.second); - - // For each available thread, allocate a new visitor. We also configure - // which root nodes it should handle as two (begin,end) iterators to the ms - // run data set tree. We push back the pair of iterators to the vector of - // iterators. - - for(std::size_t iter = 0; iter < iterators.size(); ++iter) - { - // qDebug() << "thread index:" << iter; - - RtDtMzColorMapsTreeNodeCombinerVisitorSPtr visitor_sp = - std::make_shared( - mcsp_msRunDataSet, m_processingFlow, data_kind); - - // We want to be able to intercept any cancellation of the operation. - - connect( - this, - &MsRunDataSetTreeMassDataIntegratorToDtRtMz::cancelOperationSignal, - [visitor_sp]() { visitor_sp->cancelOperation(); }); - - // The visitor gets the number of nodes to process from the data set - // tree node. Capture that number and relay it. - - connect( - visitor_sp.get(), - &RtDtMzColorMapsTreeNodeCombinerVisitor::setProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - // qDebug() << "Should emit numberOfNodesToProcessSignal"; - emit setProgressBarMaxValueSignal(number_of_nodes_to_process); - }); - - // The visitor emits the signal to tell that the currently iterated node - // has number_of_nodes_to_process children to process. Because the visitor - // might operate in a thread and that there might be other threads - // handling other nodes, we do not consider that the - // number_of_nodes_to_process value is the total number of nodes to - // process but only the number of nodes that the visitor is handling. We - // thus update the max progress bar value by number_of_nodes_to_process. - // In a typical setting, the user of the signal is the monitoring object, - // be it a non-gui object or the TaskMonitorCompositeWidget. - connect(visitor_sp.get(), - &RtDtMzColorMapsTreeNodeCombinerVisitor:: - incrementProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - emit incrementProgressBarMaxValueSignal( - number_of_nodes_to_process); - }); - - connect(visitor_sp.get(), - &RtDtMzColorMapsTreeNodeCombinerVisitor:: - setProgressBarCurrentValueSignal, - [this](std::size_t number_of_processed_nodes) { - // qDebug() << "Should emit setProgressBarCurrentValue"; - emit setProgressBarCurrentValueSignal( - number_of_processed_nodes); - }); - - connect(visitor_sp.get(), - &RtDtMzColorMapsTreeNodeCombinerVisitor:: - incrementProgressBarCurrentValueAndSetStatusTextSignal, - [this](std::size_t increment, QString text) { - emit incrementProgressBarCurrentValueAndSetStatusTextSignal( - increment, text); - }); - - connect(visitor_sp.get(), - &RtDtMzColorMapsTreeNodeCombinerVisitor::setStatusTextSignal, - [this](QString text) { - // qDebug() << "Should emit text:" << text; - emit setStatusTextSignal(text); - }); - - connect(visitor_sp.get(), - &RtDtMzColorMapsTreeNodeCombinerVisitor:: - setStatusTextAndCurrentValueSignal, - [this](QString text, std::size_t value) { - // qDebug() << "Should emit text:" << text; - emit setStatusTextAndCurrentValueSignal(text, value); - }); - - visitors.push_back(visitor_sp); - } - - // Now perform a parallel iteration in the various visitors and ask them to - // work on the matching ms run data set iterators pair. - omp_set_num_threads(visitors.size()); -#pragma omp parallel for - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - auto visitor_sp = visitors.at(iter); - - // qDebug() << "Visitor:" << visitor_sp.get() << "at index:" << iter - //<< "Executing from thread:" << QThread::currentThreadId(); - - mcsp_msRunDataSet->msp_msRunDataSetTree->accept( - *(visitor_sp.get()), - iterators.at(iter).first, - iterators.at(iter).second); - } - // End of - // #pragma omp parallel for - - // At this point we need to combine all the visitor-contained map traces - // into a single trace. We make the combination into the member MapTrace - // object. - - // qDebug() << "End of the iteration in the visitors"; - - // If the task was cancelled, the monitor widget was locked. We need to - // unlock it. - emit unlockTaskMonitorCompositeWidgetSignal(); - emit setupProgressBarSignal(0, visitors.size() - 1); - - // We might be here because the user cancelled the operation in the for loop - // above (visiting all the visitors). In this case m_isOperationCancelled is - // true. We want to set it back to false, so that the following loop is gone - // through. The user can ask that the operation be cancelled once more. But we - // want that at least the performed work be used to show the trace. - - m_isOperationCancelled = false; - - pappso::TracePlusCombiner trace_plus_combiner; - - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - if(m_isOperationCancelled) - break; - - auto &&visitor_sp = visitors.at(iter); - - // Each visitor has a std::map map to relate the rt|dt - // value to a MapTrace that was the receptacle to the combinations of all - // the mass spectra by a given rt|dt value. We need to ensure that all the - // MapTrace entities by the same rt|dt value get combined together. - - // We use the member m_doubleMapTraceMapSPtr to craft the result map. - - const std::map visitor_double_map_trace_map = - visitor_sp->getDoubleMapTraceMap(); - - std::pair visitor_double_map_trace_map_pair; - - // qDebug() << "In the consolidating loop, iter:" << iter - //<< "with a map trace of this size : " - //<< visitor_double_map_trace_map.size(); - - if(visitor_sp->getDataKind() == pappso::DataKind::rt) - { - emit setStatusTextSignal( - QString( - "Consolidating retention time-mapped spectra from thread %1") - .arg(iter + 1)); - } - else if(visitor_sp->getDataKind() == pappso::DataKind::dt) - { - emit setStatusTextSignal( - QString("Consolidating drift time-mapped spectra from thread %1") - .arg(iter + 1)); - } - - emit setProgressBarCurrentValueSignal(iter + 1); - - for(auto &&visitor_double_map_trace_map_pair : - visitor_double_map_trace_map) - { - double rt_or_dt_key = visitor_double_map_trace_map_pair.first; - - // Did we already encounter a map trace map by rt_or_dt ? - - std::map::iterator - integrator_double_map_trace_map_iterator; - - integrator_double_map_trace_map_iterator = - m_doubleMapTraceMapSPtr->find(rt_or_dt_key); - - pappso::TracePlusCombiner combiner(0 /* decimal places */); - - // Tells if the key was already found in the map. - if(integrator_double_map_trace_map_iterator != - m_doubleMapTraceMapSPtr->end()) - { - // *this integrator map already contained a pair that had the key - // value == rt_or_dt_key. All we have to do is combine the new - // mass spectrum pointed to by the map value into the MapTrace - // that is pointed to by the map key. - - // Combine the new mass spectrum right into the found MapTrace. - - combiner.combine( - integrator_double_map_trace_map_iterator->second, - visitor_double_map_trace_map_pair.second.toTrace()); - } - else - { - - // No other mass spectrum was encountered by the rt_or_dt_key key. - // So we need to do all the process here. - - // Instantiate a new MapTrace in which we'll combine this and all - // the future mass spectra having been acquired at this same rt|dt - // value. - - pappso::MapTrace map_trace; - - combiner.combine( - map_trace, visitor_double_map_trace_map_pair.second.toTrace()); - - // Finally, store in the map, the map_trace along with its - // rt_or_dt_key. - - (*m_doubleMapTraceMapSPtr)[rt_or_dt_key] = map_trace; - } - } - // End of - // for(auto &&visitor_double_map_trace_map_pair : double_map_trace_map) - - // At this point we have finished processing all the items of the double - // map trace map sitting in the iterated visitor. Go on with next visitor. - } - // End of - // for(std::size_t iter = 0; iter < visitors.size(); ++iter) - - // We now need to go through the double map trace map to inspect its - // characteristics. - - if(!m_doubleMapTraceMapSPtr->size()) - { - qDebug() << "There are no data in the double maptrace map."; - - return true; - } - - m_colorMapMinKey = m_doubleMapTraceMapSPtr->begin()->first; - m_colorMapMaxKey = m_doubleMapTraceMapSPtr->rbegin()->first; - - m_colorMapKeyCellCount = m_doubleMapTraceMapSPtr->size(); - - for(auto &&pair : *m_doubleMapTraceMapSPtr) - { - pappso::MapTrace map_trace = pair.second; - - if(!map_trace.size()) - continue; - - if(map_trace.size() > m_colorMapMzCellCount) - m_colorMapMzCellCount = map_trace.size(); - - if(map_trace.begin()->first < m_colorMapMinMz) - m_colorMapMinMz = map_trace.begin()->first; - - if(map_trace.rbegin()->first > m_colorMapMaxMz) - m_colorMapMaxMz = map_trace.rbegin()->first; - } - - // At this point we have finished going through all the visitors. Our work is - // finished. The m_doubleMapTraceMap now has items for each rt|dt value - // present in the processed data. For each such value, the corresponding - // MapTrace contains the combinatorial mass spectrum of all the mass spectra - // obtained for each rt|dt value. - - std::chrono::system_clock::time_point chrono_end_time = - std::chrono::system_clock::now(); - - QString chrono_string; - - if(data_kind == pappso::DataKind::rt) - chrono_string = pappso::Utils::chronoIntervalDebugString( - "Integration to TIC/XIC chrom / mass spectrum took:", - chrono_start_time, - chrono_end_time); - else if(data_kind == pappso::DataKind::dt) - chrono_string = pappso::Utils::chronoIntervalDebugString( - "Integration to drift spectrum / mass spectrum took:", - chrono_start_time, - chrono_end_time); - - emit logTextToConsoleSignal(chrono_string); - // qDebug().noquote() << chrono_string; - - return true; -} - - -} // namespace minexpert - -} // namespace msxps diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDtRtMz.hpp minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDtRtMz.hpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDtRtMz.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToDtRtMz.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright (C) 2009--2020 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -#pragma once - -/////////////////////// StdLib includes -#include - - -/////////////////////// Qt includes - - -/////////////////////// pappsomspp includes -#include - - -/////////////////////// Local includes -#include "globals.hpp" -#include "MsRunDataSet.hpp" -#include "ProcessingStep.hpp" -#include "ProcessingFlow.hpp" -#include "MassDataIntegrator.hpp" - - -namespace msxps -{ -namespace minexpert -{ - -class MsRunDataSetTreeMassDataIntegratorToDtRtMz; - -typedef std::shared_ptr MsRunDataSetTreeMassDataIntegratorToDtRtMzSPtr; - -class MsRunDataSetTreeMassDataIntegratorToDtRtMz : public MassDataIntegrator -{ - Q_OBJECT - - public: - MsRunDataSetTreeMassDataIntegratorToDtRtMz(); - - MsRunDataSetTreeMassDataIntegratorToDtRtMz(MsRunDataSetCstSPtr ms_run_data_set_csp); - - MsRunDataSetTreeMassDataIntegratorToDtRtMz(MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow); - - MsRunDataSetTreeMassDataIntegratorToDtRtMz(const MsRunDataSetTreeMassDataIntegratorToDtRtMz &other); - - virtual ~MsRunDataSetTreeMassDataIntegratorToDtRtMz(); - - const ProcessingFlow &getProcessingFlow() const; - void appendProcessingStep(ProcessingStep *processing_step_p); - - std::size_t getColorMapKeyCellCount() const; - std::size_t getColorMapMzCellCount() const; - - double getColorMapMinKey() const; - double getColorMapMaxKey() const; - - double getColorMapMinMz() const; - double getColorMapMaxMz() const; - - - public slots: - - bool integrateToDtRtMz(pappso::DataKind data_kind); - - signals: - - protected: - std::size_t m_colorMapKeyCellCount = 0; - std::size_t m_colorMapMzCellCount = 0; - - double m_colorMapMinKey = std::numeric_limits::max(); - double m_colorMapMaxKey = std::numeric_limits::min(); - - double m_colorMapMinMz = std::numeric_limits::max(); - double m_colorMapMaxMz = std::numeric_limits::min(); -}; - -} // namespace minexpert - -} // namespace msxps - -Q_DECLARE_METATYPE(msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDtRtMz) -extern int msRunDataSetTreeMassDataIntegratorToDtRtMzMetaTypeId; - -Q_DECLARE_METATYPE(msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToDtRtMzSPtr) -extern int msRunDataSetTreeMassDataIntegratorToDtRtMzSPtrMetaTypeId; diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToMz.cpp minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToMz.cpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToMz.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToMz.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,727 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright (C) 2009--2020 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -/////////////////////// StdLib includes -#include -#include - -/////////////////////// OpenMP include -#include - -/////////////////////// Qt includes -#include -#include - -/////////////////////// pappsomspp includes -#include - - -/////////////////////// Local includes -#include "MsRunDataSetTreeMassDataIntegratorToMz.hpp" -#include "ProcessingSpec.hpp" -#include "ProcessingStep.hpp" -#include "ProcessingType.hpp" -#include "BaseMsRunDataSetTreeNodeVisitor.hpp" -#include "TicChromTreeNodeCombinerVisitor.hpp" -#include "IntensityTreeNodeCombinerVisitor.hpp" -#include "RtDtMzColorMapsTreeNodeCombinerVisitor.hpp" -#include "TraceTreeNodeCombinerVisitor.hpp" -#include "MsRunStatisticsTreeNodeVisitor.hpp" -#include "MassSpectrumTreeNodeCombinerVisitor.hpp" -#include "DriftSpectrumTreeNodeCombinerVisitor.hpp" -#include "MultiTreeNodeCombinerVisitor.hpp" - - -int msRunDataSetTreeMassDataIntegratorToMzMetaTypeId = - qRegisterMetaType( - "msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToMz"); - -int msRunDataSetTreeMassDataIntegratorToMzSPtrMetaTypeId = qRegisterMetaType< - msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToMzSPtr>( - "msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToMzSPtr"); - - -namespace msxps -{ -namespace minexpert -{ - - -MsRunDataSetTreeMassDataIntegratorToMz::MsRunDataSetTreeMassDataIntegratorToMz() -{ - qFatal("Cannot be that the default constructor be used."); - // qDebug() << "Allocating new integrator:" << this; -} - - -MsRunDataSetTreeMassDataIntegratorToMz::MsRunDataSetTreeMassDataIntegratorToMz( - MsRunDataSetCstSPtr ms_run_data_set_csp) - : MassDataIntegrator(ms_run_data_set_csp) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - - m_processingFlow.setMsRunDataSetCstSPtr(ms_run_data_set_csp); -} - - -MsRunDataSetTreeMassDataIntegratorToMz::MsRunDataSetTreeMassDataIntegratorToMz( - MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow) - : MassDataIntegrator(ms_run_data_set_csp, processing_flow) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - if(ms_run_data_set_csp != m_processingFlow.getMsRunDataSetCstSPtr()) - qFatal("The pointers should be identical."); -} - - -MsRunDataSetTreeMassDataIntegratorToMz::MsRunDataSetTreeMassDataIntegratorToMz( - const MsRunDataSetTreeMassDataIntegratorToMz &other) - : MassDataIntegrator(other) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - if(other.mcsp_msRunDataSet != m_processingFlow.getMsRunDataSetCstSPtr()) - qFatal("The pointers should be identical."); -} - - -MsRunDataSetTreeMassDataIntegratorToMz:: - ~MsRunDataSetTreeMassDataIntegratorToMz() -{ - // qDebug() << "Destroying integrator:" << this; -} - - -const ProcessingFlow & -MsRunDataSetTreeMassDataIntegratorToMz::getProcessingFlow() const -{ - return m_processingFlow; -} - - -void -MsRunDataSetTreeMassDataIntegratorToMz::appendProcessingStep( - ProcessingStep *processing_step_p) -{ - if(processing_step_p == nullptr) - qFatal("The pointer cannot be nullptr."); - - m_processingFlow.push_back(processing_step_p); -} - - -void -MsRunDataSetTreeMassDataIntegratorToMz::integrateToMz() -{ - // qDebug(); - - std::chrono::system_clock::time_point chrono_start_time = - std::chrono::system_clock::now(); - - // We need to clear the map trace! - m_mapTrace.clear(); - - // We need a processing flow to work, and, in particular, a processing step - // from which to find the specifics of the calculation. The processing flow - // must have been set by the caller either at construction time or later - // before using the integrator, that is, calling this function. - - if(!m_processingFlow.size()) - qFatal("The processing flow cannot be empty. Program aborted."); - - // Get the most recent step that holds all the specifics of this integration. - const ProcessingStep *processing_step_p = m_processingFlow.mostRecentStep(); - - // Now get a list of the integration types that are stored in the step's map. - - std::vector processing_types = - processing_step_p->processingTypes(); - - if(!processing_types.size()) - qFatal("The processing step cannot be empty. Program aborted."); - - if(!processing_step_p->matches("ANY_TO_MZ")) - qFatal("There should be one ProcessingType = ANY_TO_MZ. Program aborted."); - - // Since we are asked that an integration to a mass spectrum be performed, - // there must be a non-nullptr mz integration pointer in the step. - const pappso::MzIntegrationParams *mz_integration_params_p = - processing_step_p->getMzIntegrationParamsPtr(); - - if(mz_integration_params_p == nullptr) - qFatal("Cannot be that the pointer is nullptr."); - - // qDebug().noquote() << "Starting integration to mz with params:" - //<< mz_integration_params_p->toString(); - - // Reset the value of the nodes visited to 0. - emit setProgressBarCurrentValueSignal(0); - - emit setTaskDescriptionTextSignal( - "Computing the combination of the appropriate mass spectra"); - - if(mz_integration_params_p->getBinningType() == pappso::BinningType::NONE) - { - integrateToMzNoBinning(); - } - else if(mz_integration_params_p->getBinningType() == pappso::BinningType::ARBITRARY) - { - integrateToMzArbitraryBinning(); - } - - std::chrono::system_clock::time_point chrono_end_time = - std::chrono::system_clock::now(); - - QString chrono_string = pappso::Utils::chronoIntervalDebugString( - "Integration to mass spectrum took:", chrono_start_time, chrono_end_time); - - emit logTextToConsoleSignal(chrono_string); - // qDebug().noquote() << chrono_string; -} - - -bool -MsRunDataSetTreeMassDataIntegratorToMz::integrateToMzNoBinning() -{ - // qDebug(); - - // This function needs to be called by integrateToMz() that has setup all the - // required parameters. - - // There are a lot of verification of the current context that have been - // performed in the calling function. - - // Try to limit the range of MS run data set tree nodes to be iterated through - // by looking from what node to what other node we need to go to ensure that - // our integration encompasses the right RT range. - - std::vector root_nodes = - mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->getRootNodes(); - - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); - - bool integration_rt = m_processingFlow.innermostRtRange(start_rt, end_rt); - - using Iterator = std::vector::const_iterator; - using Pair = std::pair; - - Pair pair; - - Iterator begin_iterator = root_nodes.begin(); - Iterator end_iterator = root_nodes.end(); - - std::size_t node_count = 0; - - if(integration_rt) - { - pair = - mcsp_msRunDataSet->treeNodeIteratorRangeForRtRange(start_rt, end_rt); - - begin_iterator = pair.first; - end_iterator = pair.second; - - node_count = std::distance(begin_iterator, end_iterator); - - qDebug() << "node_count:" << node_count; - } - else - qDebug() << "Not integration_rt"; - - if(begin_iterator == root_nodes.end()) - { - qDebug() << "There is nothing to integrate."; - return false; - } - - // Now that we know the non-0 count of nodes to be processed: - emit setProgressBarMaxValueSignal(node_count); - - // At this point, allocate a visitor that is specific for the calculation of - // the mass spectrum. Since we are not binning, we can use a visitor that - // integrates to a pappso::Trace, not a pappso::MassSpectrum. - - // But we want to parallelize the computation. Se we will allocate a vector of - // visitors (as many as possible for the available processor threads), each - // visitor having a subset of the initial data to integrate. - - // In the pair below, first is the ideal number of threads and second is the - // number of nodes per thread. - std::pair best_parallel_params = - bestParallelIntegrationParams(node_count); - - // qDebug() << "nodes_per_thread:" << best_parallel_params.second; - - using Iterator = std::vector::const_iterator; - - std::vector visitors; - std::vector> iterators = - calculateMsRunDataSetTreeNodeIteratorPairs(begin_iterator, - end_iterator, - best_parallel_params.first, - best_parallel_params.second); - - // Since we are asked that an integration to a mass spectrum be performed, - // there must be a non-nullptr mz integration pointer in the most recent step. - - const pappso::MzIntegrationParams *mz_integration_params_p = - m_processingFlow.mostRecentStep()->getMzIntegrationParamsPtr(); - - if(mz_integration_params_p == nullptr) - qFatal("Cannot be that the pointer is nullptr."); - - // We use a Trace combiner because we are not going to do any binning. - pappso::TracePlusCombinerSPtr combiner_sp = - std::make_shared( - mz_integration_params_p->getDecimalPlaces()); - - // For each available thread, allocate a new visitor. We also configure which - // root nodes it should handle as two (begin,end) iterators to the ms run data - // set tree. We push back the pair of iterators to the vector of iterators. - - for(std::size_t iter = 0; iter < iterators.size(); ++iter) - { - // qDebug() << "thread index:" << iter; - - // We are using Trace combiner visitors because we are not going to use - // binning procedures during the visitor-mediated combination. - TraceTreeNodeCombinerVisitorSPtr visitor_sp = - std::make_shared( - mcsp_msRunDataSet, m_processingFlow, combiner_sp); - - // We want to be able to intercept any cancellation of the operation. - - connect(this, - &MsRunDataSetTreeMassDataIntegratorToMz::cancelOperationSignal, - [visitor_sp]() { visitor_sp->cancelOperation(); }); - // visitor_sp.get(), - //&TraceTreeNodeCombinerVisitor::cancelOperation, - // Qt::QueuedConnection); - - // The visitor gets the number of nodes to process from the data set tree - // node. This signal tells the final user of the signal to set the max - // value of the progress bar to number_of_nodes_to_process. - - connect(visitor_sp.get(), - &TraceTreeNodeCombinerVisitor::setProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - emit setProgressBarMaxValueSignal(number_of_nodes_to_process); - }); - - // The visitor emits the signal to tell that the currently iterated node - // has number_of_nodes_to_process children to process. Because the visitor - // might operate in a thread and that there might be other threads - // handling other nodes, we do not consider that the - // number_of_nodes_to_process value is the total number of nodes to - // process but only the number of nodes that the visitor is handling. We - // thus update the max progress bar value by number_of_nodes_to_process. - // In a typical setting, the user of the signal is the monitoring object, - // be it a non-gui object or the TaskMonitorCompositeWidget. - connect(visitor_sp.get(), - &TraceTreeNodeCombinerVisitor::incrementProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - emit incrementProgressBarMaxValueSignal( - number_of_nodes_to_process); - }); - - connect(visitor_sp.get(), - &TraceTreeNodeCombinerVisitor::setProgressBarCurrentValueSignal, - [this](std::size_t number_of_processed_nodes) { - emit setProgressBarCurrentValueSignal( - number_of_processed_nodes); - }); - - connect(visitor_sp.get(), - &TraceTreeNodeCombinerVisitor:: - incrementProgressBarCurrentValueAndSetStatusTextSignal, - [this](std::size_t increment, QString text) { - emit incrementProgressBarCurrentValueAndSetStatusTextSignal( - increment, text); - }); - - connect(visitor_sp.get(), - &TraceTreeNodeCombinerVisitor::setStatusTextSignal, - [this](QString text) { - // qDebug() << "Should emit text:" << text; - emit setStatusTextSignal(text); - }); - - connect(visitor_sp.get(), - &TraceTreeNodeCombinerVisitor::setStatusTextAndCurrentValueSignal, - [this](QString text, std::size_t value) { - // qDebug() << "Should emit text:" << text; - emit setStatusTextAndCurrentValueSignal(text, value); - }); - - visitors.push_back(visitor_sp); - } - - // Now perform a parallel iteration in the various visitors and ask them to - // work on the matching ms run data set iterators pair. - omp_set_num_threads(visitors.size()); -#pragma omp parallel for - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - auto visitor_sp = visitors.at(iter); - - // qDebug() << "Visitor:" << &visitor << "at index:" << iter - //<< "Executing from thread:" << QThread::currentThreadId(); - - mcsp_msRunDataSet->msp_msRunDataSetTree->accept( - *(visitor_sp.get()), - iterators.at(iter).first, - iterators.at(iter).second); - } - // End of - // #pragma omp parallel for - - // At this point, the combination for each visitor has been performed. We - // need to consolidate the various visitor's map traces into a single Trace - // that will correspond to the actual final product of the combination. - - // qDebug() << "End of the iteration in the visitors"; - - // If the task was cancelled, the monitor widget was locked. We need to - // unlock it. - emit unlockTaskMonitorCompositeWidgetSignal(); - emit setupProgressBarSignal(0, visitors.size() - 1); - - // We might be here because the user cancelled the operation in the for loop - // above (visiting all the visitors). In this case m_isOperationCancelled is - // true. We want to set it back to false, so that the following loop is gone - // through. The user can ask that the operation be cancelled once more. But we - // want that at least the performed work be used to show the trace. - - m_isOperationCancelled = false; - - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - if(m_isOperationCancelled) - break; - - auto &&visitor_sp = visitors.at(iter); - - const pappso::MapTrace &map_trace = visitor_sp->getMapTrace(); - - // qDebug() << "In the consolidating loop, iter:" << iter - //<< " with a map trace of this size : " << map_trace.size(); - - emit setStatusTextSignal( - QString("Consolidating mass spectra from thread %1").arg(iter + 1)); - - emit setProgressBarCurrentValueSignal(iter + 1); - - visitor_sp->getCombiner()->combine(m_mapTrace, map_trace.toTrace()); - } - - // qDebug() << "The consolidated integrator map trace has size:" - //<< m_mapTrace.size(); - - // At this point, we have really combined all the traces into a single map - // trace! - - return true; -} - - -bool -MsRunDataSetTreeMassDataIntegratorToMz::integrateToMzArbitraryBinning() -{ - // qDebug(); - - // This function needs to be called by integrateToMz() that has setup all the - // required parameters. - - // There are a lot of verification of the current context that have been - // performed in the calling function. - - std::vector root_nodes = - mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->getRootNodes(); - - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); - - bool integration_rt = m_processingFlow.innermostRtRange(start_rt, end_rt); - - using Iterator = std::vector::const_iterator; - using Pair = std::pair; - - Pair pair; - - Iterator begin_iterator = root_nodes.begin(); - Iterator end_iterator = root_nodes.end(); - - std::size_t node_count = 0; - - if(integration_rt) - { - pair = - mcsp_msRunDataSet->treeNodeIteratorRangeForRtRange(start_rt, end_rt); - - begin_iterator = pair.first; - end_iterator = pair.second; - - node_count = std::distance(begin_iterator, end_iterator); - - qDebug() << "node_count:" << node_count; - } - else - qDebug() << "Not integration_rt"; - - if(begin_iterator == root_nodes.end()) - { - qDebug() << "There is nothing to integrate."; - return false; - } - - // Now that we know the non-0 count of nodes to be processed: - emit setProgressBarMaxValueSignal(node_count); - - // But we want to parallelize the computation. Se we will allocate a vector of - // visitors (as many as possible for the available processor threads), each - // visitor having a subset of the initial data to integrate. - - // In the pair below, first is the ideal number of threads and second is the - // number of nodes per thread. - std::pair best_parallel_params = - bestParallelIntegrationParams(node_count); - - // qDebug() << "nodes_per_thread:" << best_parallel_params.second; - - using Iterator = std::vector::const_iterator; - - std::vector visitors; - std::vector> iterators = - calculateMsRunDataSetTreeNodeIteratorPairs(begin_iterator, - end_iterator, - best_parallel_params.first, - best_parallel_params.second); - - // Since we are asked that an integration to a mass spectrum be performed, - // there must be a non-nullptr mz integration pointer in the most recent step. - - const pappso::MzIntegrationParams *mz_integration_params_p = - m_processingFlow.mostRecentStep()->getMzIntegrationParamsPtr(); - - if(mz_integration_params_p == nullptr) - qFatal("Cannot be that the pointer is nullptr."); - - // When integrating to a mass spectrum with arbitrary binning, we first need - // to establish the bins. Create a local copy that we'll be able to modify - // before using it. - - pappso::MzIntegrationParams local_mz_integration_params = *mz_integration_params_p; - - local_mz_integration_params.setSmallestMz( - mcsp_msRunDataSet->getMsRunDataSetStats().m_minMz); - - local_mz_integration_params.setGreatestMz( - mcsp_msRunDataSet->getMsRunDataSetStats().m_maxMz); - - // qDebug().noquote() << "Starting integration with mz integration params:" - //<< local_mz_integration_params.toString(); - - // We use a MassSpectrum combiner because we are going to do binning. - pappso::MassSpectrumPlusCombinerSPtr combiner_sp = - std::make_shared( - local_mz_integration_params.getDecimalPlaces()); - - // Set the bins to the combiner by creating them according to the - // specifications in the mz integration params instance. - - std::vector bins = local_mz_integration_params.createBins(); - - // qDebug() << "The number of bins is:" << bins.size(); - - // Now set the bins into the combiner that will use them to perform the binned - // combination. - combiner_sp->setBins(bins); - - for(std::size_t iter = 0; iter < iterators.size(); ++iter) - { - // qDebug() << "thread index:" << iter; - - if(local_mz_integration_params.getBinningType() != pappso::BinningType::ARBITRARY) - qFatal("Programming error."); - - // We are using MassSpectrum combiner visitors because we are going to use - // binning procedures during the visitor-mediated combination. - MassSpectrumTreeNodeCombinerVisitorSPtr visitor_sp = - std::make_shared( - mcsp_msRunDataSet, m_processingFlow, combiner_sp); - - // We want to be able to intercept any cancellation of the operation. - - connect(this, - &MsRunDataSetTreeMassDataIntegratorToMz::cancelOperationSignal, - [visitor_sp]() { visitor_sp->cancelOperation(); }); - // visitor_sp.get(), - //&MassSpectrumTreeNodeCombinerVisitor::cancelOperation, - // Qt::QueuedConnection); - - // The visitor gets the number of nodes to process from the data set tree - // node. This signal tells the final user of the signal to set the max - // value of the progress bar to number_of_nodes_to_process. - - connect( - visitor_sp.get(), - &MassSpectrumTreeNodeCombinerVisitor::setProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - emit setProgressBarMaxValueSignal(number_of_nodes_to_process); - }); - - // The visitor emits the signal to tell that the currently iterated node - // has number_of_nodes_to_process children to process. Because the visitor - // might operate in a thread and that there might be other threads - // handling other nodes, we do not consider that the - // number_of_nodes_to_process value is the total number of nodes to - // process but only the number of nodes that the visitor is handling. We - // thus update the max progress bar value by number_of_nodes_to_process. - // In a typical setting, the user of the signal is the monitoring object, - // be it a non-gui object or the TaskMonitorCompositeWidget. - connect(visitor_sp.get(), - &MassSpectrumTreeNodeCombinerVisitor:: - incrementProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - emit incrementProgressBarMaxValueSignal( - number_of_nodes_to_process); - }); - - connect( - visitor_sp.get(), - &MassSpectrumTreeNodeCombinerVisitor::setProgressBarCurrentValueSignal, - [this](std::size_t number_of_processed_nodes) { - emit setProgressBarCurrentValueSignal(number_of_processed_nodes); - }); - - connect(visitor_sp.get(), - &MassSpectrumTreeNodeCombinerVisitor:: - incrementProgressBarCurrentValueAndSetStatusTextSignal, - [this](std::size_t increment, QString text) { - emit incrementProgressBarCurrentValueAndSetStatusTextSignal( - increment, text); - }); - - connect(visitor_sp.get(), - &MassSpectrumTreeNodeCombinerVisitor::setStatusTextSignal, - [this](QString text) { - // qDebug() << "Should emit text:" << text; - emit setStatusTextSignal(text); - }); - - connect(visitor_sp.get(), - &MassSpectrumTreeNodeCombinerVisitor:: - setStatusTextAndCurrentValueSignal, - [this](QString text, std::size_t value) { - // qDebug() << "Should emit text:" << text; - emit setStatusTextAndCurrentValueSignal(text, value); - }); - - visitors.push_back(visitor_sp); - } - - // Now perform a parallel iteration in the various visitors and ask them to - // work on the matching ms run data set iterators pair. - omp_set_num_threads(visitors.size()); -#pragma omp parallel for - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - auto visitor_sp = visitors.at(iter); - - // qDebug() << "Visitor:" << visitor_sp.get() << "at index:" << iter - //<< "Executing from thread:" << QThread::currentThreadId(); - - mcsp_msRunDataSet->msp_msRunDataSetTree->accept( - *(visitor_sp.get()), - iterators.at(iter).first, - iterators.at(iter).second); - } - // End of - // #pragma omp parallel for - - // At this point, the combination for each visitor has been performed. We - // need to consolidate the various visitor's map traces into a single - // Trace that will correspond to the actual final product of the - // combination. - - // qDebug() << "End of the iteration in the visitors"; - - // If the task was cancelled, the monitor widget was locked. We need to - // unlock it. - emit unlockTaskMonitorCompositeWidgetSignal(); - emit setupProgressBarSignal(0, visitors.size() - 1); - - // We might be here because the user cancelled the operation in the for loop - // above (visiting all the visitors). In this case m_isOperationCancelled is - // true. We want to set it back to false, so that the following loop is gone - // through. The user can ask that the operation be cancelled once more. But we - // want that at least the performed work be used to show the trace. - - m_isOperationCancelled = false; - - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - if(m_isOperationCancelled) - break; - - auto &&visitor_sp = visitors.at(iter); - - const pappso::MapTrace &map_trace = visitor_sp->getMapTrace(); - - // qDebug() << "In the consolidating loop, iter:" << iter - //<< " with a map trace of this size : " << map_trace.size(); - - emit setStatusTextSignal( - QString("Consolidating mass spectra from thread %1").arg(iter + 1)); - - emit setProgressBarCurrentValueSignal(iter + 1); - - visitor_sp->getCombiner()->combine(m_mapTrace, map_trace.toTrace()); - } - - // qDebug() << "The consolidated integrator map trace has size:" - //<< m_mapTrace.size(); - - // At this point, we have really combined all the traces into a single map - // trace! - - return true; -} - - -} // namespace minexpert - -} // namespace msxps diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToMz.hpp minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToMz.hpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToMz.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToMz.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright (C) 2009--2020 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -#pragma once - -/////////////////////// StdLib includes -#include - - -/////////////////////// Qt includes - - -/////////////////////// pappsomspp includes -#include - - -/////////////////////// Local includes -#include "globals.hpp" -#include "MsRunDataSet.hpp" -#include "ProcessingStep.hpp" -#include "ProcessingFlow.hpp" -#include "MassDataIntegrator.hpp" - - -namespace msxps -{ -namespace minexpert -{ - -class MsRunDataSetTreeMassDataIntegratorToMz; - -typedef std::shared_ptr MsRunDataSetTreeMassDataIntegratorToMzSPtr; - -class MsRunDataSetTreeMassDataIntegratorToMz : public MassDataIntegrator -{ - Q_OBJECT - - public: - MsRunDataSetTreeMassDataIntegratorToMz(); - - MsRunDataSetTreeMassDataIntegratorToMz(MsRunDataSetCstSPtr ms_run_data_set_csp); - - MsRunDataSetTreeMassDataIntegratorToMz(MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow); - - MsRunDataSetTreeMassDataIntegratorToMz(const MsRunDataSetTreeMassDataIntegratorToMz &other); - - virtual ~MsRunDataSetTreeMassDataIntegratorToMz(); - - const ProcessingFlow &getProcessingFlow() const; - void appendProcessingStep(ProcessingStep *processing_step_p); - - - public slots: - - void integrateToMz(); - signals: - - protected: - - bool integrateToMzNoBinning(); - bool integrateToMzArbitraryBinning(); -}; - -} // namespace minexpert - -} // namespace msxps - -Q_DECLARE_METATYPE(msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToMz) -extern int msRunDataSetTreeMassDataIntegratorToMzMetaTypeId; - -Q_DECLARE_METATYPE(msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToMzSPtr) -extern int msRunDataSetTreeMassDataIntegratorToMzSPtrMetaTypeId; diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToRt.cpp minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToRt.cpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToRt.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToRt.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -34,6 +34,8 @@ /////////////////////// StdLib includes #include #include +#include + /////////////////////// OpenMP include #include @@ -48,17 +50,11 @@ /////////////////////// Local includes #include "MsRunDataSetTreeMassDataIntegratorToRt.hpp" -#include "ProcessingSpec.hpp" #include "ProcessingStep.hpp" #include "ProcessingType.hpp" #include "BaseMsRunDataSetTreeNodeVisitor.hpp" #include "TicChromTreeNodeCombinerVisitor.hpp" -#include "IntensityTreeNodeCombinerVisitor.hpp" -#include "RtDtMzColorMapsTreeNodeCombinerVisitor.hpp" -#include "TraceTreeNodeCombinerVisitor.hpp" #include "MsRunStatisticsTreeNodeVisitor.hpp" -#include "MassSpectrumTreeNodeCombinerVisitor.hpp" -#include "DriftSpectrumTreeNodeCombinerVisitor.hpp" #include "MultiTreeNodeCombinerVisitor.hpp" @@ -108,7 +104,7 @@ MsRunDataSetTreeMassDataIntegratorToRt::MsRunDataSetTreeMassDataIntegratorToRt( const MsRunDataSetTreeMassDataIntegratorToRt &other) - : MassDataIntegrator(other.mcsp_msRunDataSet) + : MassDataIntegrator(other) { // Essential that the m_processingFlow member is configured to have the right // pointer to the ms run data set. @@ -124,7 +120,7 @@ } -const ProcessingFlow & +ProcessingFlow MsRunDataSetTreeMassDataIntegratorToRt::getProcessingFlow() const { return m_processingFlow; @@ -153,13 +149,17 @@ MsRunDataSetTreeMassDataIntegratorToRt:: seedInitialTicChromatogramAndMsRunDataSetStatistics() { - // qDebug(); - std::chrono::system_clock::time_point chrono_start_time = std::chrono::system_clock::now(); + // The number of nodes we want is that of the root nodes, not of all the + // nodes, that is, we want the MS1 nodes. Indeed, the division of the nodes + // into the various threads can only be performed with the root nodes. + std::size_t node_count = + mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->getRootNodes().size(); + // If there are no data, nothing to do. - if(!mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->getRootNodes().size()) + if(!node_count) { qDebug() << "The ms run data set is empty, nothing to do."; @@ -168,69 +168,61 @@ return; } - // Set aside a spec pointer that we may use more than once for heap - // allocations. - ProcessingSpec *spec_p = nullptr; - - // Create the processing step to document the processing. - ProcessingStep *step_p = new ProcessingStep; - - // qDebug() << "Allocate a processing spec instance."; - - // We need to craft a new processing step, push it back to the processing - // flow and then call the proper integration function. + // qDebug() << "root nodes count:" << node_count; // Document that we only care of the MS1 data, because we are computing an // initial TIC chromatogram. MsFragmentationSpec ms_frag_spec; ms_frag_spec.setMsLevel(1); - // Now the real TIC chrom stuff, that needs to be pushed as the last item - // because that item will govern the actual visitor the end product that will - // be generated (that is, we want a TIC chromatogram). - - // Allocate a new spec. - spec_p = new ProcessingSpec(ms_frag_spec); - - step_p->newSpec(ProcessingType("FILE_TO_RT"), spec_p); - - // For debugging purposes, restrict the rt range to this range. Works - // (20190621). - // spec_p->setRange(0.2, 0.6); + // We need to craft a new processing step, push it back to the processing + // flow and then call the proper integration function. - m_processingFlow.push_back(step_p); + ProcessingStep *step_p = new ProcessingStep(ms_frag_spec); - // We need to clear the map trace! - m_mapTrace.clear(); + double range_start = mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr() + ->getRootNodes() + .front() + ->getQualifiedMassSpectrum() + ->getRtInMinutes(); + double range_end = mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr() + ->getRootNodes() + .back() + ->getQualifiedMassSpectrum() + ->getRtInMinutes(); - // We need a processing flow to work, and, in particular, a processing step - // from which to find the specifics of the calculation. + // qDebug() << "Right from the ms run data set, get rt range start:" + //<< range_start << "and rt range end:" << range_end; - if(!m_processingFlow.size()) - qFatal("The processing flow cannot be empty. Program aborted."); + pappso::SelectionPolygon selection_polygon; + selection_polygon.set1D(range_start, range_end); - const ProcessingStep *processing_step_p = m_processingFlow.mostRecentStep(); + step_p->setSelectionPolygon(selection_polygon); - // Now get a list of the integration types that are stored in the step's map. + // qDebug() << "Created 1D selection polygon:" + //<< step_p->getSelectionPolygon().toString(); - std::vector processing_types = - processing_step_p->processingTypes(); + // qDebug() << "Is1D:" << step_p->getSelectionPolygon().is1D(); - if(!processing_types.size()) - qFatal("The processing step cannot be empty. Program aborted."); + step_p->setSrcProcessingType(pappso::Axis::x, "FILE_RT"); + step_p->setDataKind(pappso::Axis::x, pappso::DataKind::rt); - if(!processing_step_p->matches("ANY_TO_RT")) - qFatal("There should be one ProcessingType = ANY_TO_RT. Program aborted."); + step_p->setSrcProcessingType(pappso::Axis::y, "NOT_SET"); + step_p->setDataKind(pappso::Axis::y, pappso::DataKind::unset); - // Create as many multi-visitors as there are available threads. + // Now document the destination processing type: + step_p->setDestProcessingType("RT"); - // The number of nodes we want is that of the root nodes, not of all the - // nodes, that is, we want the MS1 nodes. Indeed, the division of the nodes - // into the various threads can only be performed with the root nodes. - std::size_t node_count = - mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->getRootNodes().size(); + // At this point we have document all the necessary to perform the + // integration. + + m_processingFlow.push_back(step_p); + + // We need to clear the map trace! + m_mapTrace.clear(); + + // Create as many multi-visitors as there are available threads. - // qDebug() << "root nodes count:" << node_count; // emit setProgressBarMaxValueSignal(node_count); // In the pair below, first is the ideal number of threads and second is the @@ -252,10 +244,6 @@ { // qDebug() << "thread index:" << iter; - // Set aside a stats holder instance. - - MsRunDataSetStats ms_run_data_set_stats; - MultiTreeNodeCombinerVisitorSPtr multi_visitor_sp = std::make_shared(mcsp_msRunDataSet, m_processingFlow); @@ -264,12 +252,20 @@ // one visitor for initial TIC chrom calculation and one for the initial // ms run data set statistics. + // Start with first visitor that will compute the TIC chromatogram TicChromTreeNodeCombinerVisitorSPtr tic_visitor_sp = std::make_shared(mcsp_msRunDataSet, m_processingFlow); multi_visitor_sp->m_visitors.push_back(tic_visitor_sp); + // And now the other visitor that will compute some statistics for the ms + // run data set. + + // Set aside a stats holder instance. + + MsRunDataSetStats ms_run_data_set_stats; + MsRunStatisticsTreeNodeVisitorSPtr stats_visitor_sp = std::make_shared( mcsp_msRunDataSet, m_processingFlow, ms_run_data_set_stats); @@ -339,8 +335,8 @@ // Now perform a parallel iteration in the various visitors and ask them to // work on the matching ms run data set iterators pair. - omp_set_num_threads(visitors.size()); -#pragma omp parallel for ordered + omp_set_num_threads(visitors.size()); + #pragma omp parallel for ordered for(std::size_t iter = 0; iter < visitors.size(); ++iter) { auto multi_visitor_sp = visitors.at(iter); @@ -353,6 +349,13 @@ *(multi_visitor_sp.get()), iterators.at(iter).first, iterators.at(iter).second); + + //qDebug() << "Finished running the visitor at index:" << iter + //<< "and the m_maxMz for the data stats is:" + //<< dynamic_cast( + //multi_visitor_sp->m_visitors.back().get()) + //->getMsRunDataSetStats() + //.m_maxMz; } // End of // #pragma omp parallel for @@ -422,14 +425,32 @@ emit setProgressBarCurrentValueSignal(iter + 1); + //qDebug() << "Going to merge a visitor's MsRunDataSetStats and the " + //"m_maxMz for the data stats is:" + //<< dynamic_cast( + //multi_visitor_sp->m_visitors.back().get()) + //->getMsRunDataSetStats() + //.m_maxMz; + + //qDebug() << "We are merging one visitor's ms run data set stats:" + //<< stats_visitor_sp.get()->getMsRunDataSetStats().toString(); + + //qDebug() + //<< "Before the merge, the ms_run_data_set_stats_merge has m_maxMz:" + //<< ms_run_data_set_stats_merge.m_maxMz; + ms_run_data_set_stats_merge.merge( stats_visitor_sp.get()->getMsRunDataSetStats()); + + //qDebug() + //<< "After the merge, the ms_run_data_set_stats_merge has m_maxMz:" + //<< ms_run_data_set_stats_merge.m_maxMz; } // At this point we finally have the statistical data merged into a single // instance. We now need to consolidate. - // qDebug() << "Final consolidation of the statistics."; + //qDebug() << "Final consolidation of the statistics."; ms_run_data_set_stats_merge.consolidate(); @@ -482,16 +503,9 @@ // Get the most recent step that holds all the specifics of this integration. const ProcessingStep *processing_step_p = m_processingFlow.mostRecentStep(); - // Now get a list of the integration types that are stored in the step's map. - - std::vector processing_types = - processing_step_p->processingTypes(); - - if(!processing_types.size()) - qFatal("The processing step cannot be empty. Program aborted."); - - if(!processing_step_p->matches("ANY_TO_RT")) - qFatal("There should be one ProcessingType = ANY_TO_RT. Program aborted."); + if(!processing_step_p->srcMatches("ANY_RT")) + qFatal( + "There should be one source ProcessingType = ANY_RT. Program aborted."); // Try to limit the range of MS run data set tree nodes to be iterated through // by looking from what node to what other node we need to go to ensure that @@ -500,10 +514,9 @@ std::vector root_nodes = mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->getRootNodes(); - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); + std::pair range_pair; - bool integration_rt = m_processingFlow.innermostRtRange(start_rt, end_rt); + bool integration_rt = m_processingFlow.innermostRange("ANY_RT", range_pair); using Iterator = std::vector::const_iterator; using Pair = std::pair; @@ -517,18 +530,18 @@ if(integration_rt) { - pair = - mcsp_msRunDataSet->treeNodeIteratorRangeForRtRange(start_rt, end_rt); + pair = mcsp_msRunDataSet->treeNodeIteratorRangeForRtRange( + range_pair.first, range_pair.second); begin_iterator = pair.first; end_iterator = pair.second; node_count = std::distance(begin_iterator, end_iterator); - qDebug() << "node_count:" << node_count; + // qDebug() << "node_count:" << node_count; } - else - qDebug() << "Not integration_rt"; + // else + // qDebug() << "Not integration_rt"; if(begin_iterator == root_nodes.end()) { @@ -713,204 +726,6 @@ } -#if 0 -void -MsRunDataSetTreeMassDataIntegratorToRt::calculateInitialMsRunDataSetStatistics() -{ - // We want to parallelize the computation. - - std::chrono::system_clock::time_point chrono_start_time = - std::chrono::system_clock::now(); - - // The number of nodes we want is that of the root nodes, not of all the - // nodes, that is, we want the MS1 nodes. - std::size_t node_count = - mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->getRootNodes().size(); - - // qDebug() << "node_count:" << node_count; - // emit setProgressBarMaxValueSignal(node_count); - - // In the pair below, first is the ideal number of threads and second is the - // number of nodes per thread. - std::pair best_parallel_params = - bestParallelIntegrationParams(node_count); - - // qDebug() << "ideal_thread_count:" << best_parallel_params.first - //<< "nodes_per_thread:" << best_parallel_params.second; - - using Iterator = std::vector::const_iterator; - - std::vector visitors; - std::vector> iterators = calculateMsRunDataSetTreeNodeIteratorPairs( - node_count, best_parallel_params.first, best_parallel_params.second); - - for(std::size_t iter = 0; iter < iterators.size(); ++iter) - { - //qDebug() << "thread index:" << iter; - - MsRunDataSetStats ms_run_data_set_stats; - - MsRunStatisticsTreeNodeVisitorSPtr visitor_sp = - std::make_shared( - mcsp_msRunDataSet, m_processingFlow, ms_run_data_set_stats); - - // We want to be able to intercept any cancellation of the operation. - - connect(this, - &MsRunDataSetTreeMassDataIntegratorToRt::cancelOperationSignal, - [visitor_sp]() { visitor_sp->cancelOperation(); }); - // visitor_sp.get(), - //&TraceTreeNodeCombinerVisitor::cancelOperation, - // Qt::QueuedConnection); - - // The visitor gets the number of nodes to process from the data set tree - // node. Capture that number and relay it. - - connect(visitor_sp.get(), - &MsRunStatisticsTreeNodeVisitor::setProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - emit setProgressBarMaxValueSignal(number_of_nodes_to_process); - }); - - // The visitor emits the signal to tell that the currently iterated node - // has number_of_nodes_to_process children to process. Because the visitor - // might operate in a thread and that there might be other threads - // handling other nodes, we do not consider that the - // number_of_nodes_to_process value is the total number of nodes to - // process but only the number of nodes that the visitor is handling. We - // thus update the max progress bar value by number_of_nodes_to_process. - // In a typical setting, the user of the signal is the monitoring object, - // be it a non-gui object or the TaskMonitorCompositeWidget. - connect( - visitor_sp.get(), - &MsRunStatisticsTreeNodeVisitor::incrementProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - emit incrementProgressBarMaxValueSignal(number_of_nodes_to_process); - }); - - connect(visitor_sp.get(), - &MsRunStatisticsTreeNodeVisitor::setProgressBarCurrentValueSignal, - [this](std::size_t number_of_processed_nodes) { - emit setProgressBarCurrentValueSignal( - number_of_processed_nodes); - }); - - connect(visitor_sp.get(), - &MsRunStatisticsTreeNodeVisitor:: - incrementProgressBarCurrentValueAndSetStatusTextSignal, - [this](std::size_t increment, QString text) { - emit incrementProgressBarCurrentValueAndSetStatusTextSignal( - increment, text); - }); - - connect(visitor_sp.get(), - &MsRunStatisticsTreeNodeVisitor::setStatusTextSignal, - [this](QString text) { emit setStatusTextSignal(text); }); - - connect( - visitor_sp.get(), - &MsRunStatisticsTreeNodeVisitor::setStatusTextAndCurrentValueSignal, - [this](QString text, std::size_t value) { - emit setStatusTextAndCurrentValueSignal(text, value); - }); - - visitors.push_back(visitor_sp); - } - - emit setTaskDescriptionTextSignal( - "Computing the statistics of the MS data set"); - - omp_set_num_threads(visitors.size()); -#pragma omp parallel for - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - auto stat_visitor = visitors.at(iter); - - //qDebug() << "Visitor:" << &stat_visitor << "at index:" << iter - //<< "Executing from thread:" << QThread::currentThreadId(); - - mcsp_msRunDataSet->msp_msRunDataSetTree->accept( - *(stat_visitor.get()), - iterators.at(iter).first, - iterators.at(iter).second); - } - // End of - // #pragma omp parallel for - - // At this point all the visitors have performed their task and each one has - // a MsRunDataSetStats member that was filled with statistical data about - // all the spectra visited. - - // qDebug() << "End of the iteration in the visitors"; - - - // If the task was cancelled, the monitor widget was locked. We need to - // unlock it. - emit unlockTaskMonitorCompositeWidgetSignal(); - emit setupProgressBarSignal(0, visitors.size() - 1); - - // We now need to merge all these MsRunDataSetStats data into a single one. - MsRunDataSetStats ms_run_data_set_stats_merge; - - // We might be here because the user cancelled the operation in the for loop - // above (visiting all the visitors). In this case m_isOperationCancelled is - // true. We want to set it back to false, so that the following loop is gone - // through. The user can ask that the operation be cancelled once more. But we - // want that at least the performed work be used to show the trace. - - m_isOperationCancelled = false; - - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - //qDebug() << "Now merging the data statistics for thread at index: " - //<< iter; - - if(m_isOperationCancelled) - break; - - auto &&visitor_sp = visitors.at(iter); - - //qDebug() << "In the consolidating loop, iter:" << iter - //<< "for a new ms run data set statistics merge"; - - emit setStatusTextSignal( - QString("Consolidating statistics from thread %1").arg(iter + 1)); - - ms_run_data_set_stats_merge.merge( - visitor_sp.get()->getMsRunDataSetStats()); - } - - - // At this point we finally have the statistical data merged into a single - // instance. We now need to consolidate. - - //qDebug() << "Final consolidation of the statistics."; - - ms_run_data_set_stats_merge.consolidate(); - - // At this point we can set the statistics to the ms run data set. We need to - // un-const_cast the shared pointer (this is one of the rarest situations - // where we need to do this). - std::const_pointer_cast(mcsp_msRunDataSet) - ->setMsRunDataSetStats(ms_run_data_set_stats_merge); - - //qDebug() << mcsp_msRunDataSet->getMsRunDataSetStats().toString(); - - std::chrono::system_clock::time_point chrono_end_time; - - QString chrono_string = pappso::Utils::chronoIntervalDebugString( - "Calculation of the MS run data set statistics took:", - chrono_start_time, - chrono_end_time); - - emit logTextToConsoleSignal(chrono_string); - //qDebug().noquote() << chrono_string; - - emit finishedCalculatingInitialMsRunDataSetStatisticsSignal(this); -} -#endif - - } // namespace minexpert } // namespace msxps diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToRt.hpp minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToRt.hpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToRt.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToRt.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -77,7 +77,7 @@ virtual ~MsRunDataSetTreeMassDataIntegratorToRt(); - const ProcessingFlow &getProcessingFlow() const; + ProcessingFlow getProcessingFlow() const; void appendProcessingStep(ProcessingStep *processing_step_p); const MsRunDataSetStats &getMsRunDataSetStats() const; diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToTicInt.cpp minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToTicInt.cpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToTicInt.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToTicInt.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,415 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright (C) 2009--2020 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -/////////////////////// StdLib includes -#include -#include - -/////////////////////// OpenMP include -#include - -/////////////////////// Qt includes -#include -#include - -/////////////////////// pappsomspp includes -#include - - -/////////////////////// Local includes -#include "MsRunDataSetTreeMassDataIntegratorToTicInt.hpp" -#include "ProcessingSpec.hpp" -#include "ProcessingStep.hpp" -#include "ProcessingType.hpp" -#include "BaseMsRunDataSetTreeNodeVisitor.hpp" -#include "TicChromTreeNodeCombinerVisitor.hpp" -#include "IntensityTreeNodeCombinerVisitor.hpp" -#include "RtDtMzColorMapsTreeNodeCombinerVisitor.hpp" -#include "TraceTreeNodeCombinerVisitor.hpp" -#include "MsRunStatisticsTreeNodeVisitor.hpp" -#include "MassSpectrumTreeNodeCombinerVisitor.hpp" -#include "DriftSpectrumTreeNodeCombinerVisitor.hpp" -#include "MultiTreeNodeCombinerVisitor.hpp" - - -int msRunDataSetTreeMassDataIntegratorToTicIntMetaTypeId = qRegisterMetaType< - msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToTicInt>( - "msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToTicInt"); - -int msRunDataSetTreeMassDataIntegratorToTicIntSPtrMetaTypeId = - qRegisterMetaType< - msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToTicIntSPtr>( - "msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToTicIntSPtr"); - - -namespace msxps -{ -namespace minexpert -{ - - -MsRunDataSetTreeMassDataIntegratorToTicInt:: - MsRunDataSetTreeMassDataIntegratorToTicInt() -{ - qFatal("Cannot be that the default constructor be used."); - // qDebug() << "Allocating new integrator:" << this; -} - - -MsRunDataSetTreeMassDataIntegratorToTicInt:: - MsRunDataSetTreeMassDataIntegratorToTicInt( - MsRunDataSetCstSPtr ms_run_data_set_csp) - : MassDataIntegrator(ms_run_data_set_csp) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - - m_processingFlow.setMsRunDataSetCstSPtr(ms_run_data_set_csp); -} - - -MsRunDataSetTreeMassDataIntegratorToTicInt:: - MsRunDataSetTreeMassDataIntegratorToTicInt( - MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow) - : MassDataIntegrator(ms_run_data_set_csp), m_processingFlow(processing_flow) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - if(ms_run_data_set_csp != m_processingFlow.getMsRunDataSetCstSPtr()) - qFatal("The pointers should be identical."); -} - - -MsRunDataSetTreeMassDataIntegratorToTicInt:: - MsRunDataSetTreeMassDataIntegratorToTicInt( - const MsRunDataSetTreeMassDataIntegratorToTicInt &other) - : MassDataIntegrator(other), m_processingFlow(other.m_processingFlow) -{ - // Essential that the m_processingFlow member is configured to have the right - // pointer to the ms run data set. - if(other.mcsp_msRunDataSet != m_processingFlow.getMsRunDataSetCstSPtr()) - qFatal("The pointers should be identical."); -} - - -MsRunDataSetTreeMassDataIntegratorToTicInt:: - ~MsRunDataSetTreeMassDataIntegratorToTicInt() -{ - // qDebug() << "Destroying integrator:" << this; -} - - -const ProcessingFlow & -MsRunDataSetTreeMassDataIntegratorToTicInt::getProcessingFlow() const -{ - return m_processingFlow; -} - - -void -MsRunDataSetTreeMassDataIntegratorToTicInt::appendProcessingStep( - ProcessingStep *processing_step_p) -{ - if(processing_step_p == nullptr) - qFatal("The pointer cannot be nullptr."); - - m_processingFlow.push_back(processing_step_p); -} - - -double -MsRunDataSetTreeMassDataIntegratorToTicInt::getTicIntensity() const -{ - return m_ticIntensity; -} - - -bool -MsRunDataSetTreeMassDataIntegratorToTicInt::integrateToTicIntensity() -{ - // qDebug(); - - m_ticIntensity = 0; - - std::chrono::system_clock::time_point chrono_start_time = - std::chrono::system_clock::now(); - - // We need a processing flow to work, and, in particular, a processing step - // from which to find the specifics of the calculation. The processing flow - // must have been set by the caller either at construction time or later - // before using the integrator, that is, calling this function. - - if(!m_processingFlow.size()) - qFatal("The processing flow cannot be empty. Program aborted."); - - // Get the most recent step that holds all the specifics of this integration. - const ProcessingStep *processing_step_p = m_processingFlow.mostRecentStep(); - - // Now get a list of the integration types that are stored in the step's - // map. - - std::vector processing_types = - processing_step_p->processingTypes(); - - if(!processing_types.size()) - qFatal("The processing step cannot be empty. Program aborted."); - - if(!processing_step_p->matches("ANY_TO_INT")) - qFatal("There should be one ProcessingType = ANY_TO_INT. Program aborted."); - - // Try to limit the range of MS run data set tree nodes to be iterated through - // by looking from what node to what other node we need to go to ensure that - // our integration encompasses the right RT range. - - std::vector root_nodes = - mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->getRootNodes(); - - double start_rt = std::numeric_limits::infinity(); - double end_rt = std::numeric_limits::infinity(); - - bool integration_rt = m_processingFlow.innermostRtRange(start_rt, end_rt); - - using Iterator = std::vector::const_iterator; - using Pair = std::pair; - - Pair pair; - - Iterator begin_iterator = root_nodes.begin(); - Iterator end_iterator = root_nodes.end(); - - std::size_t node_count = 0; - - if(integration_rt) - { - pair = - mcsp_msRunDataSet->treeNodeIteratorRangeForRtRange(start_rt, end_rt); - - begin_iterator = pair.first; - end_iterator = pair.second; - - node_count = std::distance(begin_iterator, end_iterator); - - qDebug() << "node_count:" << node_count; - } - else - qDebug() << "Not integration_rt"; - - if(begin_iterator == root_nodes.end()) - { - qDebug() << "There is nothing to integrate."; - return false; - } - - // Now that we know the non-0 count of nodes to be processed: - emit setProgressBarMaxValueSignal(node_count); - - - // At this point, allocate a visitor that is specific for the calculation of - // the TIC intensity. - - // But we want to parallelize the computation. - - // In the pair below, first is the ideal number of threads and second is the - // number of nodes per thread. - std::pair best_parallel_params = - bestParallelIntegrationParams(node_count); - - // qDebug() << "ideal_thread_count:" << best_parallel_params.first - //<< "nodes_per_thread:" << best_parallel_params.second; - - using Iterator = std::vector::const_iterator; - - std::vector visitors; - std::vector> iterators = - calculateMsRunDataSetTreeNodeIteratorPairs(begin_iterator, - end_iterator, - best_parallel_params.first, - best_parallel_params.second); - - // For each available thread, allocate a new visitor. We also configure - // which root nodes it should handle as two (begin,end) iterators to the ms - // run data set tree. We push back the pair of iterators to the vector of - // iterators. - - for(std::size_t iter = 0; iter < iterators.size(); ++iter) - { - // qDebug() << "thread index:" << iter; - - IntensityTreeNodeCombinerVisitorSPtr visitor_sp = - std::make_shared(mcsp_msRunDataSet, - m_processingFlow); - - // We want to be able to intercept any cancellation of the operation. - - connect( - this, - &MsRunDataSetTreeMassDataIntegratorToTicInt::cancelOperationSignal, - [visitor_sp]() { visitor_sp->cancelOperation(); }); - // visitor_sp.get(), - //&IntensityTreeNodeCombinerVisitor::cancelOperation, - // Qt::QueuedConnection); - - // The visitor gets the number of nodes to process from the data set tree - // node. This signal tells the final user of the signal to set the max - // value of the progress bar to number_of_nodes_to_process. - - connect(visitor_sp.get(), - &IntensityTreeNodeCombinerVisitor::setProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - emit setProgressBarMaxValueSignal(number_of_nodes_to_process); - }); - - // The visitor emits the signal to tell that the currently iterated node - // has number_of_nodes_to_process children to process. Because the visitor - // might operate in a thread and that there might be other threads - // handling other nodes, we do not consider that the - // number_of_nodes_to_process value is the total number of nodes to - // process but only the number of nodes that the visitor is handling. We - // thus update the max progress bar value by number_of_nodes_to_process. - // In a typical setting, the user of the signal is the monitoring object, - // be it a non-gui object or the TaskMonitorCompositeWidget. - connect( - visitor_sp.get(), - &IntensityTreeNodeCombinerVisitor::incrementProgressBarMaxValueSignal, - [this](std::size_t number_of_nodes_to_process) { - emit incrementProgressBarMaxValueSignal(number_of_nodes_to_process); - }); - - connect( - visitor_sp.get(), - &IntensityTreeNodeCombinerVisitor::setProgressBarCurrentValueSignal, - [this](std::size_t number_of_processed_nodes) { - emit setProgressBarCurrentValueSignal(number_of_processed_nodes); - }); - - connect(visitor_sp.get(), - &IntensityTreeNodeCombinerVisitor:: - incrementProgressBarCurrentValueAndSetStatusTextSignal, - [this](std::size_t increment, QString text) { - emit incrementProgressBarCurrentValueAndSetStatusTextSignal( - increment, text); - }); - - connect(visitor_sp.get(), - &IntensityTreeNodeCombinerVisitor::setStatusTextSignal, - [this](QString text) { emit setStatusTextSignal(text); }); - - connect( - visitor_sp.get(), - &IntensityTreeNodeCombinerVisitor::setStatusTextAndCurrentValueSignal, - [this](QString text, std::size_t value) { - emit setStatusTextAndCurrentValueSignal(text, value); - }); - - visitors.push_back(visitor_sp); - } - - // Now perform a parallel iteration in the various visitors and ask them to - // work on the matching ms run data set iterators pair. - omp_set_num_threads(visitors.size()); -#pragma omp parallel for ordered - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - auto visitor_sp = visitors.at(iter); - - // qDebug() << "Visitor:" << visitor_sp.get() << "at index:" << iter - //<< "Executing from thread:" << QThread::currentThreadId(); - - mcsp_msRunDataSet->msp_msRunDataSetTree->accept( - *(visitor_sp.get()), - iterators.at(iter).first, - iterators.at(iter).second); - } - // End of - // #pragma omp parallel for - - // In the loop above, the m_ticChromMapTrace object (map , - // that is, (rt, tic)) has been filled with the various TIC values for the - // different retention times. - // - // At this point we need to combine all the visitor-contained map traces - // into a single trace. We make the combination into the member MapTrace - // object. - - // qDebug() << "End of the iteration in the visitors"; - - // If the task was cancelled, the monitor widget was locked. We need to - // unlock it. - emit unlockTaskMonitorCompositeWidgetSignal(); - emit setupProgressBarSignal(0, visitors.size() - 1); - - // We might be here because the user cancelled the operation in the for loop - // above (visiting all the visitors). In this case m_isOperationCancelled is - // true. We want to set it back to false, so that the following loop is gone - // through. The user can ask that the operation be cancelled once more. But we - // want that at least the performed work be used to show the trace. - - m_isOperationCancelled = false; - - for(std::size_t iter = 0; iter < visitors.size(); ++iter) - { - if(m_isOperationCancelled) - break; - - auto &&visitor_sp = visitors.at(iter); - - double tic_intensity = visitor_sp->getTicIntensity(); - - // qDebug() << "In the consolidating loop, iter:" << iter - //<< "with an intensity of : " << tic_intensity; - - emit setStatusTextSignal( - QString("Consolidating TIC intensities from thread %1").arg(iter + 1)); - - emit setProgressBarCurrentValueSignal(iter + 1); - - m_ticIntensity += tic_intensity; - } - - std::chrono::system_clock::time_point chrono_end_time = - std::chrono::system_clock::now(); - - QString chrono_string = pappso::Utils::chronoIntervalDebugString( - "Integration to TIC intensity took:", chrono_start_time, chrono_end_time); - - emit logTextToConsoleSignal(chrono_string); - // qDebug().noquote() << chrono_string; - - return true; -} - - -} // namespace minexpert - -} // namespace msxps diff -Nru minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToTicInt.hpp minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToTicInt.hpp --- minexpert2-7.4.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToTicInt.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunDataSetTreeMassDataIntegratorToTicInt.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright (C) 2009--2020 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -#pragma once - -/////////////////////// StdLib includes -#include - - -/////////////////////// Qt includes - - -/////////////////////// pappsomspp includes -#include - - -/////////////////////// Local includes -#include "globals.hpp" -#include "MsRunDataSet.hpp" -#include "ProcessingStep.hpp" -#include "ProcessingFlow.hpp" -#include "MassDataIntegrator.hpp" - - -namespace msxps -{ -namespace minexpert -{ - -class MsRunDataSetTreeMassDataIntegratorToTicInt; - -typedef std::shared_ptr MsRunDataSetTreeMassDataIntegratorToTicIntSPtr; - -class MsRunDataSetTreeMassDataIntegratorToTicInt : public MassDataIntegrator -{ - Q_OBJECT - - public: - MsRunDataSetTreeMassDataIntegratorToTicInt(); - - MsRunDataSetTreeMassDataIntegratorToTicInt(MsRunDataSetCstSPtr ms_run_data_set_csp); - - MsRunDataSetTreeMassDataIntegratorToTicInt(MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow); - - MsRunDataSetTreeMassDataIntegratorToTicInt(const MsRunDataSetTreeMassDataIntegratorToTicInt &other); - - virtual ~MsRunDataSetTreeMassDataIntegratorToTicInt(); - - const ProcessingFlow &getProcessingFlow() const; - void appendProcessingStep(ProcessingStep *processing_step_p); - - double getTicIntensity() const; - - public slots: - - bool integrateToTicIntensity(); - - signals: - - protected: - ProcessingFlow m_processingFlow; - - // Initialize the tic intensity to max() so that we know if a computation was - // carried-over or not. - double m_ticIntensity = std::numeric_limits::max(); -}; - -} // namespace minexpert - -} // namespace msxps - -Q_DECLARE_METATYPE(msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToTicInt) -extern int msRunDataSetTreeMassDataIntegratorToTicIntMetaTypeId; - -Q_DECLARE_METATYPE(msxps::minexpert::MsRunDataSetTreeMassDataIntegratorToTicIntSPtr) -extern int msRunDataSetTreeMassDataIntegratorToTicIntSPtrMetaTypeId; diff -Nru minexpert2-7.4.1/src/nongui/MsRunStatisticsTreeNodeVisitor.cpp minexpert2-8.1.1/src/nongui/MsRunStatisticsTreeNodeVisitor.cpp --- minexpert2-7.4.1/src/nongui/MsRunStatisticsTreeNodeVisitor.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunStatisticsTreeNodeVisitor.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -32,6 +32,7 @@ /////////////////////// StdLib includes +#include /////////////////////// Qt includes @@ -62,6 +63,9 @@ m_msRunDataSetStats(ms_run_data_set_stats) { // qDebug() << "Processing flow has" << m_processingFlow.size() << "steps"; + // qDebug() + //<< "The selection polygon:" + //<< m_processingFlow.mostRecentStep()->getSelectionPolygon().toString(); } @@ -96,28 +100,6 @@ } -void -MsRunStatisticsTreeNodeVisitor::setProcessingFlow( - const ProcessingFlow &processing_flow) -{ - m_processingFlow = processing_flow; -} - - -void -MsRunStatisticsTreeNodeVisitor::setLimitMzRangeStart(double value) -{ - m_limitMzRangeStart = value; -} - - -void -MsRunStatisticsTreeNodeVisitor::setLimitMzRangeEnd(double value) -{ - m_limitMzRangeEnd = value; -} - - const MsRunDataSetStats & MsRunStatisticsTreeNodeVisitor::getMsRunDataSetStats() const { @@ -137,331 +119,109 @@ // QThread::currentThread(); qDebug() << "Visiting node from thread:" << // QThread::currentThread(); - // Whatever the status of this node (to be or not processed) let the user know - // that we have gone through one more. - - // The "%c" format refers to the current value in the task monitor widget that - // will craft the new text according to the current value after having - // incremented it in the call below. This is necessary because this visitor - // might be in a thread and the we need to account for all the thread when - // giving feedback to the user. - - emit incrementProgressBarCurrentValueAndSetStatusTextSignal( - 1, "Processed %c nodes"); - - // At this point we need to go deep in the processing flow's steps to check if - // the node matches the whole set of the steps' specs. - - for(auto &&step : m_processingFlow) + if(!m_isProgressFeedbackSilenced) { - if(checkProcessingStep(*step, node)) - { - // qDebug() << "The node matches the iterated step."; - } - else - { - // qDebug() << "The node does not match the iterated step."; + // Whatever the status of this node (to be or not processed) let the user + // know that we have gone through one more. - return false; - } + // The "%c" format refers to the current value in the task monitor widget + // that will craft the new text according to the current value after + // having incremented it in the call below. This is necessary because this + // visitor might be in a thread and the we need to account for all the + // thread when giving feedback to the user. + + emit incrementProgressBarCurrentValueAndSetStatusTextSignal( + 1, "Processed %c nodes"); } - // At this point we know that the current node matches all the flow's steps' - // specs. - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); + // qDebug().noquote() << "Visiting node:" << &node << "text format:" << + // node.toString() + //<< "with quaified mass spectrum:" + //<< node.getQualifiedMassSpectrum()->toString(); - if(qualified_mass_spectrum_csp->getMassSpectrumSPtr() == nullptr) - { - qDebug() << "Need to access the mass data right from the file."; - - std::size_t mass_spectrum_index = - mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr()->massSpectrumIndex( - &node); - - pappso::MsRunReaderCstSPtr ms_run_reader_csp = - mcsp_msRunDataSet->getMsRunReaderCstSPtr(); - - qualified_mass_spectrum_csp = - std::make_shared( - ms_run_reader_csp->qualifiedMassSpectrum(mass_spectrum_index, true)); - } + pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = + checkQualifiedMassSpectrum(node); if(qualified_mass_spectrum_csp == nullptr) { qFatal("Failed to read the mass spectral data from the file."); } - // qDebug() << "The qualified mass spectrum:" - //<< qualified_mass_spectrum_csp->toString(); + //qDebug().noquote() << "Visiting qualified mass spectrum:" + //<< qualified_mass_spectrum_csp->toString(); - pappso::MassSpectrum &mass_spectrum = - *(qualified_mass_spectrum_csp->getMassSpectrumSPtr()); + // We do not check the MS level because we want all the mass spectra to be + // accounted for because we need to know the smallest value of all the m/z + // values in the whole data set, irrespective of MS level. - // qDebug() << "The mass spectrum being visited has size:" - //<< mass_spectrum.size(); + // Make easy check about RT and DT. - if(m_limitMzRangeStart != std::numeric_limits::max() && - m_limitMzRangeEnd != std::numeric_limits::max()) + if(!checkRtRange(qualified_mass_spectrum_csp)) { - // Before analyzing statistically the mass spectrum, we need to check - // that we work on the proper mz range asked by the caller. Here we need - // to filter the mass spectrum to only keep the m/z range specified. - - pappso::FilterResampleKeepXRange filter; - pappso::MassSpectrum filtered_mass_spectrum = - filter.filter(mass_spectrum); - - // qDebug() << "The filtered mass spectrum has size:" - //<< filtered_mass_spectrum.size(); + //qDebug() << "checkRtRange failed check."; - m_msRunDataSetStats.incrementStatistics(filtered_mass_spectrum); + return false; } - else + if(!checkDtRange(qualified_mass_spectrum_csp)) { - // We do not want to bother with y=0 data points ! - pappso::FilterHighPass filter(0.0); - - pappso::MassSpectrum filtered_mass_spectrum = - filter.filter(mass_spectrum); + //qDebug() << "checkDtRange failed check."; - // qDebug() << "The filtered mass spectrum has size:" - //<< filtered_mass_spectrum.size() - //<< "with first data point:" - //<< filtered_mass_spectrum.front().toString(); - - m_msRunDataSetStats.incrementStatistics(filtered_mass_spectrum); + return false; } - // qDebug().noquote() << "statistics:" << m_msRunDataSetStats.toString(); - - return true; -} + //qDebug().noquote() + //<< "The qualified mass spectrum:" << qualified_mass_spectrum_csp->toString() + //<< "rt in minutes:" << qualified_mass_spectrum_csp->getRtInMinutes() + //<< "dt in milliseconds:" + //<< qualified_mass_spectrum_csp->getDtInMilliSeconds() << "max m/z value:" + //<< qualified_mass_spectrum_csp->getMassSpectrumSPtr()->back().x; + // qDebug() << "The current qualified mass spectrum has size:" + //<< qualified_mass_spectrum_csp->size(); -bool -MsRunStatisticsTreeNodeVisitor::checkProcessingStep( - const ProcessingStep &step, const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); + pappso::MassSpectrum filtered_mass_spectrum; - // A processing step is a collection of mapped items: - // std::map m_processingTypeSpecMap; - // - // For each item, we need to check if the node matches the spec. - - for(auto &&pair : step.getProcessingTypeSpecMap()) + if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second)) { - if(checkProcessingSpec(pair, node)) - { - // qDebug() << "The node matches the iterated spec."; - } - else - { - // qDebug() << "The node does not match the iterated - // spec."; - - return false; - } - } - - return true; -} - - -bool -MsRunStatisticsTreeNodeVisitor::checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // This is the most elemental component of a ProcessingFlow, so here we - // actually look into the node. - - const ProcessingSpec *spec_p = type_spec_pair.second; - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const MsFragmentationSpec fragmentation_spec = - spec_p->getMsFragmentationSpec(); + // Before analyzing statistically the mass spectrum, we need to check + // that we work on the proper mz range asked by the caller. Here we need + // to filter the mass spectrum to only keep the m/z range specified. - if(fragmentation_spec.isValid()) - { - // qDebug() << "The fragmentation spec *is* valid."; + pappso::FilterResampleKeepXRange filter; - // For each member of the MsFragmentationSpec structure, check if it is - // to be used for the check. + // The filter changes the Trace (or MassSpectrum) *in place*, so we need + // to first create a copy. + filtered_mass_spectrum.initialize( + *(qualified_mass_spectrum_csp->getMassSpectrumSPtr())); - if(fragmentation_spec.getMsLevel()) - { - if(qualified_mass_spectrum_csp->getMsLevel() < - fragmentation_spec.getMsLevel()) - { - // qDebug() << "The ms level does not match."; - return false; - } - } - - if(fragmentation_spec.precursorMzValuesCount()) - { - const std::vector - &precursor_ion_data_vector = - qualified_mass_spectrum_csp->getPrecursorIonData(); - - if(!fragmentation_spec.containsMzPrecursors( - precursor_ion_data_vector)) - { - return false; - } - } - - if(fragmentation_spec.precursorSpectrumIndicesCount()) - { - if(!fragmentation_spec.containsSpectrumPrecursorIndex( - qualified_mass_spectrum_csp->getPrecursorSpectrumIndex())) - { - // qDebug() << "The precursor spectrum index does not match."; - - return false; - } - } + filtered_mass_spectrum = filter.filter(filtered_mass_spectrum); } else { - // Else, fragmentation is not a criterion for filtering data. So go on. - // qDebug() << "The fragmentation spec is *not* valid."; - } - - // qDebug() << "Frag spec ok, going on with the spec check."; - - ProcessingType type = type_spec_pair.first; - - // Because we are working on the TIC chromatogram visitor, we need to match - // the corresponding processing type that creates a TIC chromatogram right - // from the data file, apart from other processes that create a TIC chrom - // from other data settings, which in truth are called XIC chrom. - - if(type.bitMatches("FILE_TO_RT") || type.bitMatches("RT_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByRt(type_spec_pair, node)) - return false; - } - else if(type.bitMatches("MZ_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByMz(type_spec_pair, node)) - return false; - } - else if(type.bitMatches("DT_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByDt(type_spec_pair, node)) - return false; - } - - // At this point we seem to understand that the node matched! - - return true; -} - - -bool -MsRunStatisticsTreeNodeVisitor::checkProcessingTypeByRt( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(spec_p->hasValidRange()) - { - double rt = qualified_mass_spectrum_csp->getRtInMinutes(); - - if(rt >= spec_p->getStart() && rt <= spec_p->getEnd()) - { - // qDebug() << "Returning true for Rt."; - return true; - } - else - return false; - } - - return true; -} - - -bool -MsRunStatisticsTreeNodeVisitor::checkProcessingTypeByMz( - const std::pair &type_spec_pair, - [[maybe_unused]] const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // Are there specs about the m/z range to be accounted for in the - // computation? - - const ProcessingSpec *spec_p = type_spec_pair.second; + // We do not want to bother with y=0 data points ! + pappso::FilterHighPass filter(0.0); - if(spec_p->hasValidRange()) - { - // qDebug() << "Needed a m/z range filtering:" << spec_p->toString(); + // The filter changes the Trace (or MassSpectrum) *in place*, so we need + // to first create a copy. + filtered_mass_spectrum.initialize( + *(qualified_mass_spectrum_csp->getMassSpectrumSPtr())); - // The point is that if there are more than one spec in the the flow's - // steps that limit the m/z range, we want to be sure to perform the - // processing using the innermost range. So ask the ProcessingFlow to - // actually compute that innermost m/z range. - - // Make a local copy of the type_spec_pair - std::pair local_type_spec_pair( - type_spec_pair); - - if(m_processingFlow.innermostMzRange(local_type_spec_pair)) - { - m_limitMzRangeStart = local_type_spec_pair.second->getStart(); - m_limitMzRangeEnd = local_type_spec_pair.second->getEnd(); - } - else - qFatal( - "Cannot be that there is no innermost m/z range if there is a valid " - "m/z range in a spec."); + filtered_mass_spectrum = filter.filter(filtered_mass_spectrum); } - // Return true because we'll account that node whatever the mz range - // criterion. + // At this point, either we used filters, and filtered_mass_spectrum.size() is + // non-0, or we must use the origianl mass spectrum. - return true; -} - - -bool -MsRunStatisticsTreeNodeVisitor::checkProcessingTypeByDt( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const ProcessingSpec *spec_p = type_spec_pair.second; + if(filtered_mass_spectrum.size()) + m_msRunDataSetStats.incrementStatistics(filtered_mass_spectrum); + else + m_msRunDataSetStats.incrementStatistics( + *(qualified_mass_spectrum_csp->getMassSpectrumSPtr())); - if(type_spec_pair.second->hasValidRange()) - { - double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); + //qDebug() << "After statistics incrementation, m_maxMz:" << m_msRunDataSetStats.m_maxMz; - if(dt >= spec_p->getStart() && dt <= spec_p->getEnd()) - return true; - else - return false; - } + // qDebug().noquote() << "statistics:" << m_msRunDataSetStats.toString(); return true; } diff -Nru minexpert2-7.4.1/src/nongui/MsRunStatisticsTreeNodeVisitor.hpp minexpert2-8.1.1/src/nongui/MsRunStatisticsTreeNodeVisitor.hpp --- minexpert2-7.4.1/src/nongui/MsRunStatisticsTreeNodeVisitor.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MsRunStatisticsTreeNodeVisitor.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -75,11 +75,6 @@ virtual ~MsRunStatisticsTreeNodeVisitor(); - virtual void setProcessingFlow(const ProcessingFlow &processing_flow); - - void setLimitMzRangeStart(double value); - void setLimitMzRangeEnd(double value); - const MsRunDataSetStats &getMsRunDataSetStats() const; MsRunStatisticsTreeNodeVisitor & @@ -88,34 +83,8 @@ // Overrides the base class. virtual bool visit(const pappso::MsRunDataSetTreeNode &node) override; - virtual bool - checkProcessingStep(const ProcessingStep &step, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByRt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByMz( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByDt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - protected: MsRunDataSetStats m_msRunDataSetStats; - - // We almost systematically need these m/z range values when making visits: - // one criterium might be that the m/z value of data points (the x member of - // DataPoint) be contained within the limit m/z range. - double m_limitMzRangeStart = std::numeric_limits::max(); - double m_limitMzRangeEnd = std::numeric_limits::max(); }; diff -Nru minexpert2-7.4.1/src/nongui/MultiTreeNodeCombinerVisitor.cpp minexpert2-8.1.1/src/nongui/MultiTreeNodeCombinerVisitor.cpp --- minexpert2-7.4.1/src/nongui/MultiTreeNodeCombinerVisitor.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MultiTreeNodeCombinerVisitor.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -106,6 +106,8 @@ emit incrementProgressBarCurrentValueAndSetStatusTextSignal( 1, "Processed %c nodes"); + // Copy the node because we'll need to modify it later to hand it over to the + // visitors. pappso::MsRunDataSetTreeNode local_node = node; // qDebug() << "node copy:" << local_node.toString(); @@ -173,58 +175,6 @@ return true; } - -bool -MultiTreeNodeCombinerVisitor::checkProcessingStep( - [[maybe_unused]] const ProcessingStep &step, - [[maybe_unused]] const pappso::MsRunDataSetTreeNode &node) -{ - return true; -} - - -bool -MultiTreeNodeCombinerVisitor::checkProcessingSpec( - [[maybe_unused]] const std::pair - &type_spec_pair, - [[maybe_unused]] const pappso::MsRunDataSetTreeNode &node) -{ - return true; -} - - -bool -MultiTreeNodeCombinerVisitor::checkProcessingTypeByRt( - [[maybe_unused]] const std::pair - &type_spec_pair, - [[maybe_unused]] const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - return true; -} - - -bool -MultiTreeNodeCombinerVisitor::checkProcessingTypeByMz( - [[maybe_unused]] const std::pair - &type_spec_pair, - [[maybe_unused]] const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - return true; -} - - -bool -MultiTreeNodeCombinerVisitor::checkProcessingTypeByDt( - [[maybe_unused]] const std::pair - &type_spec_pair, - [[maybe_unused]] const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - return true; -} - void MultiTreeNodeCombinerVisitor::addVisitor( diff -Nru minexpert2-7.4.1/src/nongui/MultiTreeNodeCombinerVisitor.hpp minexpert2-8.1.1/src/nongui/MultiTreeNodeCombinerVisitor.hpp --- minexpert2-7.4.1/src/nongui/MultiTreeNodeCombinerVisitor.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/MultiTreeNodeCombinerVisitor.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -85,26 +85,6 @@ // Overrides the base class. virtual bool visit(const pappso::MsRunDataSetTreeNode &node) override; - virtual bool - checkProcessingStep(const ProcessingStep &step, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByRt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByMz( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByDt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - void addVisitor(BaseMsRunDataSetTreeNodeVisitorSPtr visitor_sp); protected: diff -Nru minexpert2-7.4.1/src/nongui/ProcessingFlow.cpp minexpert2-8.1.1/src/nongui/ProcessingFlow.cpp --- minexpert2-7.4.1/src/nongui/ProcessingFlow.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/ProcessingFlow.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -32,6 +32,7 @@ /////////////////////// StdLib includes +#include #include @@ -119,6 +120,13 @@ } +const pappso::MzIntegrationParams & +ProcessingFlow::getDefaultMzIntegrationParams() const +{ + return m_defaultMzIntegrationParams; +} + + void ProcessingFlow::setDefaultMsFragmentationSpec( const MsFragmentationSpec &ms_fragmentation_spec) @@ -129,13 +137,6 @@ } -const pappso::MzIntegrationParams & -ProcessingFlow::getDefaultMzIntegrationParams() const -{ - return m_defaultMzIntegrationParams; -} - - const MsFragmentationSpec & ProcessingFlow::getDefaultMsFragmentationSpec() const { @@ -159,172 +160,386 @@ bool ProcessingFlow::innermostRange( - ProcessingType type_mask, - std::pair &pair) const + ProcessingType src_processing_type_mask, + std::pair &out_range, + std::vector *out_processing_steps_p, + bool store_only_2d_steps, + bool store_only_skewed) const { - // Iterate in all the various ProcessingStep_s and check which of them has - // ProcessingSpec instances that match ProcessingType integrations and that is - // innermost of all. + qDebug() << "Searching for innermost range for source ProcessingType mask:" + << src_processing_type_mask.toBriefDesc() << "in a flow of" << size() + << "steps"; - double temp_start = std::numeric_limits::quiet_NaN(); - double temp_end = std::numeric_limits::quiet_NaN(); + // We are asked to get the innermost range for all steps having their + // processing type matching the processing_type_mask. - bool was_spec_found = false; - bool first_item = true; + // processing_type_mask specifies a source processing type, that might be + // someghing like "ANY_RT" or "ANY_DT" or "ANY_MZ". - // Remember that this processing flow is nothing but a vector of processing - // steps. + // We iterate in the steps of this processing flow and check that their source + // type matches processing_type_mask. If so, we look at the axis data kind and + // check for the innermost range. - for(auto &&step : *this) + ProcessingType src_processing_type("NOT_SET"); + ProcessingType x_src_processing_type("NOT_SET"); + ProcessingType y_src_processing_type("NOT_SET"); + + double inner_range_start = std::numeric_limits::quiet_NaN(); + double inner_range_end = std::numeric_limits::quiet_NaN(); + + bool is_first_iterated_item = true; + + ProcessingStep *innermost_step_p = nullptr; + + for(auto &&step_p : *this) { - // Now search in the various (processing type / processing spec) items of - // the step's map. + qDebug() << "Iterating in step:" << step_p->toString(); + + double range_start; + double range_end; + + ProcessingType iter_x_processing_type = step_p->m_xSrcType; + ProcessingType iter_y_processing_type = step_p->m_ySrcType; + + // qDebug() << "Iterating in ProcessingStep of x and y src types:" + //<< iter_x_processing_type.toBriefDesc() << "and" + //<< iter_y_processing_type.toBriefDesc(); - for(auto &&iter_pair : step->getProcessingTypeSpecMap()) + // Check the processing type. We may get here any kind of mono- or + // bi-dimensional processing type, like MZ_TO_ANY or DT_RT_TO_ANY. + + if(!iter_x_processing_type.bitMatches(src_processing_type_mask) && + !iter_y_processing_type.bitMatches(src_processing_type_mask)) { - if(!iter_pair.first.bitMatches(type_mask)) - continue; + qDebug() << "The iterated step has none of its source types matching " + "the searched type. Skipping it."; + + continue; + } - // Ah, there is a pair of interest, here, because the type key of - // the map pair matches the type passed as parameter. Before - // doing comparisons, we need to check if the processing spec has - // a valid range (m_start--m_end). If not we just skip the - // iter_pair, otherwise we make the checks. + // Is the currently iterated step mono- or two-dimensional ? - ProcessingSpec *spec_p = iter_pair.second; + bool is_2D = step_p->m_selectionPolygon.is2D(); - if(!spec_p->hasValidRange()) - continue; + if(!is_2D) + { + // This is the simplest situation, there is only one dimension, the x + // dimension, that is of interest. - // Because we look of a matching type item that has the more - // restricted range (that is, innermost range), we need to - // store the first item's range for later comparison. + qDebug() << "That step is 1D"; - if(first_item) + step_p->m_selectionPolygon.rangeX(range_start, range_end); + + if(is_first_iterated_item) { - temp_start = iter_pair.second->m_start; - temp_end = iter_pair.second->m_end; + inner_range_start = range_start; + inner_range_end = range_end; + + qDebug() << "First iterated step, with inner range:" + << inner_range_start << "-" << inner_range_end; - // qDebug() << "First item has range:" << temp_start << "->" - //<< temp_end; + if(!store_only_2d_steps) + { + qDebug() << "Even if 1D, setting step as innermost step as " + "requested."; + innermost_step_p = step_p; + } - first_item = false; + is_first_iterated_item = false; } else { - // We seek the *innermost* range, so be aware of the - // relational < > operators that may look used at reverse - // but are not. + qDebug() << "Not first iterated step."; + + // We now have to update the innermost range values. + + bool was_one_dimension_inner = false; - if(iter_pair.second->m_start > temp_start) - temp_start = iter_pair.second->m_start; + if(range_start > inner_range_start) + { + inner_range_start = range_start; - if(iter_pair.second->m_end < temp_end) - temp_end = iter_pair.second->m_end; + was_one_dimension_inner = true; - // qDebug() << "New item has range:" << iter_pair.second->m_start - //<< "-" << iter_pair.second->m_end; + qDebug() << "New inner range start:" << inner_range_start; + } + + if(range_end < inner_range_end) + { + inner_range_end = range_end; + + was_one_dimension_inner = true; + qDebug() << "New inner range end:" << inner_range_end; + } + + if(was_one_dimension_inner && !store_only_2d_steps) + { + qDebug() << "Even if 1D, setting step as innermost step as " + "requested."; + innermost_step_p = step_p; + } } - // We found at least one item! - was_spec_found = true; + continue; } - - if(was_spec_found) + else { + qDebug() << "That step is 2D"; + + // At this point, we know the selection polygon is 2D, which means we + // have to check what actual source types has the iterated step + // because we need to know what is the type of the different selection + // polygon axes. + + if(step_p->m_xSrcType.bitMatches(src_processing_type_mask)) + { + qDebug() << "Step's m_xSrcType.bitMatches" + << src_processing_type_mask.toBriefDesc(); + + // The x axis is the axis we need to check the innermost range of. + + step_p->m_selectionPolygon.rangeX(range_start, range_end); + + qDebug() << "Gotten range values:" << range_start << "-" + << range_end; + } + else if(step_p->m_ySrcType.bitMatches(src_processing_type_mask)) + { + qDebug() << "Step's m_ySrcType.bitMatches" + << src_processing_type_mask.toBriefDesc(); + + // The y axis is the axis we need to check the innermost range of. + + step_p->m_selectionPolygon.rangeY(range_start, range_end); + + qDebug() << "Gotten range values:" << range_start << "-" + << range_end; + } + else + qFatal("Programming error."); + + if(is_first_iterated_item) + { + inner_range_start = range_start; + inner_range_end = range_end; + + qDebug() << "First iterated step, with inner range:" + << inner_range_start << "-" << inner_range_end; - // Set the pair to the parameter. We may change it later, but - // for the moment, that is. - pair.second->setRange(temp_start, temp_end); + qDebug() << "Setting step as innermost step."; + innermost_step_p = step_p; - // qDebug() << "Set the new range:" << pair.second->getStart() << "->" - //<< pair.second->getEnd(); + is_first_iterated_item = false; + } + else + { + qDebug() << "Not first iterated step."; + + // We now have to update the innermost range values. + + bool was_one_dimension_inner = false; + + if(range_start > inner_range_start) + { + inner_range_start = range_start; + + was_one_dimension_inner = true; + + qDebug() << "New inner range start:" << inner_range_start; + } + + if(range_end < inner_range_end) + { + inner_range_end = range_end; + + was_one_dimension_inner = true; + + qDebug() << "New inner range end:" << inner_range_end; + } + + if(was_one_dimension_inner) + { + qDebug() << "Setting step as innermost step."; + innermost_step_p = step_p; + } + } + + // Done, go to next step. + continue; } } - return was_spec_found; -} + qDebug() << "Finished iterating in the vector of steps."; + // At this point we have iterated in all the steps. To know if at least one + // step was found matching the src_processing_type_mask, we can test the + // inner_range_xxx values against min and max. -bool -ProcessingFlow::innermostRange(ProcessingType type_mask, - double &start, - double &end) const -{ - ProcessingSpec spec; + if(std::isnan(inner_range_start) || std::isnan(inner_range_end)) + return false; - std::pair pair(type_mask, &spec); + // We know we can update the values in the variables passed as out params. + out_range.first = inner_range_start; + out_range.second = inner_range_end; - bool res = innermostRange(type_mask, pair); + // If the callers provides a vector of steps, then document the step. + // Check for options, nonetheless. - if(!res) - return false; + bool should_store_the_step_in_the_end = false; + + if(out_processing_steps_p != nullptr) + { + qDebug() << "The caller wants the innermost step to be stored."; + + if(innermost_step_p != nullptr) + { + qDebug() << "One innermost step was indeed found."; + + if(!store_only_skewed) + { + qDebug() + << "The caller wants *all* 2D steps, not only the skewed ones."; + should_store_the_step_in_the_end = true; + } + else + { + if(!innermost_step_p->getSelectionPolygon().isRectangle()) + { + should_store_the_step_in_the_end = true; + qDebug() << "The caller wants *only* the 2D skewed steps and " + "the step *is* skewed"; + } + else + { + qDebug() << "The caller wants *only* the 2D skewed steps and " + "the step is *not* skewed"; + } + } + } + else + qDebug() << "Not a single step was found."; + } + else + qDebug() << "The caller does *not* want the innermost step to be stored."; + + // At this point, if we have to store the step, check that another + // call by another processing type mask has not set it already + // (typically ANY_RT and ANY_DT with steps DT_RT). - start = pair.second->getStart(); - end = pair.second->getEnd(); + if(should_store_the_step_in_the_end) + { + qDebug() << "Really, the step should be stored."; + + // We only push back the range if it has not been found + // already. Note that this function might called multiple + // times with different src_processing_type_mask values. + + bool was_step_found = false; + + for(auto &&iter_step : *out_processing_steps_p) + { + if(iter_step.m_dateAndTime == innermost_step_p->m_dateAndTime) + { + was_step_found = true; + + qDebug() << "Did not store the step because it had been " + "stored already."; + + break; + } + } + + if(!was_step_found) + { + qDebug() << "The step is actually skewed, so storing it:" + << innermost_step_p->toString(); + + out_processing_steps_p->push_back(*innermost_step_p); + } + } + + // Always return true because we had returned false already when we + // discovered that the processing types did not match. return true; } bool -ProcessingFlow::innermostRtRange(double &start, double &end) const +ProcessingFlow::innermostRange( + const QString src_processing_type_mask, + std::pair &out_range, + std::vector *out_processing_steps_p, + bool store_only_2d_steps, + bool store_only_skewed) const { - return innermostRange(ProcessingType("RT_TO_ANY"), start, end); + return innermostRange(ProcessingType(src_processing_type_mask), + out_range, + out_processing_steps_p, + store_only_2d_steps, + store_only_skewed); } +#if 0 bool ProcessingFlow::innermostRtRange( - std::pair &pair) const + std::pair &pair) const { return innermostRange(ProcessingType("RT_TO_ANY"), pair); } bool -ProcessingFlow::innermostDtRange(double &start, double &end) const +ProcessingFlow::innermostMzRange(double &range_start, double &range_end) const { - return innermostRange(ProcessingType("DT_TO_ANY"), start, end); + return innermostRange(ProcessingType("MZ_TO_ANY"), range_start, range_end); } bool -ProcessingFlow::innermostDtRange( - std::pair &pair) const +ProcessingFlow::innermostMzRange( + std::pair &pair) const { - return innermostRange(ProcessingType("DT_TO_ANY"), pair); + return innermostRange(ProcessingType("MZ_TO_ANY"), pair); } +#endif + bool -ProcessingFlow::innermostMzRange(double &start, double &end) const +ProcessingFlow::hasOnly1DSteps() { - return innermostRange(ProcessingType("MZ_TO_ANY"), start, end); -} + // We want to know if all the steps in this processing flow have 1D + // selection polygons. + bool is_2D = false; -bool -ProcessingFlow::innermostMzRange( - std::pair &pair) const -{ - return innermostRange(ProcessingType("MZ_TO_ANY"), pair); + for(auto &&step_p : *this) + { + if(step_p->hasValidSelectionPolygon(is_2D)) + if(is_2D) + return false; + } + + return true; } size_t ProcessingFlow::greatestMsLevel() const { - // We want to know what is the greatest MS level in the default ms frag spec - // and in all the ms frag specs of the various processing specs. + // We want to know what is the greatest MS level in the default ms + // frag spec and in all the ms frag specs of the various processing + // specs. size_t greatest_ms_level = m_defaultMsFragmentationSpec.getMsLevel(); for(auto &&step : *this) { - if(step->greatestMsLevel() > greatest_ms_level) + if(step->getMsLevel() > greatest_ms_level) { - greatest_ms_level = step->greatestMsLevel(); + greatest_ms_level = step->getMsLevel(); } } @@ -338,8 +553,8 @@ const ProcessingStep * ProcessingFlow::oldestStep() const { - // We rely on the QDateTime instance in the steps to check which of the step - // was created last. + // We rely on the QDateTime instance in the steps to check which of + // the step was created last. if(!size()) return nullptr; @@ -349,7 +564,8 @@ const ProcessingStep *oldest_step_p = front(); - // Seed the temporary date and time with the first step in the vector. + // Seed the temporary date and time with the first step in the + // vector. QDateTime temp_date_time = front()->m_dateAndTime; for(std::vector::const_iterator iterator = begin() + 1; @@ -371,40 +587,75 @@ const ProcessingStep * ProcessingFlow::mostRecentStep() const { - // We rely on the QDateTime instance in the steps to check which of the step - // was created last. + // We rely on the QDateTime instance in the steps to check which of + // the step was created last. + // Calling from on an empty container causes undefined behaviour. if(!size()) return nullptr; if(size() == 1) return front(); - const ProcessingStep *most_recent_step_p = front(); - QDateTime date_time = most_recent_step_p->m_dateAndTime; + const ProcessingStep *most_recent_step_p = nullptr; - for(std::vector::const_iterator iterator = begin() + 1; - iterator != end(); - ++iterator) + QDateTime date_time; + date_time.setDate(QDate(1900, 1, 1)); + + for(auto &&step_p : *this) { // qDebug(); - if((*iterator)->m_dateAndTime > date_time) - most_recent_step_p = *iterator; + if(step_p->m_dateAndTime > date_time) + most_recent_step_p = step_p; } return most_recent_step_p; } +std::vector +ProcessingFlow::stepsMatchingDestType(const ProcessingType &processing_type, + bool with_valid_fragmentation_spec) const +{ + std::vector processing_steps; + + for(auto &&step_p : *this) + { + if(step_p->m_destType.bitMatches(processing_type)) + { + if(with_valid_fragmentation_spec) + { + if(step_p->getMsFragmentationSpec().isValid()) + processing_steps.push_back(step_p); + } + else + processing_steps.push_back(step_p); + } + } + + return processing_steps; +} + + +std::vector +ProcessingFlow::stepsMatchingDestType(const QString &processing_type, + bool with_valid_fragmentation_spec) const +{ + return stepsMatchingDestType(ProcessingType(processing_type), + with_valid_fragmentation_spec); +} + + const ProcessingStep * ProcessingFlow::closestOlderStep(const QDateTime &date_time) const { // qDebug() << "comparison date time:" << date_time //<< "number of steps:" << size(); - // We want a step that is older than date_time. But we also want that the - // step be the most recent older step, that is, the closest older step. + // We want a step that is older than date_time. But we also want + // that the step be the most recent older step, that is, the closest + // older step. if(!size()) return nullptr; @@ -412,7 +663,8 @@ { if(front()->m_dateAndTime < date_time) { - // qDebug() << "Returning unique older:" << front()->m_dateAndTime; + // qDebug() << "Returning unique older:" << + // front()->m_dateAndTime; return front(); } } @@ -420,7 +672,8 @@ return nullptr; - // Seed the temporary date time with the oldest step's date and time. + // Seed the temporary date time with the oldest step's date and + // time. const ProcessingStep *older_step_p = nullptr; @@ -428,29 +681,31 @@ iterator != end(); ++iterator) { - // qDebug() << "Iterating in time:" << (*iterator)->m_dateAndTime; + // qDebug() << "Iterating in time:" << + // (*iterator)->m_dateAndTime; if((*iterator)->m_dateAndTime < date_time) { - // qDebug() << "iter time is less than comparison date time."; + // qDebug() << "iter time is less than comparison date + // time."; if(older_step_p == nullptr) { - // First iteration for which the date is less than comparison - // time. + // First iteration for which the date is less than + // comparison time. older_step_p = *iterator; continue; } - // The currently iterated step is older than date_time, fine, but is - // it more recent that the temporaray time ? If + // The currently iterated step is older than date_time, + // fine, but is it more recent that the temporaray time ? If // so set it as the last older step. if((*iterator)->m_dateAndTime > older_step_p->m_dateAndTime) { - // qDebug() << "more than that: iter time is also more recent than - // " "last itered time."; + // qDebug() << "more than that: iter time is also more + // recent than " "last itered time."; older_step_p = *iterator; } @@ -474,21 +729,22 @@ if(most_recent_step_p->mpa_mzIntegrationParams != nullptr) { // qDebug() - //<< "Returning immediately the most recent step's mz integ. params."; + //<< "Returning immediately the most recent step's mz integ. + // params."; return most_recent_step_p->mpa_mzIntegrationParams; } } else { - // qDebug() << "Not a single most recent step there. The flow seems - // empty."; - // Apparently there is not a single step in the processing flow. + // qDebug() << "Not a single most recent step there. The flow + // seems empty."; Apparently there is not a single step in the + // processing flow. return nullptr; } - // If the most recent step had no mz integration params set, we need to - // iterate back in time. + // If the most recent step had no mz integration params set, we need + // to iterate back in time. while(1) { // Get a step older than the most recent step. @@ -499,14 +755,17 @@ if(closest_older_step_p != nullptr) { // qDebug() - //<< "iterating in infinite while loop with closest older step time:" + //<< "iterating in infinite while loop with closest older + // step + // time:" //<< closest_older_step_p->m_dateAndTime; - // Found an older step, but check if it has mz integration params set - // to it. + // Found an older step, but check if it has mz integration + // params set to it. if(closest_older_step_p->mpa_mzIntegrationParams != nullptr) { - // qDebug() << "Found a step that is closest and that has mz " + // qDebug() << "Found a step that is closest and that + // has mz " //"integration params."; return closest_older_step_p->mpa_mzIntegrationParams; @@ -521,7 +780,8 @@ { // There are no more older steps. // qDebug() - //<< "There are no more closest older steps. Returning nullptr"; + //<< "There are no more closest older steps. Returning + // nullptr"; return nullptr; } @@ -545,7 +805,10 @@ // text += lead; // text += spacer; text += "Sample name:\n"; - text += mcsp_msRunDataSet->getMsRunId()->getSampleName(); + if(mcsp_msRunDataSet == nullptr) + text += "nullptr"; + else + text += mcsp_msRunDataSet->getMsRunId()->getSampleName(); text += "\n\n"; // text += lead; diff -Nru minexpert2-7.4.1/src/nongui/ProcessingFlow.hpp minexpert2-8.1.1/src/nongui/ProcessingFlow.hpp --- minexpert2-7.4.1/src/nongui/ProcessingFlow.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/ProcessingFlow.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -46,8 +46,8 @@ /////////////////////// Local includes -#include "ProcessingStep.hpp" #include "MsRunDataSet.hpp" +#include "MsFragmentationSpec.hpp" namespace msxps @@ -55,6 +55,8 @@ namespace minexpert { +class ProcessingType; +class ProcessingStep; class ProcessingFlow : public std::vector { @@ -70,18 +72,22 @@ std::vector steps(); - bool innermostRange(ProcessingType type_mask, - std::pair &pair) const; - bool innermostRange(ProcessingType type_mask, double &start, double &end) const; + bool innermostRange( + ProcessingType src_processing_type_mask, + std::pair &out_range, + std::vector *out_processing_steps_p = nullptr, + bool store_only_2d_steps = true, + bool store_only_skewed = true) const; + + bool innermostRange( + const QString src_processing_type_mask, + std::pair &out_range, + std::vector *out_processing_steps_p = nullptr, + bool store_only_2d_steps = true, + bool store_only_skewed = true) const; - bool innermostRtRange(std::pair &pair) const; - bool innermostRtRange(double &start, double &end) const; - bool innermostDtRange(std::pair &pair) const; - bool innermostDtRange(double &start, double &end) const; - - bool innermostMzRange(std::pair &pair) const; - bool innermostMzRange(double &start, double &end) const; + bool hasOnly1DSteps(); size_t greatestMsLevel() const; @@ -89,6 +95,14 @@ const ProcessingStep *closestOlderStep(const QDateTime &date_time) const; const ProcessingStep *mostRecentStep() const; + std::vector + stepsMatchingDestType(const ProcessingType &processing_type, + bool with_valid_fragmentation_spec = false) const; + + std::vector + stepsMatchingDestType(const QString &processing_type, + bool with_valid_fragmentation_spec = false) const; + void setDefaultMzIntegrationParams( const pappso::MzIntegrationParams &mz_integration_params); const pappso::MzIntegrationParams &getDefaultMzIntegrationParams() const; @@ -106,10 +120,10 @@ protected: MsRunDataSetCstSPtr mcsp_msRunDataSet = nullptr; - // Note that each step has an optional pappso::MzIntegrationParams *. This one is the - // default one when not a single step has mz integration params. This one is - // set automatically in the first graph obtained when displaying the TIC - // chromatogram right after having loaded the ms run from file. + // Note that each step has an optional pappso::MzIntegrationParams *. This one + // is the default one when not a single step has mz integration params. This + // one is set automatically in the first graph obtained when displaying the + // TIC chromatogram right after having loaded the ms run from file. pappso::MzIntegrationParams m_defaultMzIntegrationParams; // Same for MsFragmentationSpec diff -Nru minexpert2-7.4.1/src/nongui/ProcessingSpec.cpp minexpert2-8.1.1/src/nongui/ProcessingSpec.cpp --- minexpert2-7.4.1/src/nongui/ProcessingSpec.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/ProcessingSpec.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,242 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright(C) 2009,...,2019 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -/////////////////////// StdLib includes - - -/////////////////////// Qt includes - - -/////////////////////// pappsomspp includes - - -/////////////////////// Local includes -#include "ProcessingSpec.hpp" -#include "MsFragmentationSpec.hpp" - - -namespace msxps -{ -namespace minexpert -{ - -ProcessingSpec::ProcessingSpec() -{ -} - - -ProcessingSpec::ProcessingSpec(const MsFragmentationSpec &ms_fragmentation_spec) -{ - mpa_msFragmentationSpec = new MsFragmentationSpec(ms_fragmentation_spec); -} - - -ProcessingSpec::ProcessingSpec(double start_value, double end_value) - : m_start(start_value), m_end(end_value) -{ -} - - -ProcessingSpec::ProcessingSpec(const MsFragmentationSpec &ms_fragmentation_spec, - double start_value, - double end_value) - : mpa_msFragmentationSpec(new MsFragmentationSpec(ms_fragmentation_spec)), - m_start(start_value), - m_end(end_value) -{ -} - - -ProcessingSpec::ProcessingSpec(const ProcessingSpec &other) -{ - if(other.mpa_msFragmentationSpec != nullptr) - mpa_msFragmentationSpec = - new MsFragmentationSpec(*other.mpa_msFragmentationSpec); - - m_start = other.m_start; - m_end = other.m_end; -} - - -ProcessingSpec::~ProcessingSpec() -{ - if(mpa_msFragmentationSpec != nullptr) - delete mpa_msFragmentationSpec; -} - - -ProcessingSpec & -ProcessingSpec::operator=(const ProcessingSpec &other) -{ - if(this == &other) - return *this; - - if(other.mpa_msFragmentationSpec != nullptr) - mpa_msFragmentationSpec = - new MsFragmentationSpec(*other.mpa_msFragmentationSpec); - - m_start = other.m_start; - m_end = other.m_end; - - return *this; -} - - -void -ProcessingSpec::setMsFragmentationSpec( - const MsFragmentationSpec &fragmentation_spec) -{ - if(mpa_msFragmentationSpec != nullptr) - delete mpa_msFragmentationSpec; - - mpa_msFragmentationSpec = new MsFragmentationSpec(fragmentation_spec); -} - - -MsFragmentationSpec -ProcessingSpec::getMsFragmentationSpec() const -{ - if(mpa_msFragmentationSpec != nullptr) - return *mpa_msFragmentationSpec; - - return MsFragmentationSpec(); -} - - -MsFragmentationSpec * -ProcessingSpec::getMsFragmentationSpecPtr() -{ - return mpa_msFragmentationSpec; -} - - -double -ProcessingSpec::getStart() const -{ - return m_start; -} - - -double -ProcessingSpec::getEnd() const -{ - return m_end; -} - - -void -ProcessingSpec::setRange(double start, double end) -{ - m_start = start; - m_end = end; -} - - -void -ProcessingSpec::resetRange() -{ - m_start = std::numeric_limits::max(); - m_end = std::numeric_limits::min(); -} - - -bool -ProcessingSpec::hasValidRange() const -{ - return (m_start < std::numeric_limits::max() && - m_end > std::numeric_limits::min()); -} - - -bool -ProcessingSpec::hasValidFragmentationSpec() const -{ - if(mpa_msFragmentationSpec != nullptr) - return mpa_msFragmentationSpec->isValid(); - else - return false; -} - - -QString -ProcessingSpec::toString(int offset, - const QString &spacer, - const ProcessingType &processing_type) const -{ - QString lead; - - for(int iter = 0; iter < offset; ++iter) - lead += spacer; - - QString text = lead; - - text += "Processing spec:\n"; - - text += lead; - text += spacer; - text += "Type: "; - text += processing_type.toString(); - text += "\n"; - - QString start_string; - if(m_start == std::numeric_limits::max()) - start_string = "not set"; - else - start_string = QString("%1").arg(m_start, 0, 'f', 6); - - QString end_string; - if(m_end == std::numeric_limits::min()) - end_string = "not set"; - else - end_string = QString("%1").arg(m_end, 0, 'f', 6); - - text += lead; - text += spacer; - text += - QString("Integration range: [%1 -- %2]").arg(start_string).arg(end_string); - - text += "\n"; - - if(mpa_msFragmentationSpec && mpa_msFragmentationSpec->isValid()) - { - text += mpa_msFragmentationSpec->toString(offset + 1, spacer); - // text += "\n"; - } - - return text; -} - - -} // namespace minexpert - -} // namespace msxps diff -Nru minexpert2-7.4.1/src/nongui/ProcessingSpec.hpp minexpert2-8.1.1/src/nongui/ProcessingSpec.hpp --- minexpert2-7.4.1/src/nongui/ProcessingSpec.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/ProcessingSpec.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright(C) 2009,...,2019 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -#pragma once - -/////////////////////// StdLib includes -#include -#include -#include - - -/////////////////////// Qt includes -#include -#include - - -/////////////////////// pappsomspp includes - - -/////////////////////// Local includes -#include "MsFragmentationSpec.hpp" -#include -#include "ProcessingType.hpp" - - -namespace msxps -{ -namespace minexpert -{ - - -class ProcessingSpec -{ - friend class ProcessingStep; - friend class ProcessingFlow; - - public: - ProcessingSpec(); - ProcessingSpec(const ProcessingSpec &other); - ProcessingSpec(double start_value, double end_value); - ProcessingSpec(const MsFragmentationSpec &ms_fragmentation_spec); - ProcessingSpec(const MsFragmentationSpec &ms_fragmentation_spec, - double start_value, - double end_value); - virtual ~ProcessingSpec(); - - ProcessingSpec &operator=(const ProcessingSpec &other); - - void setMsFragmentationSpec(const MsFragmentationSpec &fragmentation_spec); - MsFragmentationSpec getMsFragmentationSpec() const; - MsFragmentationSpec *getMsFragmentationSpecPtr(); - - double getStart() const; - double getEnd() const; - void setRange(double start, double end); - void resetRange(); - bool hasValidRange() const; - - bool hasValidFragmentationSpec() const; - - QString toString( - int offset = 0, - const QString &spacer = QString(), - const ProcessingType &processing_type = ProcessingType("NOT_SET")) const; - - protected: - // The ms fragmentation pattern is optional here. If non-nullptr it is - // considered to be enforceable. - MsFragmentationSpec *mpa_msFragmentationSpec = nullptr; - - double m_start = std::numeric_limits::max(); - double m_end = std::numeric_limits::min(); -}; - - -} // namespace minexpert - -} // namespace msxps diff -Nru minexpert2-7.4.1/src/nongui/ProcessingStep.cpp minexpert2-8.1.1/src/nongui/ProcessingStep.cpp --- minexpert2-7.4.1/src/nongui/ProcessingStep.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/ProcessingStep.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -52,36 +52,61 @@ ProcessingStep::ProcessingStep() + : m_dateAndTime(QDateTime::currentDateTimeUtc()) { - m_dateAndTime = QDateTime::currentDateTimeUtc(); } -ProcessingStep::ProcessingStep(const ProcessingStep &other) +ProcessingStep::ProcessingStep( + const pappso::SelectionPolygon &selection_polygon) + : m_dateAndTime(QDateTime::currentDateTimeUtc()), + m_selectionPolygon(selection_polygon) { - m_dateAndTime = other.m_dateAndTime; +} + + +ProcessingStep::ProcessingStep(const MsFragmentationSpec &ms_fragmentation_spec) + : m_dateAndTime(QDateTime::currentDateTimeUtc()) +{ + mpa_msFragmentationSpec = new MsFragmentationSpec(ms_fragmentation_spec); +} + +ProcessingStep::ProcessingStep(const MsFragmentationSpec &ms_fragmentation_spec, + const pappso::SelectionPolygon selection_polygon) + : m_dateAndTime(QDateTime::currentDateTimeUtc()), + m_selectionPolygon(selection_polygon) +{ + mpa_msFragmentationSpec = new MsFragmentationSpec(ms_fragmentation_spec); +} + + +ProcessingStep::ProcessingStep(const ProcessingStep &other) + : m_dateAndTime(other.m_dateAndTime), + m_xSrcType(other.m_xSrcType), + m_ySrcType(other.m_ySrcType), + m_destType(other.m_destType), + m_selectionPolygon(other.m_selectionPolygon), + m_xAxisDataKind(other.m_xAxisDataKind), + m_yAxisDataKind(other.m_yAxisDataKind) +{ if(other.mpa_mzIntegrationParams != nullptr) mpa_mzIntegrationParams = new pappso::MzIntegrationParams(*other.mpa_mzIntegrationParams); - for(auto &&type_spec_pair : other.m_processingTypeSpecMultiMap) - { - ProcessingType processing_type = type_spec_pair.first; - - m_processingTypeSpecMultiMap.insert( - std::pair( - processing_type, new ProcessingSpec(*type_spec_pair.second))); - } + if(other.mpa_msFragmentationSpec != nullptr) + mpa_msFragmentationSpec = + new MsFragmentationSpec(*other.mpa_msFragmentationSpec); } ProcessingStep::~ProcessingStep() { - m_processingTypeSpecMultiMap.clear(); - if(mpa_mzIntegrationParams != nullptr) delete mpa_mzIntegrationParams; + + if(mpa_msFragmentationSpec != nullptr) + delete mpa_msFragmentationSpec; } @@ -93,289 +118,299 @@ m_dateAndTime = other.m_dateAndTime; + m_xSrcType = other.m_xSrcType; + m_ySrcType = other.m_ySrcType; + + m_destType = other.m_destType; + + m_selectionPolygon = other.m_selectionPolygon; + + m_xAxisDataKind = other.m_xAxisDataKind; + m_yAxisDataKind = other.m_yAxisDataKind; + if(other.mpa_mzIntegrationParams != nullptr) mpa_mzIntegrationParams = new pappso::MzIntegrationParams(*other.mpa_mzIntegrationParams); - for(auto &&item : m_processingTypeSpecMultiMap) - { - m_processingTypeSpecMultiMap.insert( - std::pair( - item.first, new ProcessingSpec(*item.second))); - } + if(other.mpa_msFragmentationSpec != nullptr) + mpa_msFragmentationSpec = + new MsFragmentationSpec(*other.mpa_msFragmentationSpec); return *this; } void -ProcessingStep::setMzIntegrationParams( - const pappso::MzIntegrationParams &mz_integration_params) +ProcessingStep::setSrcProcessingType(pappso::Axis axis, + const ProcessingType &processing_type) { - mpa_mzIntegrationParams = new pappso::MzIntegrationParams(mz_integration_params); + if(axis == pappso::Axis::x) + m_xSrcType = processing_type; + else if(axis == pappso::Axis::y) + m_ySrcType = processing_type; + else + qFatal("Programming error."); } -const pappso::MzIntegrationParams * -ProcessingStep::getMzIntegrationParamsPtr() const +void +ProcessingStep::setSrcProcessingType(pappso::Axis axis, + const QString &processing_type) { - return mpa_mzIntegrationParams; + return setSrcProcessingType(axis, ProcessingType(processing_type)); } -void -ProcessingStep::newSpec(ProcessingType processing_type, - ProcessingSpec *processing_spec_p) +ProcessingType +ProcessingStep::getSrcProcessingType(pappso::Axis axis) const { - if(processing_spec_p == nullptr) - qFatal("The pointer cannot be nullptr"); + if(axis == pappso::Axis::x) + return m_xSrcType; + else if(axis == pappso::Axis::y) + return m_ySrcType; - m_processingTypeSpecMultiMap.insert( - std::pair(processing_type, - processing_spec_p)); + return ProcessingType("NOT_SET"); } -ProcessingSpec * -ProcessingStep::newSpec(ProcessingType processing_type, - const ProcessingSpec &processing_spec) +void +ProcessingStep::setDestProcessingType(const ProcessingType &processing_type) { - ProcessingSpec *new_spec_p = new ProcessingSpec(processing_spec); + m_destType = processing_type; +} - m_processingTypeSpecMultiMap.insert( - std::pair(processing_type, new_spec_p)); +void +ProcessingStep::setDestProcessingType(const QString &processing_type) +{ + setDestProcessingType(ProcessingType(processing_type)); +} - return new_spec_p; +ProcessingType +ProcessingStep::getDestProcessingType() const +{ + return m_destType; } void -ProcessingStep::newSpec(const QString &brief_desc, - ProcessingSpec *processing_spec_p) +ProcessingStep::setSelectionPolygon( + const pappso::SelectionPolygon &selection_polygon) { - // We take ownership of the processing_spec_p - m_processingTypeSpecMultiMap.insert( - std::pair(ProcessingType(brief_desc), - processing_spec_p)); + m_selectionPolygon = selection_polygon; } -void -ProcessingStep::newSpec(std::bitset<128> bit_set, - ProcessingSpec *processing_spec_p) +const pappso::SelectionPolygon & +ProcessingStep::getSelectionPolygon() const { - // We take ownership of the processing_spec_p - m_processingTypeSpecMultiMap.insert( - std::pair(ProcessingType(bit_set), - processing_spec_p)); + return m_selectionPolygon; } -const std::multimap & -ProcessingStep::getProcessingTypeSpecMap() const +void +ProcessingStep::resetSelectionPolygon() { - return m_processingTypeSpecMultiMap; + m_selectionPolygon.resetPoints(); } -std::vector -ProcessingStep::processingTypes() const +bool +ProcessingStep::hasValidSelectionPolygon(bool &is_2D) const { - std::vector processing_types; - - for(auto &&iter_pair : m_processingTypeSpecMultiMap) + if(m_selectionPolygon.is1D()) { - bool found = false; - for(auto &&type : processing_types) - { - if(type == iter_pair.first) - { - found = true; - } - } + is_2D = false; + return true; + } - if(!found) - processing_types.push_back(iter_pair.first); + if(m_selectionPolygon.is2D()) + { + is_2D = true; + return true; } - return processing_types; + return false; } -bool -ProcessingStep::matches(std::bitset<128> bit_set) const +void +ProcessingStep::setDataKind(pappso::Axis axis, pappso::DataKind data_kind) { + if(static_cast(axis) & static_cast(pappso::Axis::x)) + m_xAxisDataKind = data_kind; + else if(static_cast(axis) & static_cast(pappso::Axis::y)) + m_yAxisDataKind = data_kind; + else + qFatal("The axis provided is not correct."); +} + - // A processing step hold a map relating any number of ProcessingType objects - // with a corresponding ProcessingSpec pointer. - // - // We need to go through all of these map items and for each check if it - // matches the processing type described by the \p bit_set. +pappso::DataKind +ProcessingStep::getDataKind(pappso::Axis axis) const +{ + if(static_cast(axis) & static_cast(pappso::Axis::x)) + return m_xAxisDataKind; + else if(static_cast(axis) & static_cast(pappso::Axis::y)) + return m_yAxisDataKind; + else + qFatal("The axis provided is not correct."); +} - using Pair = std::pair; - using Map = std::map; - Map::const_iterator iterator = std::find_if( - m_processingTypeSpecMultiMap.begin(), - m_processingTypeSpecMultiMap.end(), - [bit_set](const Pair &pair) { return pair.first.bitMatches(bit_set); }); +bool +ProcessingStep::getRangeForAxis(pappso::Axis axis, + double &range_start, + double &range_end) const +{ + return m_selectionPolygon.range(axis, range_start, range_end); +} - if(iterator != m_processingTypeSpecMultiMap.end()) - return true; - return false; +bool +ProcessingStep::getRangeForAxisX(double &range_start, double &range_end) const +{ + return getRangeForAxis(pappso::Axis::x, range_start, range_end); } bool -ProcessingStep::matches(ProcessingType type) const +ProcessingStep::getRangeForAxisY(double &range_start, double &range_end) const +{ + return getRangeForAxis(pappso::Axis::y, range_start, range_end); +} + + +void +ProcessingStep::setMzIntegrationParams( + const pappso::MzIntegrationParams &mz_integration_params) { - // qDebug() << "type's brief_desc:" << type.getBriefDesc() << "with bitset:" - //<< QString::fromStdString( - // ProcessingType::bitSet(type.getBriefDesc()).to_string()) - //<< "and this bitset:" - //<< QString::fromStdString( - // ProcessingType::bitSet(type.getBriefDesc()).to_string()); + mpa_mzIntegrationParams = + new pappso::MzIntegrationParams(mz_integration_params); +} - return ProcessingStep::matches(type.bitSet()); + +const pappso::MzIntegrationParams * +ProcessingStep::getMzIntegrationParamsPtr() const +{ + return mpa_mzIntegrationParams; } -bool -ProcessingStep::matches(const QString &brief_desc) const +void +ProcessingStep::setMsFragmentationSpec( + const MsFragmentationSpec &fragmentation_spec) { - // qDebug() - //<< "brief_desc:" << brief_desc << "with bitset:" - //<< QString::fromStdString(ProcessingType::bitSet(brief_desc).to_string()) - //<< "and this bitset:" - //<< QString::fromStdString(ProcessingType::bitSet(brief_desc).to_string()); + if(mpa_msFragmentationSpec != nullptr) + delete mpa_msFragmentationSpec; - return ProcessingStep::matches(ProcessingType::bitSet(brief_desc)); + mpa_msFragmentationSpec = new MsFragmentationSpec(fragmentation_spec); } -bool -ProcessingStep::contains(const QString &brief_desc) const +MsFragmentationSpec +ProcessingStep::getMsFragmentationSpec() const { - using Pair = std::pair; - using Map = std::map; + if(mpa_msFragmentationSpec != nullptr) + return *mpa_msFragmentationSpec; - Map::const_iterator iterator = - std::find_if(m_processingTypeSpecMultiMap.begin(), - m_processingTypeSpecMultiMap.end(), - [brief_desc](const Pair &pair) { - return pair.first.getBriefDesc() == brief_desc; - }); + return MsFragmentationSpec(); +} - if(iterator != m_processingTypeSpecMultiMap.end()) - return true; - return false; +MsFragmentationSpec * +ProcessingStep::getMsFragmentationSpecPtr() +{ + return mpa_msFragmentationSpec; } size_t -ProcessingStep::greatestMsLevel() const +ProcessingStep::getMsLevel() const { + if(mpa_msFragmentationSpec != nullptr && mpa_msFragmentationSpec->isValid()) + return mpa_msFragmentationSpec->getMsLevel(); - size_t greatest_ms_level = 0; + return 0; +} - using Map = std::map; - using Iterator = Map::const_iterator; - for(Iterator iterator = m_processingTypeSpecMultiMap.begin(); - iterator != m_processingTypeSpecMultiMap.end(); - ++iterator) - { - auto &&pair = *iterator; +bool +ProcessingStep::hasValidFragmentationSpec() const +{ + if(mpa_msFragmentationSpec != nullptr) + return mpa_msFragmentationSpec->isValid(); + else + return false; +} + + +bool +ProcessingStep::isValid() const +{ + // A valid processing step has necessarily valid processing types and a valid + // selection polygon and valid axis data kinds. - ProcessingSpec *processing_spec_p = pair.second; + if(ProcessingType::compare(m_xSrcType, ProcessingType("NOT_SET"))) + return false; - MsFragmentationSpec *ms_fragmentation_spec_p = - processing_spec_p->getMsFragmentationSpecPtr(); + // We do not check the m_ySrcType because if the starting point is not + // bidimensional, that value is rightfully NOT_SET. - if(ms_fragmentation_spec_p != nullptr && - ms_fragmentation_spec_p->isValid()) - { - if(ms_fragmentation_spec_p->getMsLevel() > greatest_ms_level) - greatest_ms_level = ms_fragmentation_spec_p->getMsLevel(); - } - } + // The destination type cannot be unset because that would not mean anything + // from an integration stand point. + if(ProcessingType::compare(m_destType, ProcessingType("NOT_SET"))) + return false; + + if(!m_selectionPolygon.is1D() && !m_selectionPolygon.is2D()) + return false; - return greatest_ms_level; + if(m_xAxisDataKind == pappso::DataKind::unset || + m_yAxisDataKind == pappso::DataKind::unset) + return false; + + return true; } -std::vector -ProcessingStep::allProcessingSpecsMatching( - const ProcessingType &processing_type, - bool only_with_valid_ms_fragmentation_spec) const +bool +ProcessingStep::srcMatches(std::bitset<32> bit_set) const { - std::vector processing_specs; + return (m_xSrcType.bitMatches(bit_set) || m_ySrcType.bitMatches(bit_set)); +} - using Map = std::map; - using Iterator = Map::const_iterator; - for(Iterator iterator = m_processingTypeSpecMultiMap.begin(); - iterator != m_processingTypeSpecMultiMap.end(); - ++iterator) - { - auto &&pair = *iterator; +bool +ProcessingStep::srcMatches(const ProcessingType &processing_type) const +{ + return srcMatches(processing_type.bitSet()); +} - if(ProcessingType::bitMatches(pair.first, processing_type)) - { - if(only_with_valid_ms_fragmentation_spec && - !pair.second->hasValidFragmentationSpec()) - { - continue; - } - else - { - processing_specs.push_back(pair.second); - } - } - } - return processing_specs; +bool +ProcessingStep::srcMatches(const QString &brief_desc) const +{ + return srcMatches(ProcessingType(brief_desc)); } -std::pair -ProcessingStep::innermostRangeProcessingSpecsMatching( - const ProcessingType &processing_type, - bool only_with_valid_ms_fragmentation_spec) const +bool +ProcessingStep::destMatches(std::bitset<32> bit_set) const { - double start = std::numeric_limits::min(); - double end = std::numeric_limits::max(); + return (m_destType.bitMatches(bit_set)); +} - using Map = std::map; - using Iterator = Map::const_iterator; - for(Iterator iterator = m_processingTypeSpecMultiMap.begin(); - iterator != m_processingTypeSpecMultiMap.end(); - ++iterator) - { - auto &&pair = *iterator; +bool +ProcessingStep::destMatches(const ProcessingType &processing_type) const +{ + return destMatches(processing_type.bitSet()); +} - if(ProcessingType::bitMatches(pair.first, processing_type)) - { - if(only_with_valid_ms_fragmentation_spec && - !pair.second->hasValidFragmentationSpec()) - { - continue; - } - else - { - if(pair.second->m_start > start) - start = pair.second->m_start; - - if(pair.second->m_end < end) - end = pair.second->m_end; - } - } - } - return std::pair(start, end); +bool +ProcessingStep::destMatches(const QString &brief_desc) const +{ + return destMatches(ProcessingType(brief_desc)); } @@ -392,6 +427,42 @@ text += m_dateAndTime.toString("yyyyMMdd-HH:mm:ss"); text += "\n"; + text += "X axis Source Processing type: "; + text += m_xSrcType.toBriefDesc(); + text += "\n"; + + text += "Y axis Source Processing type: "; + text += m_ySrcType.toBriefDesc(); + text += "\n"; + + text += "Destination Processing type: "; + text += m_destType.toBriefDesc(); + text += "\n"; + + text += "X axis data kind:"; + text += QString::number(static_cast(m_xAxisDataKind), 10); + text += "\n"; + + text += "Y axis data kind:"; + text += QString::number(static_cast(m_yAxisDataKind), 10); + text += "\n"; + + text += "Selection polygon:"; + text += m_selectionPolygon.toString(); + text += "\n"; + + if(m_selectionPolygon.is1D()) + text += "Polygon is mono-dimensional\n"; + else + { + text += "Polygon is bi-dimensional: "; + + if(m_selectionPolygon.isRectangle()) + text += "rectangle\n"; + else + text += "oblique (skewed)\n"; + } + if(mpa_mzIntegrationParams != nullptr) { // text += lead; @@ -400,16 +471,12 @@ // text += "\n"; } - if(m_processingTypeSpecMultiMap.size()) + if(mpa_msFragmentationSpec != nullptr) { - for(auto &&pair : m_processingTypeSpecMultiMap) - { - // pair.second is the ProcessingSpec and pair.first is the - // ProcessingType. - - text += pair.second->toString(offset + 3, spacer, pair.first); - // text += "\n"; - } + // text += lead; + // text += spacer; + text += mpa_msFragmentationSpec->toString(offset + 2, spacer); + // text += "\n"; } return text; diff -Nru minexpert2-7.4.1/src/nongui/ProcessingStep.hpp minexpert2-8.1.1/src/nongui/ProcessingStep.hpp --- minexpert2-7.4.1/src/nongui/ProcessingStep.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/ProcessingStep.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -45,11 +45,13 @@ /////////////////////// pappsomspp includes #include +#include /////////////////////// Local includes #include "ProcessingType.hpp" -#include "ProcessingSpec.hpp" +#include "ProcessingFlow.hpp" +#include "MsFragmentationSpec.hpp" namespace msxps @@ -66,68 +68,120 @@ } }; -typedef std::pair ProcessingTypeSpecPtrPair; - class ProcessingStep { + friend struct ProcessingStepCompare; + friend class ProcessingFlow; public: ProcessingStep(); - ProcessingStep(const ProcessingStep &other); - - virtual ~ProcessingStep(); - - ProcessingStep &operator=(const ProcessingStep &other); - void setMzIntegrationParams(const pappso::MzIntegrationParams &mz_integration_params); - const pappso::MzIntegrationParams *getMzIntegrationParamsPtr() const; - - void newSpec(ProcessingType processing_type, - ProcessingSpec *processing_spec_p); + ProcessingStep(const pappso::SelectionPolygon &selection_polygon); - ProcessingSpec *newSpec(ProcessingType processing_type, - const ProcessingSpec &processing_spec); + ProcessingStep(const MsFragmentationSpec &ms_fragmentation_spec); - void newSpec(std::bitset<128> bit_set, ProcessingSpec *processing_spec_p); + ProcessingStep(const MsFragmentationSpec &ms_fragmentation_spec, + const pappso::SelectionPolygon selection_polygon); - void newSpec(const QString &brief_desc, ProcessingSpec *processing_spec_p); - - std::vector processingTypes() const; + ProcessingStep(const ProcessingStep &other); - const std::multimap & - getProcessingTypeSpecMap() const; + virtual ~ProcessingStep(); - bool matches(std::bitset<128> bit_set) const; - bool matches(ProcessingType type) const; - bool matches(const QString &brief_desc) const; - bool contains(const QString &brief_desc) const; + ProcessingStep &operator=(const ProcessingStep &other); - std::vector allProcessingSpecsMatching( - const ProcessingType &processing_type, - bool only_with_valid_ms_fragmentation_spec = false) const; + void setProcessingType(const QString &processing_type); + void setProcessingType(const ProcessingType &processing_type); + ProcessingType getProcessingType() const; + + void setSrcProcessingType(pappso::Axis axis, + const ProcessingType &processing_type); + void setSrcProcessingType(pappso::Axis axis, const QString &processing_type); + ProcessingType getSrcProcessingType(pappso::Axis axis) const; + + void setDestProcessingType(const ProcessingType &processing_type); + void setDestProcessingType(const QString &processing_type); + ProcessingType getDestProcessingType() const; + + void setSelectionPolygon(const pappso::SelectionPolygon &selection_polygon); + const pappso::SelectionPolygon &getSelectionPolygon() const; + void resetSelectionPolygon(); + + bool hasValidSelectionPolygon(bool &is_2D) const; + + void setDataKind(pappso::Axis axis, pappso::DataKind data_kind); + pappso::DataKind getDataKind(pappso::Axis axis) const; + + bool getRangeForAxis(pappso::Axis axis, + double &range_start, + double &range_end) const; + bool getRangeForAxisX(double &range_start, double &range_end) const; + bool getRangeForAxisY(double &range_start, double &range_end) const; - std::pair innermostRangeProcessingSpecsMatching( - const ProcessingType &processing_type, - bool only_with_valid_ms_fragmentation_spec = false) const; + void setMzIntegrationParams( + const pappso::MzIntegrationParams &mz_integration_params); + const pappso::MzIntegrationParams *getMzIntegrationParamsPtr() const; - size_t greatestMsLevel() const; + void setMsFragmentationSpec(const MsFragmentationSpec &fragmentation_spec); + MsFragmentationSpec getMsFragmentationSpec() const; + MsFragmentationSpec *getMsFragmentationSpecPtr(); + size_t getMsLevel() const; + + bool hasValidFragmentationSpec() const; + + bool isValid() const; + + bool srcMatches(std::bitset<32> bit_set) const; + bool srcMatches(const ProcessingType &processing_type) const; + bool srcMatches(const QString &brief_desc) const; + + bool destMatches(std::bitset<32> bit_set) const; + bool destMatches(const ProcessingType &processing_type) const; + bool destMatches(const QString &brief_desc) const; QString toString(int offset = 0, const QString &spacer = QString()) const; protected: - std::multimap - m_processingTypeSpecMultiMap; - QDateTime m_dateAndTime; + ProcessingType m_xSrcType = ProcessingType("NOT_SET"); + ProcessingType m_ySrcType = ProcessingType("NOT_SET"); + + ProcessingType m_destType = ProcessingType("NOT_SET"); + + // The QPointF objects in the selection polygon are initialized to + // std::numeric_limits::quiet_NaN() for x and y. + pappso::SelectionPolygon m_selectionPolygon; + + // We need to know which kind of data are along the axes that make the + // selection polygon. + pappso::DataKind m_xAxisDataKind = pappso::DataKind::unset; + pappso::DataKind m_yAxisDataKind = pappso::DataKind::unset; + // When integrating to m/z spectra we need to configure the integration. This // class instance allows to do so. Because not all the specs need such // parameters, we do not make a member variable of that type, but we provide a // means to store a pointer. pappso::MzIntegrationParams *mpa_mzIntegrationParams = nullptr; + + // The ms fragmentation pattern is optional here. If non-nullptr it is + // considered to be enforceable. + MsFragmentationSpec *mpa_msFragmentationSpec = nullptr; +}; + + +struct ProcessingStepCompare +{ + bool + operator()(const ProcessingStep &a, const ProcessingStep &b) const + { + // The data and time has a second granulometry. That should be sufficient + // to ascertain if a and be are identical. + + return a.m_dateAndTime < b.m_dateAndTime; + } }; diff -Nru minexpert2-7.4.1/src/nongui/ProcessingType.cpp minexpert2-8.1.1/src/nongui/ProcessingType.cpp --- minexpert2-7.4.1/src/nongui/ProcessingType.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/ProcessingType.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -57,119 +57,31 @@ { std::pair("NOT_SET", "Not set"), - std::pair("FILE_TO_RT", "File to TIC chrom."), - std::pair("DATA_TO_RT", "Data to XIC chrom."), - std::pair("FILE_TO_MZ", "File to mass spectrum"), - std::pair("FILE_TO_DT", "File to drift spectrum"), - std::pair("FILE_TO_RT_MZ", "File to RT/MZ color map"), - std::pair("FILE_TO_DT_MZ", "File to DT/MZ color map"), - std::pair("FILE_TO_DT_RT", "File to DT/MZ color map"), - - std::pair("DATA_TABLE_VIEW_TO_RT", "Data table view to TIC chrom."), - std::pair("DATA_TABLE_VIEW_TO_MZ", "Data table view to mass spectrum"), - std::pair("DATA_TABLE_VIEW_TO_DT", "Data table view to drift spectrum"), - std::pair("DATA_TABLE_VIEW_TO_INT", "Data table view to TIC intensity"), - std::pair("DATA_TABLE_VIEW_TO_DT_MZ", "Data table view to DT/MZ color map"), - std::pair("DATA_TABLE_VIEW_TO_RT_DT", "Data table view to RT/DT color map"), - std::pair("DATA_TABLE_VIEW_TO_RT_MZ", "Data table view to RT/MZ color map"), - - std::pair("RT_TO_RT", "TIC chrom. to XIC chrom."), - std::pair("RT_TO_MZ", "TIC chrom. to mass spectrum"), - std::pair("RT_TO_DT", "TIC chrom. to drift spectrum"), - std::pair("RT_TO_INT", "TIC chrom. to intensity"), - std::pair("RT_TO_RT_MZ", "TIC chrom. to TIC chrom. / mass spectrum colormap"), - std::pair("RT_TO_DT_MZ", "TIC chrom. to drift spectrum / mass spectrum colormap"), - std::pair("RT_TO_RT_DT", "TIC chrom. to TIC|XIC chrom. / drift spectrum colormap"), - - std::pair("MZ_TO_RT", "Mass spectrum to XIC chrom."), - std::pair("MZ_TO_MZ", "Mass spectrum to mass spectrum"), - std::pair("MZ_TO_DT", "Mass spectrum to drift spectrum"), - std::pair("MZ_TO_INT", "Mass spectrum to intensity"), - std::pair("MZ_TO_RT_MZ", "Mass spectrum to TIC chrom. / mass spectrum colormap"), - std::pair("MZ_TO_DT_MZ", "Mass spectrum to TIC chrom. / drift spectrum colormap"), - std::pair("MZ_TO_RT_DT", "Mass spectrum to TIC|XIC chrom. / drift spectrum colormap"), - - std::pair("DT_TO_RT", "Drift spectrum to XIC chrom."), - std::pair("DT_TO_MZ", "Drift spectrum to mass spectrum"), - std::pair("DT_TO_DT", "Drift spectrum to drift spectrum"), - std::pair("DT_TO_INT", "Drift spectrum to intensity"), - std::pair("DT_TO_RT_MZ", "Drift spectrum to TIC chrom. / mass spectrum colormap"), - std::pair("DT_TO_DT_MZ", "Drift spectrum to drift spectrum / mass spectrum colormap"), - std::pair("DT_TO_RT_DT", "Drift spectrum to TIC|XIC chrom. / drift spectrum colormap"), - - std::pair("RT_MZ_MZ_TO_DT", "TIC|XIC chrom. / mass spectrum to drift spectrum (MZ)"), - std::pair("RT_MZ_RT_TO_DT", "TIC|XIC chrom. / mass spectrum to drift spectrum (RT)"), - - std::pair("RT_MZ_MZ_TO_RT", "TIC|XIC chrom. / mass spectrum to XIC chrom. (MZ)"), - std::pair("RT_MZ_RT_TO_RT", "TIC|XIC chrom. / mass spectrum to XIC chrom. (RT)"), - - std::pair("RT_MZ_MZ_TO_MZ", "TIC|XIC chrom./ mass spectrum to mass spectrum (MZ)"), - std::pair("RT_MZ_RT_TO_MZ", "TIC|XIC chrom./ mass spectrum to mass spectrum (RT)"), - - std::pair("RT_MZ_MZ_TO_RT_MZ", "TIC|XIC chrom. / mass spectrum to XIC chrom. / mass spectrum (MZ)"), - std::pair("RT_MZ_RT_TO_RT_MZ", "TIC|XIC chrom. / mass spectrum to XIC chrom. / mass spectrum (RT)"), - - std::pair("RT_MZ_MZ_TO_DT_MZ", "TIC|XIC chrom. / mass spectrum to drift spectrum / mass spectrum (MZ)"), - std::pair("RT_MZ_RT_TO_DT_MZ", "TIC|XIC chrom. / mass spectrum to drift spectrum / mass spectrum (RT)"), - - std::pair("RT_MZ_MZ_TO_RT_DT", "TIC|XIC chrom. / mass spectrum to TIC|XIC chrom. / drift spectrum (MZ)"), - std::pair("RT_MZ_RT_TO_RT_DT", "TIC|XIC chrom. / mass spectrum to TIC|XIC chrom. / drift spectrum (RT)"), - - std::pair("RT_MZ_RT_TO_INT", "TIC|XIC chrom. / mass spectrum to TIC intensity (RT)"), - std::pair("RT_MZ_MZ_TO_INT", "TIC|XIC chrom. / mass spectrum to TIC intensity (MZ)"), - - std::pair("RT_DT_RT_TO_MZ", "TIC|XIC chrom. / mass spectrum to mass spectrum (RT)"), - std::pair("RT_DT_DT_TO_MZ", "TIC|XIC chrom. / mass spectrum to mass spectrum (DT)"), - - std::pair("RT_DT_RT_TO_DT", "TIC|XIC chrom. / mass spectrum to drift spectrum (RT)"), - std::pair("RT_DT_DT_TO_DT", "TIC|XIC chrom. / mass spectrum to drift spectrum (DT)"), - - std::pair("RT_DT_RT_TO_RT", "TIC|XIC chrom. / mass spectrum to TIC|XIC chrom. (RT)"), - std::pair("RT_DT_DT_TO_RT", "TIC|XIC chrom. / mass spectrum to TIC|XIC chrom. (DT)"), - - std::pair("RT_DT_RT_TO_INT", "TIC|XIC chrom. / mass spectrum to TIC intensity (RT)"), - std::pair("RT_DT_DT_TO_INT", "TIC|XIC chrom. / mass spectrum to TIC intensity (DT)"), - - std::pair("RT_DT_RT_TO_RT_DT", "TIC|XIC chrom. / mass spectrum to TIC|XIC chrom. / drift spectrum (RT)"), - std::pair("RT_DT_DT_TO_RT_DT", "TIC|XIC chrom. / mass spectrum to TIC|XIC chrom. / drift spectrum (DT)"), - - std::pair("RT_DT_RT_TO_RT_MZ", "TIC|XIC chrom. / drift spectrum to TIC|XIC chrom. / mass spectrum (RT)"), - std::pair("RT_DT_DT_TO_RT_MZ", "TIC|XIC chrom. / drift spectrum to TIC|XIC chrom. / mass spectrum (DT)"), - - std::pair("RT_DT_RT_TO_DT_MZ", "TIC|XIC chrom. / drift spectrum to TIC|XIC chrom. / drift spectrum (RT)"), - std::pair("RT_DT_DT_TO_DT_MZ", "TIC|XIC chrom. / drift spectrum to TIC|XIC chrom. / drift spectrum (DT)"), - - std::pair("RT_DT_RT_TO_INT", "TIC|XIC chrom. / drift spectrum to TIC intensity (RT)"), - std::pair("RT_DT_DT_TO_INT", "TIC|XIC chrom. / drift spectrum to TIC intensity (DT)"), - - std::pair("DT_MZ_MZ_TO_DT", "Drift spectrum / mass spectrum to drift spectrum (MZ)"), - std::pair("DT_MZ_DT_TO_DT", "Drift spectrum / mass spectrum to drift spectrum (DT)"), - - std::pair("DT_MZ_MZ_TO_RT", "Drift spectrum / mass spectrum to XIC chrom. (MZ)"), - std::pair("DT_MZ_DT_TO_RT", "Drift spectrum / mass spectrum to XIC chrom. (DT)"), - - std::pair("DT_MZ_MZ_TO_MZ", "Drift spectrum / mass spectrum to mass spectrum (MZ)"), - std::pair("DT_MZ_DT_TO_MZ", "Drift spectrum / mass spectrum to mass spectrum (DT)"), - - std::pair("DT_MZ_MZ_TO_RT_MZ", "Drift spectrum / mass spectrum to XIC chrom. / mass spectrum (MZ)"), - std::pair("DT_MZ_DT_TO_RT_MZ", "Drift spectrum / mass spectrum to XIC chrom. / mass spectrum (DT)"), + // These are the new types conforming to the new idea of a processing step's + // types. + std::pair("FILE_RT", "File, Tic chrom."), - std::pair("DT_MZ_MZ_TO_RT_DT", "Drift spectrum / mass spectrum to XIC chrom. / drift spectrum (MZ)"), - std::pair("DT_MZ_DT_TO_RT_DT", "Drift spectrum / mass spectrum to XIC chrom. / drift spectrum (DT)"), + std::pair("DATA_TABLE_VIEW_DT", "Data table view, drift spectrum"), + std::pair("DATA_TABLE_VIEW_RT", "Data table view, drift spectrum"), - std::pair("DT_MZ_MZ_TO_DT_MZ", "Drift spectrum / mass spectrum to drift spectrum / mass spectrum (MZ)"), - std::pair("DT_MZ_DT_TO_DT_MZ", "Drift spectrum / mass spectrum to drift spectrum / mass spectrum (DT)"), + std::pair("DATA_XIC_MZ", "Data Xic chrom. limited by MZ"), - std::pair("DT_MZ_DT_TO_INT", "Drift spectrum / mass spectrum to TIC intensity (RT)"), - std::pair("DT_MZ_MZ_TO_INT", "Drift spectrum / mass spectrum to TIC intensity (MZ)"), + std::pair("DT", "Drift spectrum"), + std::pair("DT_MZ", "Drift spectrum, Mass spectrum"), + std::pair("DT_RT", "Drift spectrum, Tic|Xic chrom."), - //std::pair("", ""), + std::pair("MZ", "Mass spectrum"), + std::pair("MZ_RT", "Mass spectrum, Tic|Xic chrom."), + + std::pair("RT", "Tic|Xic chrom."), + std::pair("INT", "Tic intensity"), + //std::pair("", ""), }; // clang-format on -std::unordered_map, ProcessingTypeStringPair> +std::unordered_map, ProcessingTypeStringPair> ProcessingType::processingTypeRegistry = {}; @@ -188,14 +100,14 @@ // Instantiate a new bit set of which a single bit will be set to true: // the bit at index iter. - std::bitset<128> bit_set; + std::bitset<32> bit_set; // All bits to false, first. bit_set.reset(); // Now the single bit at position iter to true. bit_set.set(iter, true); ProcessingType::processingTypeRegistry.insert( - std::pair, ProcessingTypeStringPair>( + std::pair, ProcessingTypeStringPair>( bit_set, ProcessingType::processingTypes.at(iter))); // qDebug() << "Inserted new bit_set:" @@ -207,170 +119,67 @@ std::vector brief_desc_list; - /* ANY TO RT */ - brief_desc_list = {"FILE_TO_RT", - "DATA_TO_RT", - "DATA_TABLE_VIEW_TO_RT", - "DATA_TABLE_VIEW_TO_RT_MZ", - "DATA_TABLE_VIEW_TO_RT_DT", - "FILE_TO_RT_MZ", - "MZ_TO_RT", - "RT_TO_RT", - "RT_TO_RT_DT", - "DT_TO_RT", - "RT_TO_RT_MZ", - "MZ_TO_RT_MZ", - "MZ_TO_RT_DT", - "DT_TO_RT_MZ", - "DT_TO_RT_DT", - "DT_MZ_MZ_TO_RT", - "DT_MZ_DT_TO_RT", - "DT_MZ_MZ_TO_RT_MZ", - "DT_MZ_DT_TO_RT_MZ", - "RT_MZ_MZ_TO_RT", - "RT_MZ_RT_TO_RT", - "RT_MZ_MZ_TO_RT_MZ", - "RT_MZ_RT_TO_RT_MZ", - "RT_MZ_MZ_TO_RT_DT", - "RT_MZ_RT_TO_RT_DT", - "DT_MZ_MZ_TO_RT_DT", - "DT_MZ_DT_TO_RT_DT", - "RT_DT_RT_TO_RT", - "RT_DT_DT_TO_RT", - "RT_DT_RT_TO_RT_DT", - "RT_DT_DT_TO_RT_DT", - "RT_DT_RT_TO_RT_MZ", - "RT_DT_DT_TO_RT_MZ"}; - registerProcessingCompositeTypes( - brief_desc_list, - std::pair("ANY_TO_RT", "Any to TIC chrom.")); - /* ANY TO MZ */ - brief_desc_list = {"FILE_TO_MZ", - "DATA_TABLE_VIEW_TO_MZ", - "DATA_TABLE_VIEW_TO_RT_MZ", - "DATA_TABLE_VIEW_TO_DT_MZ", - "MZ_TO_MZ", - "RT_TO_MZ", - "DT_TO_MZ", - "RT_TO_DT_MZ", - "RT_TO_RT_MZ", - "MZ_TO_RT_MZ", - "MZ_TO_DT_MZ", - "DT_TO_DT_MZ", - "DT_TO_RT_MZ", - "DT_MZ_MZ_TO_MZ", - "DT_MZ_DT_TO_MZ", - "RT_MZ_MZ_TO_MZ", - "RT_MZ_RT_TO_MZ", - "RT_MZ_MZ_TO_RT_MZ", - "RT_MZ_RT_TO_RT_MZ", - "DT_MZ_MZ_TO_RT_MZ", - "DT_MZ_DT_TO_RT_MZ", - "DT_MZ_MZ_TO_DT_MZ", - "DT_MZ_DT_TO_DT_MZ", - "RT_DT_RT_TO_RT_MZ", - "RT_DT_DT_TO_RT_MZ", - "RT_DT_RT_TO_DT_MZ", - "RT_DT_DT_TO_DT_MZ", - "RT_DT_RT_TO_MZ", - "RT_DT_DT_TO_MZ"}; + /* ANY_DT */ + // clang-format off + brief_desc_list = { + "DATA_TABLE_VIEW_DT", + "DT", + "DT_MZ", + "DT_RT", + }; + // clang-format on registerProcessingCompositeTypes( brief_desc_list, - std::pair("ANY_TO_MZ", "Any to mass spectrum")); + std::pair("ANY_DT", "Whatever drift spectrum")); - /* ANY TO DT */ - brief_desc_list = {"FILE_TO_DT", - "DATA_TABLE_VIEW_TO_DT", - "DATA_TABLE_VIEW_TO_DT_MZ", - "DATA_TABLE_VIEW_TO_RT_DT", - "RT_TO_DT", - "DT_TO_DT", - "MZ_TO_DT", - "RT_TO_DT_MZ", - "RT_TO_RT_DT", - "MZ_TO_DT_MZ", - "MZ_TO_RT_DT", - "DT_TO_DT_MZ", - "DT_TO_RT_DT", - "DT_MZ_MZ_TO_DT_MZ", - "DT_MZ_DT_TO_DT_MZ", - "DT_MZ_MZ_TO_DT", - "DT_MZ_DT_TO_DT", - "RT_MZ_MZ_TO_DT", - "RT_MZ_RT_TO_DT", - "RT_MZ_MZ_TO_DT_MZ", - "RT_MZ_RT_TO_DT_MZ", - "RT_MZ_MZ_TO_RT_DT", - "RT_MZ_RT_TO_RT_DT", - "DT_MZ_MZ_TO_RT_DT", - "DT_MZ_DT_TO_RT_DT", - "RT_DT_RT_TO_RT_DT", - "RT_DT_DT_TO_RT_DT", - "RT_DT_RT_TO_DT_MZ", - "RT_DT_DT_TO_DT_MZ", - "RT_DT_RT_TO_DT", - "RT_DT_DT_TO_DT"}; - registerProcessingCompositeTypes( - brief_desc_list, - std::pair("ANY_TO_DT", "Any to drift spectrum")); - /* ANY TO INT */ + /* ANY_MZ */ + // clang-format off brief_desc_list = { - "RT_TO_INT", - "DT_TO_INT", - "MZ_TO_INT", - "DATA_TABLE_VIEW_TO_INT", - "RT_MZ_RT_TO_INT", - "RT_MZ_MZ_TO_INT", - "DT_MZ_DT_TO_INT", - "DT_MZ_MZ_TO_INT", - "RT_DT_RT_TO_INT", - "RT_DT_DT_TO_INT", - }; + "MZ", + "DATA_XIC_MZ", + "DT_MZ", + "MZ_RT", + }; + // clang-format on registerProcessingCompositeTypes( brief_desc_list, - std::pair("ANY_TO_INT", "Any to TIC intensity")); + std::pair("ANY_MZ", "Whatever mass spectrum")); - /* RT TO ANY */ - brief_desc_list = { - "RT_TO_RT", "RT_TO_MZ", "RT_TO_DT", - "RT_TO_INT", "RT_TO_RT_MZ", "RT_TO_DT_MZ", - "RT_TO_RT_DT", "RT_TO_INT", "RT_MZ_RT_TO_RT", - "RT_MZ_RT_TO_DT", "RT_MZ_RT_TO_MZ", "RT_MZ_RT_TO_RT_MZ", - "RT_MZ_RT_TO_DT_MZ", "RT_MZ_RT_TO_RT_DT", "RT_DT_RT_TO_RT_DT", - "RT_MZ_RT_TO_INT", "RT_DT_RT_TO_RT_MZ", "RT_DT_RT_TO_RT", - "RT_DT_RT_TO_DT", "RT_DT_RT_TO_INT", "RT_DT_RT_TO_MZ", - "RT_DT_RT_TO_DT_MZ"}; - registerProcessingCompositeTypes( - brief_desc_list, - std::pair("RT_TO_ANY", "TIC chrom. to any")); - /* MZ TO ANY */ + /* ANY_RT */ + // clang-format off brief_desc_list = { - "MZ_TO_RT", "MZ_TO_MZ", "MZ_TO_DT", - "MZ_TO_INT", "MZ_TO_RT_MZ", "MZ_TO_DT_MZ", - "MZ_TO_RT_DT", "DT_MZ_MZ_TO_DT", "DT_MZ_MZ_TO_RT", - "DT_MZ_MZ_TO_MZ", "DT_MZ_MZ_TO_RT_MZ", "DT_MZ_MZ_TO_DT_MZ", - "RT_MZ_MZ_TO_DT", "RT_MZ_MZ_TO_RT", "RT_MZ_MZ_TO_MZ", - "RT_MZ_MZ_TO_RT_MZ", "RT_MZ_MZ_TO_DT_MZ", "RT_MZ_MZ_TO_RT_DT", - "RT_MZ_MZ_TO_INT", "DT_MZ_MZ_TO_INT", "DT_MZ_MZ_TO_RT_DT"}; + "FILE_RT", + "DATA_TABLE_VIEW_RT", + "DT_RT", + "MZ_RT", + "RT", + }; + // clang-format on registerProcessingCompositeTypes( brief_desc_list, - std::pair("MZ_TO_ANY", "Mass spectrum to any")); + std::pair("ANY_RT", "Whatever Tic|Xic chrom.")); + + +#if 0 + // This cannot work, because the map is not multimap and we cannot insert keys + // that have the same value. Since we imagines ANY_INT as a synonym of INT, + // the key would be the same. + + // We we decided to have only a INT processing type. - /* DT TO ANY */ + /* ANY_INT */ + // clang-format off brief_desc_list = { - "DT_TO_RT", "DT_TO_MZ", "DT_TO_DT", - "DT_TO_INT", "DT_TO_RT_MZ", "DT_TO_DT_MZ", - "DT_TO_RT_DT", "DT_MZ_DT_TO_DT", "DT_MZ_DT_TO_RT", - "DT_MZ_DT_TO_MZ", "DT_MZ_DT_TO_RT_MZ", "DT_MZ_DT_TO_DT_MZ", - "DT_MZ_DT_TO_RT_DT", "RT_DT_DT_TO_RT_DT", "DT_MZ_DT_TO_INT", - "RT_DT_DT_TO_RT_MZ", "RT_DT_DT_TO_RT", "RT_DT_DT_TO_DT", - "RT_DT_DT_TO_MZ", "RT_DT_DT_TO_INT", "RT_DT_DT_TO_DT_MZ"}; + "INT", + }; + // clang-format on registerProcessingCompositeTypes( brief_desc_list, - std::pair("DT_TO_ANY", "Drift spectrum to any")); + std::pair("ANY_INT", "Whatever Tic intensity")); +#endif // brief_desc_list = {"", "", ""}; // registerProcessingCompositeTypes( @@ -385,11 +194,12 @@ ProcessingType::registerProcessingCompositeTypes( std::vector brief_desc_list, ProcessingTypeStringPair dest_desc_pair) { - std::bitset<128> final_bit_set; + std::bitset<32> final_bit_set; final_bit_set.reset(); // qDebug() << "The list of brief descriptions has size:" - //<< brief_desc_list.size(); + //<< brief_desc_list.size() << "and is titled:" << dest_desc_pair.first + //<< "-" << dest_desc_pair.second; for(auto &&brief_desc : brief_desc_list) { @@ -397,13 +207,13 @@ if(brief_desc.isEmpty()) { - // qDebug() << "brief_desc is empty, continuing."; + //qDebug() << "brief_desc is empty, continuing."; continue; } - using Pair = std::pair, ProcessingTypeStringPair>; + using Pair = std::pair, ProcessingTypeStringPair>; using Map = - std::unordered_map, ProcessingTypeStringPair>; + std::unordered_map, ProcessingTypeStringPair>; using Iterator = Map::const_iterator; Iterator found_iterator = @@ -416,7 +226,7 @@ if(found_iterator == ProcessingType::processingTypeRegistry.end()) qFatal("Programming error."); - std::bitset<128> iter_bit_set = found_iterator->first; + std::bitset<32> iter_bit_set = found_iterator->first; // qDebug() << "The iterated bit set:" //<< QString::fromStdString(iter_bit_set.to_string()); @@ -430,17 +240,17 @@ // At this point we can effectively insert the new ProcessType ProcessingType::processingTypeRegistry.insert( - std::pair, ProcessingTypeStringPair>(final_bit_set, + std::pair, ProcessingTypeStringPair>(final_bit_set, dest_desc_pair)); - // qDebug() << "Inserted new bit_set:" << dest_desc_pair << "with value:" - //<< QString::fromStdString(final_bit_set.to_string()); + //qDebug() << "Inserted new bit_set:" << dest_desc_pair << "with value:" + //<< QString::fromStdString(final_bit_set.to_string()); } // static bool -ProcessingType::isRegistered(std::bitset<128> bit_set) +ProcessingType::isRegistered(std::bitset<32> bit_set) { if(ProcessingType::processingTypeRegistry.find(bit_set) == ProcessingType::processingTypeRegistry.end()) @@ -454,8 +264,8 @@ bool ProcessingType::isRegistered(QString brief_desc) { - using Pair = std::pair, ProcessingTypeStringPair>; - using Map = std::unordered_map, ProcessingTypeStringPair>; + using Pair = std::pair, ProcessingTypeStringPair>; + using Map = std::unordered_map, ProcessingTypeStringPair>; using Iterator = Map::const_iterator; Iterator found_iterator = std::find_if( @@ -471,7 +281,7 @@ // constructor -ProcessingType::ProcessingType(std::bitset<128> bit_set) +ProcessingType::ProcessingType(std::bitset<32> bit_set) { registerProcessingTypes(); @@ -521,7 +331,16 @@ // instance. But check anyway for the moment. if(!ProcessingType::isRegistered(other.m_briefDesc)) - qFatal("Programming error."); + { + + qDebug() << "brief_desc:" << other.m_briefDesc + << "Processing types vector size:" + << ProcessingType::processingTypes.size() + << "Processing types map size:" + << ProcessingType::processingTypeRegistry.size(); + + qFatal("Programming error."); + } m_briefDesc = other.m_briefDesc; } @@ -562,7 +381,8 @@ } -std::bitset<128> ProcessingType::operator&(const ProcessingType &mask) +std::bitset<32> +ProcessingType::operator&(const ProcessingType &mask) { return (bitSet() & mask.bitSet()); } @@ -570,7 +390,7 @@ // Return the bit set on the basis of m_briefDesc. -std::bitset<128> +std::bitset<32> ProcessingType::bitSet() const { // Return the bit set representation of *this processing type. @@ -587,27 +407,35 @@ QString -ProcessingType::toString() const +ProcessingType::toBriefDesc() const { return getBriefDesc(); } +QString +ProcessingType::toBitString() const +{ + return QString::fromStdString(bitSet().to_string()); +} + + /*/// static bit set -- brief/detailed desc relating functions */ /*/// static bit set -- brief/detailed desc relating functions */ // static // Return the bit set on the basis of brief_desc. -std::bitset<128> +std::bitset<32> ProcessingType::bitSet(QString brief_desc) { if(!isRegistered(brief_desc)) { + qDebug() << brief_desc << "is not registered."; qFatal("Programming error."); } - using Pair = std::pair, ProcessingTypeStringPair>; - using Map = std::unordered_map, ProcessingTypeStringPair>; + using Pair = std::pair, ProcessingTypeStringPair>; + using Map = std::unordered_map, ProcessingTypeStringPair>; using Iterator = Map::const_iterator; // Search in the static map member the Pair that has its second element @@ -620,7 +448,7 @@ if(found_iterator == ProcessingType::processingTypeRegistry.end()) { - std::bitset<128> bit_set; + std::bitset<32> bit_set; bit_set.reset(); return bit_set; } @@ -630,11 +458,11 @@ // static -std::bitset<128> +std::bitset<32> ProcessingType::bitSet(const ProcessingType &processing_type) { - // Get the brief description member out of processing_type, which we'll use to - // find the bit set. + // Get the brief description member out of processing_type, which we'll use + // to find the bit set. return bitSet(processing_type.m_briefDesc); } @@ -642,9 +470,9 @@ // static QString -ProcessingType::briefDesc(std::bitset<128> bit_set) +ProcessingType::briefDesc(std::bitset<32> bit_set) { - using Map = std::unordered_map, ProcessingTypeStringPair>; + using Map = std::unordered_map, ProcessingTypeStringPair>; using Iterator = Map::const_iterator; Iterator found_iterator = @@ -661,9 +489,9 @@ // static QString -ProcessingType::detailedDesc(std::bitset<128> bit_set) +ProcessingType::detailedDesc(std::bitset<32> bit_set) { - using Map = std::unordered_map, ProcessingTypeStringPair>; + using Map = std::unordered_map, ProcessingTypeStringPair>; using Iterator = Map::const_iterator; Iterator found_iterator = @@ -694,15 +522,15 @@ // static bool ProcessingType::bitMatches(const ProcessingType &processing_type, - std::bitset<128> mask) + std::bitset<32> mask) { // qDebug() << "processing_type bit set representation:" //<< QString::fromStdString(processing_type.bitSet().to_string()) //<< "while the mask is:" << QString::fromStdString(mask.to_string()); - std::bitset<128> test_bit_set = processing_type.bitSet(); + std::bitset<32> test_bit_set = processing_type.bitSet(); - std::bitset<128> res_bit_set = test_bit_set & mask; + std::bitset<32> res_bit_set = test_bit_set & mask; bool res = res_bit_set == test_bit_set; // qDebug() << "res_bit_set:" << @@ -743,7 +571,7 @@ bool -ProcessingType::bitMatches(std::bitset<128> mask) const +ProcessingType::bitMatches(std::bitset<32> mask) const { return ProcessingType::bitMatches(*this, mask); } diff -Nru minexpert2-7.4.1/src/nongui/ProcessingType.hpp minexpert2-8.1.1/src/nongui/ProcessingType.hpp --- minexpert2-7.4.1/src/nongui/ProcessingType.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/ProcessingType.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -63,7 +63,7 @@ class ProcessingType { public: - ProcessingType(std::bitset<128> bit_set); + ProcessingType(std::bitset<32> bit_set); ProcessingType(const QString &brief_desc); ProcessingType(const ProcessingType &other); @@ -74,23 +74,23 @@ /*/// & = == operators */ ProcessingType &operator=(const ProcessingType &other); bool operator==(const ProcessingType &other); - std::bitset<128> operator&(const ProcessingType &mask); + std::bitset<32> operator&(const ProcessingType &mask); /* & = == operators */ /// - std::bitset<128> bitSet() const; + std::bitset<32> bitSet() const; /*/// static bit set -- brief/detailed desc relating functions */ - static std::bitset<128> bitSet(QString brief_desc); - static std::bitset<128> bitSet(const ProcessingType &processing_type); - static QString briefDesc(std::bitset<128> bit_set); - static QString detailedDesc(std::bitset<128> bit_set); + static std::bitset<32> bitSet(QString brief_desc); + static std::bitset<32> bitSet(const ProcessingType &processing_type); + static QString briefDesc(std::bitset<32> bit_set); + static QString detailedDesc(std::bitset<32> bit_set); /* static bit set -- brief/detailed desc relating functions */ /// /*/// static comparison and bit matching functions */ static bool compare(const ProcessingType &a, const ProcessingType &b); static bool bitMatches(const ProcessingType &processing_type, - std::bitset<128> mask); + std::bitset<32> mask); static bool bitMatches(const ProcessingType &processing_type, const QString &mask); static bool bitMatches(const ProcessingType &processing_type, @@ -100,12 +100,13 @@ /*/// Begin non static comparison and bit matching */ bool compare(const ProcessingType &other); - bool bitMatches(std::bitset<128> mask) const; + bool bitMatches(std::bitset<32> mask) const; bool bitMatches(const ProcessingType &mask) const; bool bitMatches(const QString &mask) const; /* non static comparison and bit matching */ /// - QString toString() const; + QString toBriefDesc() const; + QString toBitString() const; private: static bool mapFilled; @@ -114,144 +115,21 @@ // This is a vector of ProcessingTypeDescription items that describe all the // processing types available in the program. - void registerProcessingTypes(); - void - registerProcessingCompositeTypes(std::vector brief_desc_list, - ProcessingTypeStringPair dest_desc_pair); - /// Begin static private data and functions static std::vector processingTypes; - static std::unordered_map, ProcessingTypeStringPair> + static std::unordered_map, ProcessingTypeStringPair> processingTypeRegistry; static bool isRegistered(QString brief_desc); - static bool isRegistered(std::bitset<128> bit_set); + static bool isRegistered(std::bitset<32> bit_set); /// End static private data and functions -}; - - -#if 0 -enum class ProcessingType : int128_t -{ - NOT_SET = 0x0000, - - FILE_TO_RT = 1LLU << 0, - /*!< Integrate from mass data file to retention time (TIC chromatogram) */ - - FILE_TO_RT_MZ = 1LLU << 1, - /*!< Integrate from mass data file to retention time (TIC chromatogram) */ - - FILE_TO_MZ = 1LLU << 2, - /*!< Integrate from mass data file to retention time (TIC chromatogram) */ - - FILE_TO_DT = 1LLU << 3, - /*!< Integrate from mass data file to retention time (TIC chromatogram) */ - - FILE_TO_DT_MZ_COLORMAP = 1LLU << 4, - /*!< Integrate from mass data file to retention time (TIC chromatogram) */ - - FILE_TO_TIC_INT = 1LLU << 5, - /*!< Integrate from mass data file to retention time (XIC chromatogram) */ - - FILE_TO_XIC = 1LLU << 6, - /*!< Integrate from mass data file to retention time (XIC chromatogram) */ - - RT_TO_MZ = 1LLU << 7, - /*!< Integrate from TIC or XIC chromatogram to mass spectrum */ - - RT_TO_DT = 1LLU << 8, - /*!< Integrate from TIC or XIC chromatogram to drift spectrum */ - - RT_TO_TIC_INT = 1LLU << 9, - /*!< Integrate from TIC chrom range to TIC intensity single value */ - - MZ_TO_RT = 1LLU << 10, - /*!< Integrate from mass spectrum to XIC chromatogram (retention time) */ - - MZ_TO_MZ = 1LLU << 11, - /*!< Integrate from mass spectrum to mass spectrum (from color map)*/ - - MZ_TO_DT = 1LLU << 12, - /*!< Integrate from mass spectrum to drift spectrum*/ - - MZ_TO_TIC_INT = 1LLU << 13, - /*!< Integrate from mass spectrum range to TIC intensity single value */ - - DT_TO_RT = 1LLU << 14, - /*!< Integrate from drift spectrum to XIC (retention time) */ - DT_TO_MZ = 1LLU << 15, - /*!< Integrate from drift spectrum to mass spectrum */ - - DT_TO_DT = 1LLU << 16, - /*!< Integrate from drift spectrum to drift spectrum (from color map)*/ - - DT_TO_TIC_INT = 1LLU << 17, - /*!< Integrate from drift spectrum range to TIC intensity single value */ - - // Now the specific color map integration types: - DTMZ_DT_TO_RT = 1LLU << 18, - /*!< Integrate from mz/dt color map, dt range, to retention time (XIC - chromatogram) */ - - DTMZ_MZ_TO_RT = 1LLU << 19, - /*!< Integrate from mz/dt color map, mz range, to retention time (XIC - chromatogram) */ - - // Now the specific color map integration types: - DTMZ_DT_TO_MZ = 1LLU << 20, - /*!< Integrate from mz/dt color map, dt range, to mass spectrum */ - - DTMZ_MZ_TO_MZ = 1LLU << 21, - /*!< Integrate from mz/dt color map, mz range, to mass spectrum */ - - // Now the specific color map integration types: - DTMZ_DT_TO_DT = 1LLU << 22, - /*!< Integrate from mz/dt color map, dt range, to drift spectrum */ - - DTMZ_MZ_TO_DT = 1LLU << 23, - /*!< Integrate from mz/dt color map, mz range, to drift spectrum */ - - // Now the specific color map integration types: - DTMZ_DT_TO_TIC_INT = 1LLU << 24, - /*!< Integrate from mz/dt color map, dt range, to TIC intensity value */ - - DTMZ_MZ_TO_TIC_INT = 1LLU << 25, - /*!< Integrate from mz/dt color map, mz range, to TIC intensity value */ - - // Now the generic XXX_TO_YY - XXX_TO_RT = 1LLU << 26, - XXX_TO_MZ = 1LLU << 27, - XXX_TO_DT = 1LLU << 28, - XXX_TO_TIC_INT = 1LLU << 29, - - // And the generic YY_TO_XXX - RT_TO_XXX = 1LLU << 30, - MZ_TO_XXX = 1LLU << 31, - DT_TO_XXX = 1LLU << 32, - - RT_TO_ANY = (RT_TO_XXX | RT_TO_MZ | RT_TO_DT | RT_TO_TIC_INT), - - MZ_TO_ANY = - (MZ_TO_XXX | MZ_TO_RT | DTMZ_MZ_TO_RT | DTMZ_MZ_TO_MZ | DTMZ_MZ_TO_DT | - FILE_TO_XIC | MZ_TO_MZ | MZ_TO_DT | MZ_TO_TIC_INT), - - DT_TO_ANY = (DT_TO_XXX | DT_TO_RT | DTMZ_DT_TO_RT | DTMZ_DT_TO_MZ | - DTMZ_DT_TO_DT | DT_TO_MZ | DT_TO_DT | DT_TO_TIC_INT), - - ANY_TO_RT = (XXX_TO_RT | FILE_TO_RT | FILE_TO_RT_MZ), - - ANY_TO_MZ = (XXX_TO_MZ | FILE_TO_MZ | RT_TO_MZ | MZ_TO_MZ | DT_TO_MZ | - DTMZ_DT_TO_MZ | DTMZ_MZ_TO_MZ), - - ANY_TO_DT = (XXX_TO_DT | FILE_TO_DT | RT_TO_DT | MZ_TO_DT | DT_TO_DT | - DTMZ_DT_TO_DT | DTMZ_MZ_TO_DT), - - ANY_TO_TIC_INT = (XXX_TO_TIC_INT | RT_TO_TIC_INT | MZ_TO_TIC_INT | - DT_TO_TIC_INT | DTMZ_DT_TO_TIC_INT | DTMZ_MZ_TO_TIC_INT), + void registerProcessingTypes(); + void + registerProcessingCompositeTypes(std::vector brief_desc_list, + ProcessingTypeStringPair dest_desc_pair); }; -#endif } // namespace minexpert diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegrator.cpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegrator.cpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegrator.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegrator.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -5,11 +5,9 @@ * Copyright (C) 2009--2020 Filippo Rusconi * * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: + * * This file is part of the msXpertSuite project. * * The msXpertSuite + * project is the successor of the massXpert project. This project now includes + * various independent modules: * * - massXpert, model polymer chemistries and simulate mass spectrometric data; * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; @@ -33,6 +31,7 @@ /////////////////////// StdLib includes #include +#include /////////////////////// Qt includes @@ -45,6 +44,7 @@ /////////////////////// Local includes #include "QualifiedMassSpectrumVectorMassDataIntegrator.hpp" +#include "ProcessingStep.hpp" int qualifiedMassSpectrumVectorMassDataIntegratorMetaTypeId = qRegisterMetaType< @@ -79,6 +79,8 @@ qualified_mass_spectra_to_integrate_sp) { m_processingFlow.setMsRunDataSetCstSPtr(mcsp_msRunDataSet); + + // qDebug() << "Going to call setInnermostRanges()."; setInnermostRanges(); } @@ -93,6 +95,7 @@ mcsp_qualifiedMassSpectraToIntegrateVector( other.mcsp_qualifiedMassSpectraToIntegrateVector) { + //qDebug(); m_processingFlow.setMsRunDataSetCstSPtr(mcsp_msRunDataSet); setInnermostRanges(); } @@ -116,6 +119,8 @@ const ProcessingFlow &processing_flow) { m_processingFlow = processing_flow; + + // qDebug() << "Going to call setInnermostRanges()."; setInnermostRanges(); } @@ -161,15 +166,16 @@ } if(qualified_mass_spectrum_csp == nullptr) - qFatal("QualifiedMassSpectrum cannot be nullptr."); - - //qDebug() << "Retention time is:" << qualified_mass_spectrum_csp->getRtInMinutes(); - - // In some cases this might happen, for example with the Leptocheline_MS3_DDA_IT_1.mzml - // test file. - - //if(!qualified_mass_spectrum_csp->size()) - //qFatal("The qualified mass spectrum is empty (size is 0)."); + qFatal("QualifiedMassSpectrum cannot be nullptr."); + + // qDebug() << "Retention time is:" << + // qualified_mass_spectrum_csp->getRtInMinutes(); + + // In some cases this might happen, for example with the + // Leptocheline_MS3_DDA_IT_1.mzml test file. + + // if(!qualified_mass_spectrum_csp->size()) + // qFatal("The qualified mass spectrum is empty (size is 0)."); // If the parameter had effectively the binary data in it, then we return it // as it was. Otherwise we have created one new. @@ -185,8 +191,9 @@ } -void -QualifiedMassSpectrumVectorMassDataIntegrator::setMaxThreadUseCount(std::size_t number) +void +QualifiedMassSpectrumVectorMassDataIntegrator::setMaxThreadUseCount( + std::size_t number) { m_maxThreadUseCount = number; } @@ -204,8 +211,8 @@ { m_isOperationCancelled = true; - //qDebug() << "cancellation asked, setting m_isOperationCancelled to true and " - //"emitting cancelOperationSignal"; + // qDebug() << "cancellation asked, setting m_isOperationCancelled to true and + // " "emitting cancelOperationSignal"; emit cancelOperationSignal(); } @@ -242,8 +249,8 @@ std::pair -QualifiedMassSpectrumVectorMassDataIntegrator::bestParallelIntegrationParams([ - [maybe_unused]] std::size_t node_count) +QualifiedMassSpectrumVectorMassDataIntegrator::bestParallelIntegrationParams( + [[maybe_unused]] std::size_t node_count) { std::size_t ideal_thread_count = bestThreadCount(); @@ -273,20 +280,20 @@ #if 0 - // Quality check, go through all the qual mass specs and check that they are - // fine. + // Quality check, go through all the qual mass specs and check that they are + // fine. - qDebug() << "Quality check: verifying that all the mass spectra in the " - "vector are correct"; + qDebug() << "Quality check: verifying that all the mass spectra in the " + "vector are correct"; - for(auto &mass_spectrum_csp : *mcsp_qualifiedMassSpectraToIntegrateVector) - { - if(nullptr == mass_spectrum_csp || nullptr == mass_spectrum_csp.get()) - qFatal("Cannot be nullptr."); + for(auto &mass_spectrum_csp : *mcsp_qualifiedMassSpectraToIntegrateVector) + { + if(nullptr == mass_spectrum_csp || nullptr == mass_spectrum_csp.get()) + qFatal("Cannot be nullptr."); - qDebug() << "Iterated mass spectrum at rt:" - << mass_spectrum_csp.get()->getRtInMinutes(); - } + qDebug() << "Iterated mass spectrum at rt:" + << mass_spectrum_csp.get()->getRtInMinutes(); + } #endif @@ -355,27 +362,27 @@ #if 0 - qDebug() << "Textual output of all the iterators:"; + qDebug() << "Textual output of all the iterators:"; - // Provide a textual output of all the pointers to the various mass spectra + // Provide a textual output of all the pointers to the various mass spectra - // The iterators are defined like this: - // std::vector::const_iterator; + // The iterators are defined like this: + // std::vector::const_iterator; - std::size_t thread_index = 0; - for(auto &iterator_pair : iterators) - { - qDebug() << "For thread index " << thread_index << "iterators:"; + std::size_t thread_index = 0; + for(auto &iterator_pair : iterators) + { + qDebug() << "For thread index " << thread_index << "iterators:"; - qDebug() << "first mass spectrum:" << iterator_pair.first->get() - << "at rt:" << iterator_pair.first->get()->getRtInMinutes(); + qDebug() << "first mass spectrum:" << iterator_pair.first->get() + << "at rt:" << iterator_pair.first->get()->getRtInMinutes(); - qDebug() << "last mass spectrum : " - << std::prev(iterator_pair.second)->get() - << "at rt:" << std::prev(iterator_pair.second)->get()->getRtInMinutes(); + qDebug() << "last mass spectrum : " + << std::prev(iterator_pair.second)->get() + << "at rt:" << std::prev(iterator_pair.second)->get()->getRtInMinutes(); - ++thread_index; - } + ++thread_index; + } #endif @@ -477,9 +484,14 @@ // Get the greatest MS level that is requested amongst all the steps/specs in // the processing flow. We are not going going to accept a mass spectrum with - // a differing MS level. + // a differing MS level. Indeed, in a mass spectral data exploration, one + // typically starts by looking at mass data of MS level 0 (all the levels), or + // 1 (typically the TIC chrom). Then, one start delving into the depth of the + // mass data, with higher MS levels. It is thus logical that we only accept + // mass spectra that have as MS level matching that greatest MS level as + // recorded in the steps of the processing flow. - size_t greatest_ms_level = m_processingFlow.greatestMsLevel(); + std::size_t greatest_ms_level = m_processingFlow.greatestMsLevel(); // qDebug().noquote() << "Greatest ms level in the processing flow:" //<< greatest_ms_level @@ -494,27 +506,27 @@ { if(spectrum_ms_level != greatest_ms_level) { - // qDebug().noquote() - //<< "Spectrum ms level:" << spectrum_ms_level - //<< "does *not* match greatestest ms level:" << greatest_ms_level; + //qDebug().noquote() + //<< "Spectrum ms level:" << spectrum_ms_level + //<< "does *not* match greatest ms level:" << greatest_ms_level; return false; } - else - { - // qDebug().noquote() - //<< "Spectrum ms level:" << spectrum_ms_level - //<< "*does* match greatestest ms level:" << greatest_ms_level; - } + //else + //{ + //qDebug().noquote() + //<< "Spectrum ms level:" << spectrum_ms_level + //<< "*does* match greatest ms level:" << greatest_ms_level; + //} } - else - { - // qDebug() << "The greatest ms level is 0, accounting all the spectra."; + // else + //{ + // qDebug() << "The greatest ms level is 0, accounting all the spectra."; - // Just go on, we do take into consideration any MS level. - } + // Just go on, we do take into consideration any MS level. + //} - // qDebug() << "Returning true."; + //qDebug() << "Returning true."; return true; } @@ -522,704 +534,450 @@ bool QualifiedMassSpectrumVectorMassDataIntegrator::checkMsFragmentation( + const ProcessingStep &processing_step, pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) { // qDebug(); - if(qualified_mass_spectrum_csp == nullptr) qFatal("Cannot be nullptr"); if(qualified_mass_spectrum_csp.get() == nullptr) qFatal("Cannot be nullptr"); - // We want to go through all the ProcessingStep_s in the Flow and for each - // Step check each Spec's MsFragmentationSpec, if any. - - // As soon as there is a single fragmentation spec that does not match the - // requirement, we set this variable to false. - bool should_account_mass_spectrum = true; + const MsFragmentationSpec fragmentation_spec = + processing_step.getMsFragmentationSpec(); - // A processing flow contains a number of processing steps. - for(auto &&step : m_processingFlow) + if(fragmentation_spec.isValid()) { + //qDebug().noquote() << "ProcessingSpec's MsFragmentationSpec *is* valid:" + //<< fragmentation_spec.toString(); + + // Check if the fragmentation spec contains at least one + // precursor. There are not necessarily because the fragmentation + // spec may simply stipulate a ms level or define one or more + // precursor spectrum indices. - // Each processing step contains a map relating processing types with - // processing specs. - for(auto &&type_spec_pair : step->getProcessingTypeSpecMap()) + if(fragmentation_spec.precursorMzValuesCount()) { + // Get the list of precursor ion data that were recorded while + // acquiring the mass data. - const ProcessingSpec *spec_p = type_spec_pair.second; + const std::vector + &precursor_ion_data_vector = + qualified_mass_spectrum_csp->getPrecursorIonData(); - // Each processing spec might contain a ms fragmentation spec in the - // form of a pointer to such an instance. If no such fragspec is - // available (the pointer is nullptr), then an invalid - // MsFragmentationSpec is returned, which is why we test it here. - const MsFragmentationSpec fragmentation_spec = - spec_p->getMsFragmentationSpec(); + std::size_t precursor_ion_data_vector_size = + precursor_ion_data_vector.size(); - if(fragmentation_spec.isValid()) - { - // qDebug().noquote() - //<< "ProcessingSpec's MsFragmentationSpec *is* valid:" - //<< fragmentation_spec.toString(); - - // Check if the fragmentation spec contains at least one - // precursor. There are not necessarily because the fragmentation - // spec may simply stipulate a ms level or define one or more - // precursor spectrum indices. - - if(fragmentation_spec.precursorMzValuesCount()) - { - // Get the list of precursor ion data that were recorded while - // acquiring the mass data. - - const std::vector - &precursor_ion_data_vector = - qualified_mass_spectrum_csp->getPrecursorIonData(); - - std::size_t precursor_ion_data_vector_size = - precursor_ion_data_vector.size(); - - // There are two situations: - // - // 1. Evidently, since the fragmentation spec contains actual - // precursor mz values, if the mass spectrum contains no - // precursor ion data, then it should be dismissed - // immediately, without even calling the - // fragmentation_spec.containsMzPrecursors() function. - - // 2. We need to actually check if the fragmentation spec also - // lists precursor mz values. The function below checks if - // there are matches between the precursor mz values from the - // mass spectrum acquisition and the precursor mz values - // listed in the MsFragmentationSpec. The function returns - // true if at least one match could be performed. - - if(!precursor_ion_data_vector_size || - !fragmentation_spec.containsMzPrecursors( - precursor_ion_data_vector)) - { - should_account_mass_spectrum = false; - } - // else - // qDebug().noquote() - //<< "Mass spectrum:" << qualified_mass_spectrum_csp.get() - //<< "matched the MsFragmentationSpec's mz precursor " - //"values. " - //<< "Mass spectrum prec mz values: " - //<< qualified_mass_spectrum_csp - //->getPrecursorDataMzValuesAsString() - //<< "and MsFragmentationSpec prec mz values: " - //<< fragmentation_spec.mzPrecursorsToString(); - } - - if(fragmentation_spec.precursorSpectrumIndicesCount()) - { - // qDebug() << "There are precursor spectrum indices."; - - if(!fragmentation_spec.containsSpectrumPrecursorIndex( - qualified_mass_spectrum_csp - ->getPrecursorSpectrumIndex())) - { - should_account_mass_spectrum = false; - } - } - } - else - { - // Else, fragmentation is not a criterion for filtering data. So - // go on. + // There are two situations: + // + // 1. Evidently, since the fragmentation spec contains actual + // precursor mz values, if the mass spectrum contains no + // precursor ion data, then it should be dismissed + // immediately, without even calling the + // fragmentation_spec.containsMzPrecursors() function. + + // 2. We need to actually check if the fragmentation spec also + // lists precursor mz values. The function below checks if + // there are matches between the precursor mz values from the + // mass spectrum acquisition and the precursor mz values + // listed in the MsFragmentationSpec. The function returns + // true if at least one match could be performed. - // qDebug() << "The fragmentation spec is *not* valid."; - } + if(!precursor_ion_data_vector_size || + !fragmentation_spec.containsMzPrecursors( + precursor_ion_data_vector)) + return false; + + // else + // qDebug().noquote() + //<< "Mass spectrum:" << qualified_mass_spectrum_csp.get() + //<< "matched the MsFragmentationSpec's mz precursor " + //"values. " + //<< "Mass spectrum prec mz values: " + //<< qualified_mass_spectrum_csp + //->getPrecursorDataMzValuesAsString() + //<< "and MsFragmentationSpec prec mz values: " + //<< fragmentation_spec.mzPrecursorsToString(); } - } - // qDebug() << "The MsFragmentation ends out to check:" - //<< should_account_mass_spectrum << "for qualified mass spectrum: " - //<< qualified_mass_spectrum_csp.get() - //<< "at rt:" << qualified_mass_spectrum_csp.get()->getRtInMinutes(); + if(fragmentation_spec.precursorSpectrumIndicesCount()) + { + // qDebug() << "There are precursor spectrum indices."; - return should_account_mass_spectrum; + if(!fragmentation_spec.containsSpectrumPrecursorIndex( + qualified_mass_spectrum_csp->getPrecursorSpectrumIndex())) + return false; + } + } + //else + //{ + //// Else, fragmentation is not a criterion for filtering data. So + //// go on. + + //qDebug() << "The fragmentation spec is *not* valid. This means that the " + //"check succeeds because fragmentation is not a criterion for " + //"the filtering of the data."; + //} + + return true; } -void -QualifiedMassSpectrumVectorMassDataIntegrator::setInnermostRanges() +bool +QualifiedMassSpectrumVectorMassDataIntegrator::checkMsFragmentation( + pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) { + // qDebug(); - double start = std::numeric_limits::max(); - double end = std::numeric_limits::min(); - // The function below returns true only if a spec has been found that that - // type "RT_TO_ANY" - if(m_processingFlow.innermostRtRange(start, end)) - { - m_rtRange.first = start; - m_rtRange.second = end; - } - else - { - m_rtRange.first = std::numeric_limits::max(); - m_rtRange.second = std::numeric_limits::min(); - } + if(qualified_mass_spectrum_csp == nullptr) + qFatal("Cannot be nullptr"); - start = std::numeric_limits::max(); - end = std::numeric_limits::min(); + if(qualified_mass_spectrum_csp.get() == nullptr) + qFatal("Cannot be nullptr"); - // The function below returns true only if a spec has been found that that - // type "DT_TO_ANY" - if(m_processingFlow.innermostDtRange(start, end)) - { - m_dtRange.first = start; - m_dtRange.second = end; - } - else - { - m_dtRange.first = std::numeric_limits::max(); - m_dtRange.second = std::numeric_limits::min(); - } + // We want to go through all the ProcessingStep_s in the Flow. - start = std::numeric_limits::max(); - end = std::numeric_limits::min(); + // A processing flow contains a number of processing steps. - // The function below returns true only if a spec has been found that that - // type "DT_TO_ANY" - if(m_processingFlow.innermostMzRange(start, end)) - { - m_mzRange.first = start; - m_mzRange.second = end; - } - else + for(auto &step : m_processingFlow) { - m_mzRange.first = std::numeric_limits::max(); - m_mzRange.second = std::numeric_limits::min(); + if(!checkMsFragmentation(*step, qualified_mass_spectrum_csp)) + return false; } - // qDebug() << "Innermost RT range:" << m_rtRange.first << "->" - //<< m_rtRange.second << "Innermost DT range:" << m_dtRange.first - //<< "->" << m_dtRange.second; + return true; } -bool -QualifiedMassSpectrumVectorMassDataIntegrator::checkRtRange( - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) +void +QualifiedMassSpectrumVectorMassDataIntegrator::setInnermostRanges() { - double rt = qualified_mass_spectrum_csp->getRtInMinutes(); + //qDebug(); - bool res = (rt >= m_rtRange.first && rt <= m_rtRange.second); + m_innermostSteps2D.clear(); - // if(!res) - //{ - // qDebug() << "Rt range did not check:" << m_rtRange.first << "->" - //<< m_rtRange.second << "with value:" << rt; - //} - // else - //{ - // qDebug() << "Rt range did check:" << m_rtRange.first << "->" - //<< m_rtRange.second << "with value:" << rt; - //} + std::pair range_pair; - return res; -} + // The RT_TO_ANY processing type mask is the most generic mask involving RT + // data, that encompasses both the 1D RT_ONLY_TO_ANY, but also the 2D + // XX_RT_TO_ANY types. + // There are two situations: + // + // 1. when the processing step has a source type that matches the ANY_RT mask + // is 1D, then we only are interested in the innermost RT range values. -bool -QualifiedMassSpectrumVectorMassDataIntegrator::checkDtRange( - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) -{ - // Only try to actually check the values if that the dt time values were - // intented to be accounted for. Otherwise just return true because the dt - // times are not a criterion. + // 2. when the processing step is 2D, that is, the selection polygon is + // rectangle, if any one of the source types matches the mask, then the + // correct selection polygon axis range is used. - if(m_dtRange.first == std::numeric_limits::max() || - m_dtRange.second == std::numeric_limits::min()) - { - // qDebug() - //<< "m_dtRange.first is max() and m_dtRange.second is min(). This means - //" "that DT range is not a criterion. Returning true."; - return true; - } + // No that when asking that relevant 2D steps be stored in the vector + // m_innermostSteps2D, we specify two options: + // + // 1. That 2D steps be stored *only*. 2. That only 2D steps that have a + // skewed selection polygon be stored. This option is easily understood: if a + // rectangle is squared, then it is fully described using two ranges, one + // range for one axis and another range for the other axis. Only skewed + // selection polygons are a challenge for the analysis of the data. The + // checkXxRange() functions do monitor the m_innermostSteps2D vector for + // skewed selection polygon rectangles. - double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); + m_dtRange.first = std::numeric_limits::quiet_NaN(); + m_dtRange.second = std::numeric_limits::quiet_NaN(); - if(dt != -1) + // true: only 2D steps + // true: only skewed 2D steps + if(m_processingFlow.innermostRange( + "ANY_DT", range_pair, &m_innermostSteps2D, true, true)) { - // qDebug() << "dt:" << dt << "m_dtRange.first:" << m_dtRange.first - //<< "m_dtRange.second:" << m_dtRange.second; + //qDebug() << "innermost DT range:" << range_pair.first << "-" + //<< range_pair.second; - return (dt >= m_dtRange.first && dt <= m_dtRange.second); + m_dtRange.first = range_pair.first; + m_dtRange.second = range_pair.second; } - // qDebug() << "Returning true."; - - return true; -} - + m_mzRange.first = std::numeric_limits::quiet_NaN(); + m_mzRange.second = std::numeric_limits::quiet_NaN(); -bool -QualifiedMassSpectrumVectorMassDataIntegrator::checkProcessingStep( - const ProcessingStep &step, - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) -{ - // qDebug(); - - // A processing step is a collection of mapped items: - // std::map m_processingTypeSpecMap; - // - // For each item, we need to check if the node matches the spec. - - for(auto &&pair : step.getProcessingTypeSpecMap()) + // true: only 2D steps + // true: only skewed 2D steps + if(m_processingFlow.innermostRange( + "ANY_MZ", range_pair, &m_innermostSteps2D, true, true)) { - if(checkProcessingSpec(pair, qualified_mass_spectrum_csp)) - { - // qDebug() << "The node:" << &node << "matches the iterated spec."; - } - else - { - // qDebug() << "The node:" << &node - //<< "does not match the iterated spec. Returning false."; + //qDebug() << "innermost MZ range:" << range_pair.first << "-" + //<< range_pair.second; - return false; - } + m_mzRange.first = range_pair.first; + m_mzRange.second = range_pair.second; } - // qDebug() << "The node:" << &node - //<< "matched all the processing specs: matching the step: returning " - //"true."; - - return true; -} - - -bool -QualifiedMassSpectrumVectorMassDataIntegrator::checkProcessingStep( - const ProcessingStep &step, - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp, - pappso::MassDataCombinerInterface &mass_spectrum_combiner) -{ - // qDebug(); + m_rtRange.first = std::numeric_limits::quiet_NaN(); + m_rtRange.second = std::numeric_limits::quiet_NaN(); - // A processing step is a collection of mapped items: - // std::map m_processingTypeSpecMap; - // - // For each item, we need to check if the node matches the spec. - - for(auto &&pair : step.getProcessingTypeSpecMap()) + // true: only 2D steps + // true: only skewed 2D steps + if(m_processingFlow.innermostRange( + "ANY_RT", range_pair, &m_innermostSteps2D, true, true)) { - if(checkProcessingSpec( - pair, qualified_mass_spectrum_csp, mass_spectrum_combiner)) - { - // qDebug() << "The node:" << &node << "matches the iterated spec."; - } - else - { - // qDebug() << "The node:" << &node - //<< "does not match the iterated spec. Returning false."; + //qDebug() << "innermost RT range:" << range_pair.first << "-" + //<< range_pair.second; - return false; - } + m_rtRange.first = range_pair.first; + m_rtRange.second = range_pair.second; + } + // Sanity check. + // It it not possible that not a single step provides a range for RT, given + // that such a range should have been created upon reading the data from the + // disk followed by the computation of the TIC chromatogram. + else + { + qFatal( + "Programming error. Not possible that a processing flow has not a " + "single step with a retention range-specifying step."); } - // qDebug() << "The node:" << &node - //<< "matched all the processing specs: matching the step: returning " - //"true."; - - return true; + //qDebug() << "The m_innermostSteps2D has now" << m_innermostSteps2D.size() + //<< "steps"; } -bool -QualifiedMassSpectrumVectorMassDataIntegrator::checkProcessingSpec( - const std::pair &type_spec_pair, - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) +std::size_t +QualifiedMassSpectrumVectorMassDataIntegrator::fillInSelectionPolygonSpecs( + std::vector &selection_polygon_specs) { - // qDebug(); - - // This is the most elemental component of a ProcessingFlow, so here we - // actually look into the node. + //qDebug() + //<< "Fill in the selection polygon specs (MZ-related stuff) vector from " + //"m_innermostSteps2D with size:" + //<< m_innermostSteps2D.size(); - // A Processing spec defines a range of acceptable values and holds a - // pointer to a MsFragmentationSpec : + // This function is responsible for configuring the selection polygon specs by + // looking at m_innermostSteps2D steps that contains MZ data king. These specs + // are then used by filters to determine if Trace or Mass Spectrum m/z data + // points are to be used or not for the integration. All this is required to + // abide by selection polygons that are not rectangle but are oblique, or + // skewed. - // MsFragmentationSpec *mpa_msFragmentationSpec = nullptr; - // double m_start = std::numeric_limits::max(); - // double m_end = std::numeric_limits::min(); - - // qDebug() << "Node:" << &node << "with qualified mass spectrum:" - //<< node.getQualifiedMassSpectrum()->toString(); - - // In the step, each processing spec is associated to a processing type in a - // map. We get the pair of both to check the compliance of the node to the - // range and the processing type. + for(auto &&step : m_innermostSteps2D) + { + if(step.getSelectionPolygon().isRectangle()) + { + // The selection polygon is rectangle, which means that the ranges + // extracted from the processing flow at construction time are fully + // sufficient to characterize the combination work. - const ProcessingSpec *spec_p = type_spec_pair.second; + //qDebug() << "Currently iterated step's selection polygon *is* " + //"rectangle. Skipping it." + //<< step.toString(); - if(qualified_mass_spectrum_csp == nullptr) - qFatal("Cannot be nullptr"); + continue; + } - if(qualified_mass_spectrum_csp.get() == nullptr) - qFatal("Cannot be nullptr"); + //qDebug() << "Iterating in inner most step 2D:" << step.toString(); - const MsFragmentationSpec fragmentation_spec = - spec_p->getMsFragmentationSpec(); + // There are two kinds of processing types of interest: DT_MZ_TO_ANY and + // MZ_RT_TO_ANY. - if(fragmentation_spec.isValid()) - { - if(fragmentation_spec.precursorMzValuesCount()) + if(step.getSrcProcessingType(pappso::Axis::x).bitMatches("MZ")) { - const std::vector - &precursor_ion_data_vector = - qualified_mass_spectrum_csp->getPrecursorIonData(); + //qDebug() << "Step x source type matches MZ"; - if(!fragmentation_spec.containsMzPrecursors( - precursor_ion_data_vector)) + if(step.getSrcProcessingType(pappso::Axis::y).bitMatches("DT")) { - return false; - } - } + //qDebug() << "We are handling a DT_MZ step source type"; - if(fragmentation_spec.precursorSpectrumIndicesCount()) - { - // qDebug() << "There are precursor spectrum indices."; + // We want the selection polygon to have x:DT and y:MZ. - if(!fragmentation_spec.containsSpectrumPrecursorIndex( - qualified_mass_spectrum_csp->getPrecursorSpectrumIndex())) + selection_polygon_specs.push_back(pappso::SelectionPolygonSpec( + step.getSelectionPolygon().transpose(), pappso::DataKind::dt)); + } + else if(step.getSrcProcessingType(pappso::Axis::y).bitMatches("RT")) { - // qDebug() << "Node:" << &node - //<< "The precursor spectrum index does not match."; + //qDebug() << "We are handling a MZ_RT step source type"; - return false; + // We want the selection polygon to have x:RT and y:MZ. + + selection_polygon_specs.push_back(pappso::SelectionPolygonSpec( + step.getSelectionPolygon().transpose(), pappso::DataKind::rt)); } else - { - // qDebug() - //<< "The mass spectrum has a precursor spectrum index of:" - //<< qualified_mass_spectrum_csp->getPrecursorSpectrumIndex() - //<< "and it matches one of the requested list."; - } + qFatal("Programming error."); } - } - else - { - // Else, fragmentation is not a criterion for filtering data. So go - // on. - - // qDebug() << "Node:" << &node - //<< "The fragmentation spec is *not* valid. Accounting the " - //"spectrum."; - } + else if(step.getSrcProcessingType(pappso::Axis::y).bitMatches("MZ")) + { + //qDebug() << "Step y source type matches MZ"; - // qDebug() << "Node:" << &node << "Frag spec ok, going on with the spec - // check."; + if(step.getSrcProcessingType(pappso::Axis::x).bitMatches("DT")) + { + //qDebug() << "We are handling a DT_MZ step source type"; - ProcessingType type = type_spec_pair.first; + // We want the selection polygon to have x:DT and y:MZ. - if(type.bitMatches("RT_TO_ANY") || type.bitMatches("FILE_TO_MZ")) - { - // qDebug(); - if(!checkProcessingTypeByRt(type_spec_pair, qualified_mass_spectrum_csp)) - { - // qDebug() << "Node:" << &node << "Checking by Rt failed."; + selection_polygon_specs.push_back(pappso::SelectionPolygonSpec( + step.getSelectionPolygon(), pappso::DataKind::dt)); + } + else if(step.getSrcProcessingType(pappso::Axis::x).bitMatches("RT")) + { + //qDebug() << "We are handling a MZ_RT step source type"; - return false; - } - } - else if(type.bitMatches("MZ_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByMz(type_spec_pair, qualified_mass_spectrum_csp)) - { - // qDebug() << "Node:" << &node << "Checking by Mz failed."; + // We want the selection polygon to have x:RT and y:MZ. - return false; - } - } - else if(type.bitMatches("DT_TO_ANY")) - { - if(!checkProcessingTypeByDt(type_spec_pair, qualified_mass_spectrum_csp)) - { - return false; + selection_polygon_specs.push_back(pappso::SelectionPolygonSpec( + step.getSelectionPolygon(), pappso::DataKind::rt)); + } + else + qFatal("Programming error."); } + //else + //qDebug() << "The step a no source type involving MZ data."; } + // End of + // for(auto &&step : m_innermostSteps2D) - // At this point we seem to understand that the node matched! - - return true; + return selection_polygon_specs.size(); } bool -QualifiedMassSpectrumVectorMassDataIntegrator::checkProcessingSpec( - const std::pair &type_spec_pair, - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp, - pappso::MassDataCombinerInterface &mass_spectrum_combiner_sp) +QualifiedMassSpectrumVectorMassDataIntegrator::checkInnermostDtRt2DSteps( + pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) { - // qDebug(); - // This is the most elemental component of a ProcessingFlow, so here we - // actually look into the node. - - // qDebug() << "Node:" << &node << "with qualified mass spectrum:" - //<< node.getQualifiedMassSpectrum()->toString(); - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(qualified_mass_spectrum_csp == nullptr) - qFatal("Cannot be nullptr"); + double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); + double rt = qualified_mass_spectrum_csp->getRtInMinutes(); - if(qualified_mass_spectrum_csp.get() == nullptr) - qFatal("Cannot be nullptr"); + // qDebug() << "The vector of innermost 2D steps has size:" + //<< m_innermostSteps2D.size(); - const MsFragmentationSpec fragmentation_spec = - spec_p->getMsFragmentationSpec(); + // Now see if we have to also account for 2D selection skewed polygons + // involving dt and rt. - if(fragmentation_spec.isValid()) + for(auto &&step : m_innermostSteps2D) { - // qDebug() << "Node:" << &node << "Spec's fragmentation spec *is* - // valid:" - //<< fragmentation_spec.toString(); - - if(fragmentation_spec.precursorMzValuesCount()) - { - if(!fragmentation_spec.containsMzPrecursor( - qualified_mass_spectrum_csp->getPrecursorMz())) - { - // qDebug() << "Node:" << &node - //<< "The precursor mz does not match."; + // qDebug() << "Iterating in step:" << step.toString(); - return false; - } - } + // A skewed selection polygon was found. - if(fragmentation_spec.precursorSpectrumIndicesCount()) + if(step.getSrcProcessingType(pappso::Axis::x).bitMatches("DT") && + step.getSrcProcessingType(pappso::Axis::y).bitMatches("RT")) { - // qDebug() << "There are precursor spectrum indices."; + // That had DT and RT axes. - if(!fragmentation_spec.containsSpectrumPrecursorIndex( - qualified_mass_spectrum_csp->getPrecursorSpectrumIndex())) + if(!step.getSelectionPolygon().contains(QPointF(dt, rt))) { - // qDebug() << "Node:" << &node - //<< "The precursor spectrum index does not match."; - + // qDebug() << "Checking step:" << step.toString() + //<< "for qualified mass spectrum with dt|rt:" << dt << "|" + //<< rt << "failed"; return false; } - else - { - // qDebug() - //<< "The mass spectrum has a precursor spectrum index of:" - //<< qualified_mass_spectrum_csp->getPrecursorSpectrumIndex() - //<< "and it matches one of the requested list."; - } + // else + // qDebug() << "Checking step:" << step.toString() + //<< "for qualified mass spectrum with dt|rt:" << dt << "|" + //<< rt << "succeeded."; } - } - else - { - // Else, fragmentation is not a criterion for filtering data. So go - // on. - - // qDebug() << "Node:" << &node - //<< "The fragmentation spec is *not* valid. Accounting the " - //"spectrum."; - } - - // qDebug() << "Node:" << &node << "Frag spec ok, going on with the spec - // check."; - - ProcessingType type = type_spec_pair.first; - - if(type.bitMatches("RT_TO_ANY") || type.bitMatches("FILE_TO_MZ")) - { - // qDebug(); - if(!checkProcessingTypeByRt(type_spec_pair, qualified_mass_spectrum_csp)) + else if(step.getSrcProcessingType(pappso::Axis::x).bitMatches("RT") && + step.getSrcProcessingType(pappso::Axis::y).bitMatches("DT")) { - // qDebug() << "Node:" << &node << "Checking by Rt failed."; + // That had DT and RT axes. - return false; - } - } - else if(type.bitMatches("MZ_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByMz(type_spec_pair, - qualified_mass_spectrum_csp, - mass_spectrum_combiner_sp)) - { - // qDebug() << "Node:" << &node << "Checking by Mz failed."; + qWarning() << "The selection polygon should have x:DT and y:RT"; - return false; - } - } - else if(type.bitMatches("DT_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByDt(type_spec_pair, qualified_mass_spectrum_csp)) - { - return false; - } + if(!step.getSelectionPolygon().contains(QPointF(rt, dt))) + { + // qDebug() << "Checking step:" << step.toString() + //<< "for qualified mass spectrum with dt|rt:" << dt << "|" + //<< rt << "failed"; + return false; + } + // else + // qDebug() << "Checking step:" << step.toString() + //<< "for qualified mass spectrum with dt|rt:" << dt << "|" + //<< rt << "succeeded."; + } + // else + // qDebug() << "The step" << step.toString() + //<< "source types did not match DT|RT nor RT|DT. " + //"Skipping it."; } - // At this point we seem to understand that the node matched! - return true; } bool -QualifiedMassSpectrumVectorMassDataIntegrator::checkProcessingTypeByRt( - const std::pair &type_spec_pair, +QualifiedMassSpectrumVectorMassDataIntegrator::checkDtRange( pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) { - // qDebug(); + //qDebug(); - const ProcessingSpec *spec_p = type_spec_pair.second; + // We are asked to check if the mass spectrum matches the DT range. This + // means that we can quickly check that agains all DT range that was + // determined during the construction time of this integrator. - if(spec_p->hasValidRange()) - { - double rt = qualified_mass_spectrum_csp->getRtInMinutes(); + // Attention, all this is useful only if the processing flow was seen + // containings steps involving the DT data kind. - if(rt >= spec_p->getStart() && rt <= spec_p->getEnd()) - { - // qDebug() << "Returning true for Rt."; - return true; - } - else - { - return false; - } + if(std::isnan(m_dtRange.first) || std::isnan(m_dtRange.second)) + { + // There is no DT range data, which means DT is not a criterion to + // filter mass spectra. Return true so that the mass spectrum is + // accounted for. + return true; } - return true; -} - - -bool -QualifiedMassSpectrumVectorMassDataIntegrator::checkProcessingTypeByMz( - const std::pair &type_spec_pair, - [[maybe_unused]] pappso::QualifiedMassSpectrumCstSPtr - &qualified_mass_spectrum_csp) -{ - // qDebug(); - - // Are there specs about the m/z range to be accounted for in the - // computation? + double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); - const ProcessingSpec *spec_p = type_spec_pair.second; + // qDebug() << qSetRealNumberPrecision(10) << "dt range:" << m_dtRange.first + //<< "-" << m_dtRange.second << "The mass spectrum dt value:" << dt; - if(spec_p->hasValidRange()) + if(dt == -1) { - // qDebug() << "Needed a m/z range filtering:" << spec_p->toString(); - - // The point is that if there are more than one spec in the the flow's - // steps that limit the m/z range, we want to be sure to perform the - // combination using the innermost range. So ask the ProcessingFlow to - // actually compute that innermost m/z range. - - // Make a local copy of the type_spec_pair - - std::pair local_type_spec_pair( - type_spec_pair); - - if(m_processingFlow.innermostMzRange(local_type_spec_pair)) - { - // qDebug() << "MZ range limitations were found."; - - m_limitMzRangeStart = local_type_spec_pair.second->getStart(); - m_limitMzRangeEnd = local_type_spec_pair.second->getEnd(); - } - else - qFatal( - "Cannot be that there is no innermost m/z range if there is a " - "valid " - "m/z range in a spec."); + // There is no DT range data in the mass spectrum, which means DT cannot + // be a criterion to filter mass spectra. Return true so that the mass + // spectrum is accounted for. + return true; } - // Return true because we'll account that node whatever the mz range - // criterion. But, the limits will be accounted for in the visit() function - // at the moment of TIC calculation. - - return true; -} - - -bool -QualifiedMassSpectrumVectorMassDataIntegrator::checkProcessingTypeByMz( - const std::pair &type_spec_pair, - [[maybe_unused]] pappso::QualifiedMassSpectrumCstSPtr - &qualified_mass_spectrum_csp, - pappso::MassDataCombinerInterface &mass_spectrum_combiner) -{ - // qDebug(); - - // Are there specs about the m/z range to be accounted for in the - // computation? - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(spec_p->hasValidRange()) + if(!(dt >= m_dtRange.first && dt <= m_dtRange.second)) { - // qDebug() << "Needed a m/z range filtering:" << spec_p->toString(); - - // The point is that if there are more than one spec in the the flow's - // steps that limit the m/z range, we want to be sure to perform the - // combination using the innermost range. So ask the ProcessingFlow to - // actually compute that innermost m/z range. - - // Make a local copy of the type_spec_pair - - std::pair local_type_spec_pair( - type_spec_pair); - - if(m_processingFlow.innermostMzRange(local_type_spec_pair)) - { - mass_spectrum_combiner.setFilterResampleKeepXRange( - pappso::FilterResampleKeepXRange( - local_type_spec_pair.second->getStart(), - local_type_spec_pair.second->getEnd())); - - m_limitMzRangeStart = local_type_spec_pair.second->getStart(); - m_limitMzRangeEnd = local_type_spec_pair.second->getEnd(); - } - else - qFatal( - "Cannot be that there is no innermost m/z range if there is a " - "valid " - "m/z range in a spec."); + //qDebug() << "Returning false on the check of the dt range."; + return false; } - // Return true because we'll account that node whatever the mz range - // criterion. But, the limits will be accounted for in the visit() function - // at the moment of TIC calculation. + // Now see if we have to also account for 2D selection skewed polygons + // involving dt and rt. - return true; + return checkInnermostDtRt2DSteps(qualified_mass_spectrum_csp); } bool -QualifiedMassSpectrumVectorMassDataIntegrator::checkProcessingTypeByDt( - const std::pair &type_spec_pair, +QualifiedMassSpectrumVectorMassDataIntegrator::checkRtRange( pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp) { - // qDebug(); + //qDebug(); - const ProcessingSpec *spec_p = type_spec_pair.second; + // We are asked to check if the mass spectrum matches the RT range. This + // means that we can quickly check that agains all RT range that was + // determined during the construction time of this integrator. - if(spec_p->hasValidRange()) - { - // qDebug() << "spec_p has valid range:" << spec_p->getStart() << "->" - //<< spec_p->getEnd(); + double rt = qualified_mass_spectrum_csp->getRtInMinutes(); - double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); + if(!(rt >= m_rtRange.first && rt <= m_rtRange.second)) + { + // qDebug() << "rt:" << rt << "failed to check range:" + //<< "[" << m_rtRange.first << "-" << m_rtRange.second << "]"; - if(dt >= spec_p->getStart() && dt <= spec_p->getEnd()) - return true; - else - return false; + return false; } - return true; + // Now see if we have to also account for 2D selection skewed polygons + // involving dt and rt. + + return checkInnermostDtRt2DSteps(qualified_mass_spectrum_csp); } diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegrator.hpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegrator.hpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegrator.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegrator.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -135,17 +135,22 @@ MsRunDataSetCstSPtr mcsp_msRunDataSet = nullptr; ProcessingFlow m_processingFlow; - + std::size_t m_maxThreadUseCount = 0; - std::pair m_rtRange = std::pair( - std::numeric_limits::max(), std::numeric_limits::min()); + std::vector m_innermostSteps2D; - std::pair m_dtRange = std::pair( - std::numeric_limits::max(), std::numeric_limits::min()); + std::vector m_selectionPolygonSpecs; - std::pair m_mzRange = std::pair( - std::numeric_limits::max(), std::numeric_limits::min()); + std::pair m_dtRange = + std::pair(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); + std::pair m_mzRange = + std::pair(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); + std::pair m_rtRange = + std::pair(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); const QualifiedMassSpectraVectorSPtr mcsp_qualifiedMassSpectraToIntegrateVector; @@ -163,59 +168,32 @@ virtual void setInnermostRanges(); + virtual std::size_t fillInSelectionPolygonSpecs( + std::vector &selection_polygon_specs); + virtual bool checkMsLevel( pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); virtual bool checkMsFragmentation( + const ProcessingStep &processing_step, pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); - virtual bool checkRtRange( - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); - - virtual bool checkDtRange( - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); - - virtual bool checkProcessingStep( - const ProcessingStep &step, - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); - - virtual bool checkProcessingStep( - const ProcessingStep &step, - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp, - pappso::MassDataCombinerInterface &mass_spectrum_combiner); - - virtual bool checkProcessingSpec( - const std::pair &type_spec_pair, - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); - - virtual bool checkProcessingSpec( - const std::pair &type_spec_pair, - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp, - pappso::MassDataCombinerInterface &mass_spectrum_combiner); - - virtual bool checkProcessingTypeByRt( - const std::pair &spec_type_pair, + virtual bool checkMsFragmentation( pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); - virtual bool checkProcessingTypeByMz( - const std::pair &spec_type_pair, + virtual bool checkRtRange( pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); - virtual bool checkProcessingTypeByMz( - const std::pair &spec_type_pair, - pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp, - pappso::MassDataCombinerInterface &mass_spectrum_combiner); - - virtual bool checkProcessingTypeByDt( - const std::pair &spec_type_pair, + virtual bool checkDtRange( pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); protected: // We almost systematically need these m/z range values when making visits: // one criterium might be that the m/z value of data points (the x member of // DataPoint) be contained within the limit m/z range. - double m_limitMzRangeStart = std::numeric_limits::max(); - double m_limitMzRangeEnd = std::numeric_limits::max(); + // + // Note that we set them to min() and max() because we'll use std::min() and + // std::max() against these values. using Iterator = std::vector::const_iterator; @@ -229,6 +207,9 @@ std::size_t thread_count, int nodes_per_thread); + bool checkInnermostDtRt2DSteps( + pappso::QualifiedMassSpectrumCstSPtr &qualified_mass_spectrum_csp); + private: }; diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDt.cpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDt.cpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDt.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDt.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -33,6 +33,8 @@ /////////////////////// StdLib includes #include +#include + /////////////////////// OPENMP include #include @@ -48,6 +50,7 @@ /////////////////////// Local includes #include "QualifiedMassSpectrumVectorMassDataIntegratorToDt.hpp" +#include "ProcessingStep.hpp" int qualifiedMassSpectrumVectorMassDataIntegratorToDtMetaTypeId = @@ -102,256 +105,10 @@ } -// Old version -#if 0 void -QualifiedMassSpectrumVectorMassDataIntegratorToDt::integrateToDt() +QualifiedMassSpectrumVectorMassDataIntegratorToDt::integrate() { - //qDebug(); - - std::chrono::system_clock::time_point chrono_start_time = - std::chrono::system_clock::now(); - - // If there are no data, nothing to do. - std::size_t mass_spectra_count = m_vectorOfQualifiedMassSpectraSPtr->size(); - - if(!mass_spectra_count) - { - qDebug() << "The qualified mass spectrum vector is empty, nothing to do."; - - emit cancelOperationSignal(); - } - - // Nothing special to do about processing flow info because that must have - // been set before calling this function. - - // We need to clear the map trace! - m_mapTrace.clear(); - - // Determine the best number of threads to use and how many spectra to provide - // each of the threads. - - // In the pair below, first is the ideal number of threads and second is the - // number of mass spectra per thread. - std::pair best_parallel_params = - bestParallelIntegrationParams(mass_spectra_count); - - // Handy alias. - using Iterator = - std::vector::const_iterator; - - // Prepare a set of iterators that will distribute all the mass spectra - // uniformly. - std::vector> iterators = - calculateQualifiedMassSpectrumVectorIteratorPairs( - best_parallel_params.first, best_parallel_params.second); - - // Set aside a vector of std::map to store retention time - // values and their TIC intensity - - // Handy aliases. - using Pair = std::pair; - using Map = std::map; - using MapSPtr = std::shared_ptr; - - std::vector vector_of_dt_spec_map; - for(std::size_t iter = 0; iter < iterators.size(); ++iter) - vector_of_dt_spec_map.push_back( - std::make_shared()); - - // Now that we have all the parallel material, we can start the parallel work. - emit setProgressBarMaxValueSignal(mass_spectra_count); - - omp_set_num_threads(iterators.size()); -#pragma omp parallel for ordered - for(std::size_t iter = 0; iter < iterators.size(); ++iter) - { - qDebug() << "thread index:" << iter; - - // Get the iterator range that we need to deal in this thread. - Iterator current_iterator = iterators.at(iter).first; - Iterator end_iterator = iterators.at(iter).second; - - // Get the map for this thread. - - MapSPtr current_dt_spec_map_sp = vector_of_dt_spec_map.at(iter); - - std::size_t qualified_mass_spectrum_count = - std::distance(current_iterator, end_iterator); - - qDebug() << "For thread index:" << iter - << "the number of mass spectra to process:" - << qualified_mass_spectrum_count; - - while(current_iterator != end_iterator) - { - // We want to be able to intercept any cancellation of the - // operation. - - if(m_isOperationCancelled) - break; - - // Make the computation. - - // For each mass spectrum all we need is compute its TIC value, that - // is, the sum of all its intensities (the y value of the DataPoint - // instances it contains). - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - *current_iterator; - - // Test if the mass spectrum is nullptr. - - pappso::MassSpectrumCstSPtr mass_spectrum_csp = - qualified_mass_spectrum_csp->getMassSpectrumCstSPtr(); - - if(qualified_mass_spectrum_csp == nullptr) - qFatal("Cannot be nullptr"); - if(qualified_mass_spectrum_csp.get() == nullptr) - qFatal("Cannot be nullptr"); - - if(qualified_mass_spectrum_csp->getMassSpectrumSPtr() == nullptr) - { - //qDebug() << "Need to access the mass data right from the file."; - - std::size_t mass_spectrum_index = - mcsp_msRunDataSet->getMsRunDataSetTreeCstSPtr() - ->massSpectrumIndex(qualified_mass_spectrum_csp); - - pappso::MsRunReaderCstSPtr ms_run_reader_csp = - mcsp_msRunDataSet->getMsRunReaderCstSPtr(); - - qualified_mass_spectrum_csp = - std::make_shared( - ms_run_reader_csp->qualifiedMassSpectrum(mass_spectrum_index, - true)); - } - - if(qualified_mass_spectrum_csp == nullptr) - { - qFatal("Failed to read the mass spectral data from the file."); - } - - // Great, at this point we actually have the mass spectrum! - - double mass_spectrum_sum_y = 0; - mass_spectrum_sum_y = qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY(); - - if(!mass_spectrum_sum_y) - { - continue; - } - - double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); - - using Iterator = Map::iterator; - - // Try to insert the pair into the map. Check if that was done or not. - std::pair res = - current_dt_spec_map_sp->insert(Pair(dt, mass_spectrum_sum_y)); - - if(!res.second) - { - // One other same rt value was seen already (like in ion mobility - // mass spectrometry, for example). Only increment the y value. - - res.first->second += mass_spectrum_sum_y; - } - - // qDebug() << "Processed one more spectrum."; - - emit incrementProgressBarCurrentValueAndSetStatusTextSignal( - 1, "Processing spectra"); - - // Now we can go to the next mass spectrum. - ++current_iterator; - } - // End of - // while(current_iterator != end_iterator) - } - // End of - // #pragma omp parallel for ordered - // for(std::size_t iter = 0; iter < iterators.size(); ++iter) - - // In the loop above, for each thread, a std::map map was - // filled in with the rt, TIC pairs. - - // If the task was cancelled, the monitor widget was locked. We need to - // unlock it. - emit unlockTaskMonitorCompositeWidgetSignal(); - emit setupProgressBarSignal(0, vector_of_dt_spec_map.size() - 1); - - // We might be here because the user cancelled the operation in the for loop - // above (visiting all the visitors). In this case m_isOperationCancelled is - // true. We want to set it back to false, so that the following loop is gone - // through. The user can ask that the operation be cancelled once more. But - // we want that at least the performed work be used to show the trace. - - m_isOperationCancelled = false; - int iter = 0; - - for(auto &&map_sp : vector_of_dt_spec_map) - { - ++iter; - - if(m_isOperationCancelled) - break; - - //qDebug() << "In the consolidating loop, iter:" << iter - //<< "with a map of this size : " << map_sp->size(); - - for(auto &&pair : *map_sp) - { - - emit setStatusTextSignal( - QString("Consolidating drift spectra from thread %1") - .arg(iter)); - - emit setProgressBarCurrentValueSignal(iter); - - double dt = pair.first; - double tic = pair.second; - - using Iterator = Map::iterator; - - std::pair res = m_mapTrace.insert(Pair(dt, tic)); - - if(!res.second) - { - // One other same rt value was seen already (like in ion mobility - // mass spectrometry, for example). Only increment the y value. - - res.first->second += tic; - } - } - } - - // Write the data to file so that we can check. It works !!! - // pappso::Utils::appendToFile(m_mapTrace.toString(), "/tmp/prova.txt"); - - std::chrono::system_clock::time_point chrono_end_time = - std::chrono::system_clock::now(); - - QString chrono_string = pappso::Utils::chronoIntervalDebugString( - "Integration to drift spectrum took:", - chrono_start_time, - chrono_end_time); - - emit logTextToConsoleSignal(chrono_string); - - //qDebug().noquote() << chrono_string; - - return; -} - -// Old version -#endif - - -void -QualifiedMassSpectrumVectorMassDataIntegratorToDt::integrateToDt() -{ - // qDebug(); + qDebug(); std::chrono::system_clock::time_point chrono_start_time = std::chrono::system_clock::now(); @@ -367,8 +124,7 @@ emit cancelOperationSignal(); } - // Nothing special to do about processing flow info because that must have - // been set before calling this function. + qDebug() << "The number of mass spectra to handle:" << mass_spectra_count; // We need to clear the map trace! m_mapTrace.clear(); @@ -381,21 +137,36 @@ if(!m_processingFlow.size()) qFatal("The processing flow cannot be empty. Program aborted."); - // Get the most recent step that holds all the specifics of this integration. - const ProcessingStep *most_recent_processing_step_p = - m_processingFlow.mostRecentStep(); - - // There must be at least one ProcessingSpec (and thus a type) in the - // processing step. - - if(!most_recent_processing_step_p->processingTypes().size()) - qFatal("The processing step cannot be empty. Program aborted."); - - // We are integrating to m/z so we need a spec description that matches - // "ANY_TO_MZ". - - if(!most_recent_processing_step_p->matches("ANY_TO_DT")) - qFatal("There should be one ProcessingType = ANY_TO_DT. Program aborted."); + // When constructing this integrator, the processing flow passed as parameter + // was used to gather innermost ranges data. When the steps that match + // the innermost criterion, these are stored in m_innermostSteps2D. When the + // steps are non-2D steps, then only the m_xxRange values are updated. + + // If the m_innermostSteps2D vector of ProcessingSteps is non-empty, then, + // that means that we may have some MZ-related 2D processing steps to account + // at combination time, because that is precisely the only moment that we can + // do that work. To be able to provide selection polygon an mass + // spectrum-specific dt|rt data, we have the SelectionPolygonSpec class. There + // can be as many such class instances as required to document the integration + // boundaries rt/mz and dt/mz for example. This is why we need to fill in the + // vector of SelectionPolygonSpec and then set that to the combiner. + + // Note, however, that the hassle described above only is acceptable when the + // selection polygon is not square. If the selection polygon is square, then + // the ranges suffice, and they have been filled-in properly upon construction + // of this integrator. + + qDebug() << "Now filling-in the selection_polygon_specs for any 2D step that " + "has a source type involving the MZ data kind."; + + std::vector selection_polygon_specs; + + std::size_t selection_polygon_spec_count = + fillInSelectionPolygonSpecs(selection_polygon_specs); + + qDebug() << selection_polygon_spec_count + << "selection polygon specs were retained for the configuration of " + "the filter."; // At this point, allocate a visitor that is specific for the calculation of // the mass spectrum. Since we are not binning, we can use a visitor that @@ -411,8 +182,7 @@ // In the pair below, first is the ideal number of threads and second is the // number of mass spectra per thread. std::pair best_parallel_params = - bestParallelIntegrationParams( - mcsp_qualifiedMassSpectraToIntegrateVector->size()); + bestParallelIntegrationParams(mass_spectra_count); // Handy alias. using MassSpecVector = std::vector; @@ -437,14 +207,11 @@ for(std::size_t iter = 0; iter < iterators.size(); ++iter) vector_of_dt_spec_map.push_back(std::make_shared()); - - // Now that we have all the parallel material, we can start the parallel work. - emit setProgressBarMaxValueSignal( - mcsp_qualifiedMassSpectraToIntegrateVector->size()); - // Now that we have all the parallel material, we can start the parallel work. emit setProgressBarMaxValueSignal(mass_spectra_count); + qDebug() << "Starting the iteration in the visitors."; + omp_set_num_threads(iterators.size()); #pragma omp parallel for ordered for(std::size_t iter = 0; iter < iterators.size(); ++iter) @@ -482,6 +249,11 @@ qualified_mass_spectrum_csp = checkQualifiedMassSpectrum(qualified_mass_spectrum_csp); + if(qualified_mass_spectrum_csp == nullptr) + qFatal( + "Programming error. Not possible that shared pointer to " + "qualified mass spectrum be nullptr."); + // Great, at this point we actually have the mass spectrum! // We now need to ensure that the processing flow allows for this mass @@ -491,74 +263,42 @@ // that matches the greatest MS level found in the member processing // flow instance. - if(!checkMsLevel(qualified_mass_spectrum_csp) || - !checkRtRange(qualified_mass_spectrum_csp) || - !checkDtRange(qualified_mass_spectrum_csp)) + if(!checkMsLevel(qualified_mass_spectrum_csp)) { - // if(!checkMsLevel(qualified_mass_spectrum_csp)) - // qDebug() << "MS level did not check."; - - // if(!checkRtRange(qualified_mass_spectrum_csp)) - // qDebug() << "RT range did not check."; - - // if(!checkDtRange(qualified_mass_spectrum_csp)) - // qDebug() << "DT range did not check."; - - // qDebug() << "The checks returned false"; - + qDebug() << "The MsLevel check returned false"; ++current_iterator; continue; } - - // At this point we need to go deep in the processing flow's steps to - // check if the node matches the whole set of the steps' specs. - - // qDebug() << "The processing flow has" << m_processingFlow.size() << - // "steps."; - - // Boolean value needed because we need to break two loops. - bool should_increment_iterator_and_continue = false; - - for(auto &&step : m_processingFlow) - { - if(!checkProcessingStep(*step, qualified_mass_spectrum_csp)) - { - should_increment_iterator_and_continue = true; - break; - } - } - - if(should_increment_iterator_and_continue) + if(!checkMsFragmentation(qualified_mass_spectrum_csp)) { + qDebug() << "The MsFragmentation check returned false"; ++current_iterator; continue; } - double mass_spectrum_sum_y = 0; - - // These values are set in the in the base class constuctor. + // Make easy check about RT and DT. - if(m_mzRange.first != std::numeric_limits::max() && - m_mzRange.second != std::numeric_limits::min()) + if(!checkRtRange(qualified_mass_spectrum_csp)) { - mass_spectrum_sum_y = - qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY( - m_mzRange.first, m_mzRange.second); + qDebug() << "checkRtRange failed check."; + + ++current_iterator; + continue; } - else + if(!checkDtRange(qualified_mass_spectrum_csp)) { - mass_spectrum_sum_y = - qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY(); - } + qDebug() << "checkDtRange failed check."; - if(!mass_spectrum_sum_y) - { ++current_iterator; continue; } - // Now handle the mobility data, either drift time or 1/K0 depending - // on the file type. + double mass_spectrum_sum_y = 0; + + // Handle the mobility data, either drift time or 1/K0 depending + // on the file type. Do that now because we'll need the dt value when + // performing the sumY calculation if a filtering with selection in + // polygon is required. double dt = -1; @@ -595,6 +335,65 @@ dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); } + // At this point we need to account for any limitations in the m/z + // dimension of the data. These limitations might be as easy as having + // a single m/z range limit or as complex as having one or more 2D + // steps involving the m/z dimension in the m_innermostSteps2D, if the + // selection polygons are not rectangle. + + if(!selection_polygon_specs.size()) + { + if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second)) + { + mass_spectrum_sum_y = + qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY( + m_mzRange.first, m_mzRange.second); + } + else + { + mass_spectrum_sum_y = + qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY(); + } + } + else + { + // It may be possible that the 2D steps limiting the m/z range + // have been followed by 1D steps further limiting the m/Z range. + // The point is, the 1D steps are not stored in + // selection_polygon_specs. However, by necessity, if there is at + // least one selection_polygon_spec, then the m_mzRange holds + // values. Futher, if there had been a 1D step limiting even more + // the m/z range, then that step would have been accounted for in + // m_mzRange. So we can account that limit right away. + + if(std::isnan(m_mzRange.first) || std::isnan(m_mzRange.second)) + qFatal("Programming error."); + + pappso::Trace filtered_trace( + *qualified_mass_spectrum_csp->getMassSpectrumSPtr()); + + pappso::FilterResampleKeepXRange the_keep_filter( + m_mzRange.first, m_mzRange.second); + + filtered_trace = the_keep_filter.filter(filtered_trace); + + pappso::FilterResampleKeepPointInPolygon the_polygon_filter( + selection_polygon_specs); + + filtered_trace = the_polygon_filter.filter( + filtered_trace, + dt, + qualified_mass_spectrum_csp->getRtInMinutes()); + + mass_spectrum_sum_y = filtered_trace.sumY(); + } + + if(!mass_spectrum_sum_y) + { + ++current_iterator; + continue; + } + // Try to insert the pair into the map. Check if that was done or // not. std::pair res = @@ -616,14 +415,12 @@ // Now we can go to the next mass spectrum. ++current_iterator; } - // End of - // while(current_iterator != end_iterator) + // End of + // while(current_iterator != end_iterator) -#if 0 - qDebug() << "At the end of the current iterator pair, current map:"; - for(auto &&pair : *current_dt_spec_map_sp) - qDebug().noquote() << "(" << pair.first << "," << pair.second << ")"; -#endif + // qDebug() << "At the end of the current iterator pair, current map:"; + // for(auto &&pair : *current_dt_spec_map_sp) + // qDebug().noquote() << "(" << pair.first << "," << pair.second << ")"; } // End of // #pragma omp parallel for ordered @@ -662,8 +459,7 @@ { emit setStatusTextSignal( - QString("Consolidating drift spectra from thread %1") - .arg(iter)); + QString("Consolidating drift spectra from thread %1").arg(iter)); emit setProgressBarCurrentValueSignal(iter); diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDt.hpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDt.hpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDt.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDt.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -87,7 +87,7 @@ public slots: - void integrateToDt(); + void integrate(); signals: protected: diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz.cpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz.cpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -34,6 +34,8 @@ /////////////////////// StdLib includes #include #include +#include + /////////////////////// OpenMP include #include @@ -48,7 +50,6 @@ /////////////////////// Local includes #include "QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz.hpp" -#include "ProcessingSpec.hpp" #include "ProcessingStep.hpp" #include "ProcessingType.hpp" @@ -170,19 +171,13 @@ void -QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz::integrate( - pappso::DataKind data_kind) +QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz::integrate() { - // qDebug() << "Data kind:" << static_cast(data_kind); + qDebug(); std::chrono::system_clock::time_point chrono_start_time = std::chrono::system_clock::now(); - // In this integration, we are going to craft the data to create a colormap - // that will plot mz data with either rt or dt data (depending on data_kind). - - m_lastIntegrationDataKind = data_kind; - // If there are no data, nothing to do. std::size_t mass_spectra_count = mcsp_qualifiedMassSpectraToIntegrateVector->size(); @@ -194,12 +189,37 @@ emit cancelOperationSignal(); } - // Nothing special to do about processing flow info because that must have - // been set before calling this function. + qDebug() << "The number of mass spectra to handle:" << mass_spectra_count; // We need to clear the map trace! m_mapTrace.clear(); + // In this integration, we are going to craft the data to create a colormap + // that will plot mz data against either rt or dt data. The way we know if we + // have to plot mz data against one or the other is by looking into the + // processing flow's processing type. + + if(!m_processingFlow.size()) + qFatal("The processing flow cannot be empty. Program aborted."); + + const ProcessingStep *last_processing_step = + m_processingFlow.mostRecentStep(); + + ProcessingType last_processing_type = + last_processing_step->getDestProcessingType(); + + // We need to know what kind of integration we deal with here, rt_mz or dt_mz + // because we have to store it so that after the computation is performed, the + // consumer of this integrator knows what integration was performed. It will + // have no other means to know what kind of integration we have performed. + + if(last_processing_type.bitMatches("DT_MZ")) + m_lastIntegrationDataKind = pappso::DataKind::dt; + else if(last_processing_type.bitMatches("MZ_RT")) + m_lastIntegrationDataKind = pappso::DataKind::rt; + else + qFatal("Programming error. The processing is not allowed here."); + // Choose the right message to emit and make sanity checks. if(m_lastIntegrationDataKind == pappso::DataKind::rt) { @@ -214,22 +234,44 @@ else qFatal("Programming error."); + // When constructing this integrator, the processing flow passed as parameter + // was used to gather innermost ranges data. When the steps that match + // the innermost criterion, these are stored in m_innermostSteps2D. When the + // steps are non-2D steps, then only the m_xxRange values are updated. + + // If the m_innermostSteps2D vector of ProcessingSteps is non-empty, then, + // that means that we may have some MZ-related 2D processing steps to account + // at combination time, because that is precisely the only moment that we can + // do that work. To be able to provide selection polygon an mass + // spectrum-specific dt|rt data, we have the SelectionPolygonSpec class. There + // can be as many such class instances as required to document the integration + // boundaries rt/mz and dt/mz for example. This is why we need to fill in the + // vector of SelectionPolygonSpec and then set that to the combiner. + + // Note, however, that the hassle described above only is acceptable when the + // selection polygon is not square. If the selection polygon is square, then + // the ranges suffice, and they have been filled-in properly upon construction + // of this integrator. + + qDebug() << "Now filling-in the selectionpolygonspecs."; + + std::vector selection_polygon_specs; + + std::size_t selection_polygon_spec_count = + fillInSelectionPolygonSpecs(selection_polygon_specs); + + qDebug() << selection_polygon_spec_count + << "selection polygon specs were retained for the configuration of " + "the filter."; + + // Prepare the template for all the combiners we'll use in the different + // threads. + + // Set the decimal places to 0 below, because we have a large + // binning for the color map with mz data, otherwize it would + // be huge. - // We need a processing flow to work, and, in particular, a processing step - // from which to find the specifics of the calculation. - - if(!m_processingFlow.size()) - qFatal("The processing flow cannot be empty. Program aborted."); - - // Get the most recent step that holds all the specifics of this integration. - const ProcessingStep *most_recent_processing_step_p = - m_processingFlow.mostRecentStep(); - - // There must be at least one ProcessingSpec (and thus type) in the - // processing step since we need to know what color map is being computed - // (either rt/mz or dt/mz). - if(!most_recent_processing_step_p->processingTypes().size()) - qFatal("The processing step must have at least one type. Program aborted."); + pappso::TracePlusCombiner plus_combiner(0); // Using a shared pointer make it easy to handle the copying of the map to // users of that map without bothering. @@ -284,6 +326,8 @@ // Now that we have all the parallel material, we can start the parallel work. emit setProgressBarMaxValueSignal(mass_spectra_count); + qDebug() << "Starting the iteration in the visitors."; + omp_set_num_threads(iterators.size()); #pragma omp parallel for ordered for(std::size_t iter = 0; iter < iterators.size(); ++iter) @@ -299,23 +343,6 @@ MapSPtr current_double_maptrace_map_sp = vector_of_double_maptrace_maps.at(iter); - // Set the decimal places to 0 below, because we have a large - // binning for the color map with mz data, otherwize it would - // be huge. - pappso::TracePlusCombiner combiner(0); - - // We need to inform the combiner if we have to limit the mz range - // for the combinations. - - // These values are set in the in the base class constuctor. - - if(m_mzRange.first != std::numeric_limits::max() && - m_mzRange.second != std::numeric_limits::min()) - { - combiner.setFilterResampleKeepXRange(pappso::FilterResampleKeepXRange( - m_mzRange.first, m_mzRange.second)); - } - while(current_iterator != end_iterator) { // We want to be able to intercept any cancellation of the @@ -339,6 +366,11 @@ qualified_mass_spectrum_csp = checkQualifiedMassSpectrum(qualified_mass_spectrum_csp); + if(qualified_mass_spectrum_csp == nullptr) + qFatal( + "Programming error. Not possible that shared pointer to " + "qualified mass spectrum be nullptr."); + // Great, at this point we actually have the mass spectrum! // We now need to ensure that the processing flow allows for this mass @@ -348,45 +380,32 @@ // that matches the greatest MS level found in the member processing // flow instance. - if(!checkMsLevel(qualified_mass_spectrum_csp) || - !checkRtRange(qualified_mass_spectrum_csp) || - !checkDtRange(qualified_mass_spectrum_csp)) + if(!checkMsLevel(qualified_mass_spectrum_csp)) { - // if(!checkMsLevel(qualified_mass_spectrum_csp)) - // qDebug() << "MS level did not check."; - - // if(!checkRtRange(qualified_mass_spectrum_csp)) - // qDebug() << "RT range did not check."; - - // if(!checkDtRange(qualified_mass_spectrum_csp)) - // qDebug() << "DT range did not check."; - - // qDebug() << "The checks returned false"; - + qDebug() << "The MsLevel check returned false"; + ++current_iterator; + continue; + } + if(!checkMsFragmentation(qualified_mass_spectrum_csp)) + { + qDebug() << "The MsFragmentation check returned false"; ++current_iterator; continue; } - // At this point we need to go deep in the processing flow's steps to - // check if the node matches the whole set of the steps' specs. - - // qDebug() << "The processing flow has" << m_processingFlow.size() << - // "steps."; - - // Boolean value needed because we need to break two loops. - bool should_increment_iterator_and_continue = false; + // Make easy check about RT and DT. - for(auto &&step : m_processingFlow) + if(!checkRtRange(qualified_mass_spectrum_csp)) { - if(!checkProcessingStep(*step, qualified_mass_spectrum_csp)) - { - should_increment_iterator_and_continue = true; - break; - } - } + qDebug() << "checkRtRange failed check."; - if(should_increment_iterator_and_continue) + ++current_iterator; + continue; + } + if(!checkDtRange(qualified_mass_spectrum_csp)) { + qDebug() << "checkDtRange failed check."; + ++current_iterator; continue; } @@ -394,15 +413,18 @@ // Great, at this point we actually have the mass spectrum and we need // to get the dt|rt value for it. + double rt_value = qualified_mass_spectrum_csp->getRtInMinutes(); + double dt_value = qualified_mass_spectrum_csp->getDtInMilliSeconds(); + double first_key; // that is, either rt or dt. - if(data_kind == pappso::DataKind::rt) + if(m_lastIntegrationDataKind == pappso::DataKind::rt) { - first_key = qualified_mass_spectrum_csp->getRtInMinutes(); + first_key = rt_value; } - else if(data_kind == pappso::DataKind::dt) + else if(m_lastIntegrationDataKind == pappso::DataKind::dt) { - first_key = qualified_mass_spectrum_csp->getDtInMilliSeconds(); + first_key = dt_value; } else qFatal("Programming error."); @@ -415,6 +437,42 @@ double_maptrace_map_iterator = current_double_maptrace_map_sp->find(first_key); + // Before combining, we need to check if some filtering is + // required as for m/z data. + + pappso::Trace filtered_trace( + *qualified_mass_spectrum_csp->getMassSpectrumSPtr()); + + // It may be possible that the 2D steps limiting the m/z range + // have been followed by 1D steps further limiting the m/z range. + // The point is, the 1D steps are not stored in + // selection_polygon_specs. However, by necessity, if there is at + // least one selection_polygon_spec, then the m_mzRange holds + // values. Futher, if there had been a 1D step limiting even more + // the m/z range, then that step would have been accounted for in + // m_mzRange. So we can account that limit right away. + + if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second)) + { + pappso::FilterResampleKeepXRange the_keep_filter( + m_mzRange.first, m_mzRange.second); + + filtered_trace = the_keep_filter.filter(filtered_trace); + } + + if(selection_polygon_specs.size()) + { + pappso::FilterResampleKeepPointInPolygon the_polygon_filter( + selection_polygon_specs); + + filtered_trace = the_polygon_filter.filter( + filtered_trace, + qualified_mass_spectrum_csp->getDtInMilliSeconds(), + qualified_mass_spectrum_csp->getRtInMinutes()); + } + + // At this point we can make the combination with the filtered trace. + // Tells if the key was already found in the map. if(double_maptrace_map_iterator != current_double_maptrace_map_sp->end()) @@ -430,9 +488,8 @@ // qDebug() << "Before combination, map trace map size: " //<< double_map_trace_map_iterator->second.size(); - combiner.combine( - double_maptrace_map_iterator->second, - *(qualified_mass_spectrum_csp->getMassSpectrumCstSPtr())); + plus_combiner.combine(double_maptrace_map_iterator->second, + filtered_trace); } else { @@ -450,9 +507,7 @@ pappso::MapTrace map_trace; - combiner.combine( - map_trace, - *(qualified_mass_spectrum_csp->getMassSpectrumCstSPtr())); + plus_combiner.combine(map_trace, filtered_trace); // Finally, store in the map, the map_trace along with its // first_key. @@ -495,6 +550,9 @@ m_isOperationCancelled = false; int iter = 0; + // This time we do not need to configure the combiner with m/z dimension + // related limitations because these have been enforced during the first + // combination round above. pappso::TracePlusCombiner combiner(0); for(auto &&map_sp : vector_of_double_maptrace_maps) @@ -540,11 +598,15 @@ // Combine the new mass spectrum right into the found MapTrace. - // qDebug() << "Before combination, map trace map size: " - //<< double_map_trace_map_iterator->second.size(); + //std::size_t before_size = current_maptrace.size(); combiner.combine(double_maptrace_map_iterator->second, current_maptrace); + + //std::size_t after_size = current_maptrace.size(); + + //qDebug() << "Before combination, map trace map size: " + //<< before_size << "after combination:" << after_size; } else { @@ -562,8 +624,15 @@ pappso::MapTrace map_trace; + //std::size_t before_size = map_trace.size(); + combiner.combine(map_trace, current_maptrace); + //std::size_t after_size = map_trace.size(); + + //qDebug() << "Before combination, map trace map size: " + //<< before_size << "after combination:" << after_size; + // Finally, store in the map, the map_trace along with its // first_key. @@ -612,12 +681,12 @@ QString chrono_string; - if(data_kind == pappso::DataKind::rt) + if(m_lastIntegrationDataKind == pappso::DataKind::rt) chrono_string = pappso::Utils::chronoIntervalDebugString( "Integration to RT / MZ colormap took:", chrono_start_time, chrono_end_time); - else if(data_kind == pappso::DataKind::dt) + else if(m_lastIntegrationDataKind == pappso::DataKind::dt) chrono_string = pappso::Utils::chronoIntervalDebugString( "Integration to DT / MZ colormap took:", chrono_start_time, diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz.hpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz.hpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToDtRtMz.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -99,7 +99,7 @@ public slots: - void integrate(pappso::DataKind data_kind); + void integrate(); signals: diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToMz.cpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToMz.cpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToMz.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToMz.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -33,6 +33,8 @@ /////////////////////// StdLib includes #include +#include + /////////////////////// OPENMP include #include @@ -40,6 +42,7 @@ /////////////////////// Qt includes #include #include +#include /////////////////////// pappsomspp includes @@ -49,6 +52,7 @@ /////////////////////// Local includes #include "QualifiedMassSpectrumVectorMassDataIntegrator.hpp" #include "QualifiedMassSpectrumVectorMassDataIntegratorToMz.hpp" +#include "ProcessingStep.hpp" int qualifiedMassSpectrumVectorMassDataIntegratorToMzMetaTypeId = @@ -105,20 +109,11 @@ void -QualifiedMassSpectrumVectorMassDataIntegratorToMz::integrateToMz() +QualifiedMassSpectrumVectorMassDataIntegratorToMz::integrate() { - // qDebug(); - std::chrono::system_clock::time_point chrono_start_time = std::chrono::system_clock::now(); - if(!mcsp_qualifiedMassSpectraToIntegrateVector->size()) - { - qDebug() << "The qualified mass spectrum vector is empty, nothing to do."; - - emit cancelOperationSignal(); - } - // Nothing special to do about processing flow info because that must have // been set before calling this function. @@ -153,9 +148,23 @@ bool QualifiedMassSpectrumVectorMassDataIntegratorToMz::integrateToMzNoBinning() { - // qDebug(); + qDebug(); + + // If there are no data, nothing to do. + std::size_t mass_spectra_count = + mcsp_qualifiedMassSpectraToIntegrateVector->size(); + + if(!mass_spectra_count) + { + qDebug() << "The qualified mass spectrum vector is empty, nothing to do."; + + emit cancelOperationSignal(); + } - emit setTaskDescriptionTextSignal("Integrating to a mass spectrum"); + qDebug() << "The number of mass spectra to handle:" << mass_spectra_count; + + emit setTaskDescriptionTextSignal( + "Integrating to a mass spectrum (no binning)"); // We need a processing flow to work, and, in particular, a processing step // from which to find the specifics of the calculation. @@ -163,24 +172,78 @@ if(!m_processingFlow.size()) qFatal("The processing flow cannot be empty. Program aborted."); - // qDebug().noquote() << "The processing flow has" << m_processingFlow.size() - //<< "steps and is:" << m_processingFlow.toString(); + // When constructing this integrator, the processing flow passed as parameter + // was used to gather innermost ranges data. When the steps that match + // the innermost criterion, these are stored in m_innermostSteps2D. When the + // steps are non-2D steps, then only the m_xxRange values are updated. + + // If the m_innermostSteps2D vector of ProcessingSteps is non-empty, then, + // that means that we may have some MZ-related 2D processing steps to account + // at combination time, because that is precisely the only moment that we can + // do that work. To be able to provide selection polygon an mass + // spectrum-specific dt|rt data, we have the SelectionPolygonSpec class. There + // can be as many such class instances as required to document the integration + // boundaries rt/mz and dt/mz for example. This is why we need to fill in the + // vector of SelectionPolygonSpec and then set that to the combiner. + + // If the m_innermostSteps2D vector of ProcessingSteps is non-empty, then, + // that means that we may have some MZ-related 2D processing steps to account + // at combination time, because that is precisely the only moment that we can + // do that work. + + qDebug() << "Now filling-in the selectionpolygonspecs."; + + std::vector selection_polygon_specs; + + std::size_t selection_polygon_spec_count = + fillInSelectionPolygonSpecs(selection_polygon_specs); + + qDebug() << selection_polygon_spec_count + << "selection polygon specs were retained for the configuration of " + "the filter."; + + // Prepare the template for all the combiners we'll use in the different + // threads. - // Get the most recent step that holds all the specifics of this integration. - const ProcessingStep *most_recent_processing_step_p = - m_processingFlow.mostRecentStep(); + pappso::MzIntegrationParams mz_integration_params = + m_processingFlow.getDefaultMzIntegrationParams(); - // There must be at least one ProcessingSpec (and thus a type) in the - // processing step. + pappso::TracePlusCombiner template_plus_combiner( + mz_integration_params.getDecimalPlaces()); - if(!most_recent_processing_step_p->processingTypes().size()) - qFatal("The processing step cannot be empty. Program aborted."); + // Now we need to check a number of things: + // + // 1. If there are no selection polygon specs, then all we need to check is if + // there is some m/z range limitation. If so, create the right filter. + // + // 2. If there is at least one selection polygon spec, then create the right + // filter. + + // if(!selection_polygon_specs.size()) + //{ + // if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second)) + //{ + // pappso::FilterInterfaceCstSPtr filter_csp = + // std::make_shared( + // m_mzRange.first, m_mzRange.second); + + // qDebug() << "Adding pappso::FilterResampleKeepXRange."; + + // template_plus_combiner.addFilter(filter_csp); + //} + //} + // else + //{ + // pappso::FilterInterfaceCstSPtr filter_csp = + // std::make_shared( + // pappso::FilterResampleKeepPointInPolygon(selection_polygon_specs)); - // We are integrating to m/z so we need a spec description that matches - // "ANY_TO_MZ". + // qDebug() << "Adding pappso::FilterResampleKeepPointInPolygon."; - if(!most_recent_processing_step_p->matches("ANY_TO_MZ")) - qFatal("There should be one ProcessingType = ANY_TO_MZ. Program aborted."); + // template_plus_combiner.addFilter(filter_csp); + //} + + qDebug(); // At this point, allocate a visitor that is specific for the calculation of // the mass spectrum. Since we are not binning, we can use a visitor that @@ -196,8 +259,7 @@ // In the pair below, first is the ideal number of threads and second is the // number of mass spectra per thread. std::pair best_parallel_params = - bestParallelIntegrationParams( - mcsp_qualifiedMassSpectraToIntegrateVector->size()); + bestParallelIntegrationParams(mass_spectra_count); // Handy alias. using MassSpecVector = std::vector; @@ -218,8 +280,9 @@ vector_of_map_trace.push_back(std::make_shared()); // Now that we have all the parallel material, we can start the parallel work. - emit setProgressBarMaxValueSignal( - mcsp_qualifiedMassSpectraToIntegrateVector->size()); + emit setProgressBarMaxValueSignal(mass_spectra_count); + + qDebug() << "Starting the iteration in the visitors."; omp_set_num_threads(iterators.size()); #pragma omp parallel for ordered @@ -235,34 +298,24 @@ pappso::MapTraceSPtr current_map_trace_sp = vector_of_map_trace.at(iter); + // std::size_t qualified_mass_spectrum_count = + // std::distance(current_iterator, end_iterator); + + // qDebug() << "For thread index:" << iter + //<< "the number of mass spectra to process:" + //<< qualified_mass_spectrum_count; + // Allocate the combiner because we'll need it for the checking of the // steps (will set eventual processing to the Trace if there are // start-end ranges for the mz values, for example with // setFilterResampleKeepXRange. - pappso::TracePlusCombiner trace_plus_combiner; - - trace_plus_combiner.setDecimalPlaces( - m_processingFlow.getDefaultMzIntegrationParams().getDecimalPlaces()); - - // We need to inform the combiner if we have to limit the mz range - // for the combinations. - - // These values are set in the in the base class constuctor. - - if(m_mzRange.first != std::numeric_limits::max() && - m_mzRange.second != std::numeric_limits::min()) - { - //qDebug() << "The m_mzRange.first:" << m_mzRange.first - //<< "and m_mzRange.second:" << m_mzRange.second; - - trace_plus_combiner.setFilterResampleKeepXRange( - pappso::FilterResampleKeepXRange(m_mzRange.first, - m_mzRange.second)); - } - //else - //qDebug() << "There is no limitation on the m/z range."; + pappso::TracePlusCombiner trace_plus_combiner(template_plus_combiner); + // Now process each qualified mass spectrum in the iterator range. + // Remember the begin and end iterators point to a range of mass + // spectra in the mass spectra vector that holds *all* the mass + // spectra to be processed. while(current_iterator != end_iterator) { // We want to be able to intercept any cancellation of the @@ -282,6 +335,11 @@ qualified_mass_spectrum_csp = checkQualifiedMassSpectrum(qualified_mass_spectrum_csp); + if(qualified_mass_spectrum_csp == nullptr) + qFatal( + "Programming error. Not possible that shared pointer to " + "qualified mass spectrum be nullptr."); + // Great, at this point we actually have the mass spectrum! // We now need to ensure that the processing flow allows for this mass @@ -291,74 +349,80 @@ // that matches the greatest MS level found in the member processing // flow instance. - bool check_failed = false; - if(!checkMsLevel(qualified_mass_spectrum_csp)) { - // qDebug() << "The MsLevel check returned false"; - check_failed = true; + qDebug() << "The MsLevel check returned false"; + ++current_iterator; + continue; } if(!checkMsFragmentation(qualified_mass_spectrum_csp)) { - // qDebug() << "The MsFragmentation check returned false"; - check_failed = true; + qDebug() << "The MsFragmentation check returned false"; + ++current_iterator; + continue; } + + // Make easy check about RT and DT. + if(!checkRtRange(qualified_mass_spectrum_csp)) { - // qDebug() << "The RtRange check returned false"; - check_failed = true; + qDebug() << "checkRtRange failed check."; + + ++current_iterator; + continue; } if(!checkDtRange(qualified_mass_spectrum_csp)) { - // qDebug() << "The DtRange check returned false"; - check_failed = true; - } - - if(check_failed) - { - // qDebug() << "The checks returned false"; + qDebug() << "checkDtRange failed check."; ++current_iterator; continue; } -#if 0 + pappso::Trace filtered_trace( + *qualified_mass_spectrum_csp->getMassSpectrumSPtr()); - // This code is no more necessary because we handle all checks above - // and both are equipotent unless the code above is much quicker - // because it avoids cycling too much into the various steps/specs by - // looking at innermost Dt|Mz|Rt ranges. - - // At this point we need to go deep in the processing flow's steps to - // check if the node matches the whole set of the steps' specs. - - // qDebug() << "The processing flow has" << m_processingFlow.size() << - // "steps."; - - // Boolean value needed because we need to break two loops. - bool should_increment_iterator_and_continue = false; - - for(auto &&step : m_processingFlow) - { - if(!checkProcessingStep(*step, - qualified_mass_spectrum_csp, - mass_spectrum_plus_combiner)) - { - should_increment_iterator_and_continue = true; - break; - } + // It may be possible that the 2D steps limiting the m/z range + // have been followed by 1D steps further limiting the m/Z range. + // The point is, the 1D steps are not stored in + // selection_polygon_specs. However, by necessity, if there is at + // least one selection_polygon_spec, then the m_mzRange holds + // values. Futher, if there had been a 1D step limiting even more + // the m/z range, then that step would have been accounted for in + // m_mzRange. So we can account that limit right away. + + if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second)) + { + pappso::FilterResampleKeepXRange the_keep_filter( + m_mzRange.first, m_mzRange.second); + + filtered_trace = the_keep_filter.filter(filtered_trace); } - if(should_increment_iterator_and_continue) + if(selection_polygon_specs.size()) { - ++current_iterator; - continue; + pappso::FilterResampleKeepPointInPolygon the_polygon_filter( + selection_polygon_specs); + + filtered_trace = the_polygon_filter.filter( + filtered_trace, + qualified_mass_spectrum_csp->getDtInMilliSeconds(), + qualified_mass_spectrum_csp->getRtInMinutes()); } -#endif - trace_plus_combiner.combine( - *current_map_trace_sp, - *qualified_mass_spectrum_csp->getMassSpectrumCstSPtr()); + // No need to configure the combiner here, because we already have + // done that above. + + // qDebug() << "Going to combine a new qualified mass spectrum."; + + std::size_t before_size = current_map_trace_sp->size(); + + trace_plus_combiner.combine(*current_map_trace_sp, filtered_trace); + + std::size_t after_size = current_map_trace_sp->size(); + + qDebug() << "Before combination, map trace map size: " << before_size + << "after combination:" << after_size; // qDebug() << "Processed one more spectrum."; @@ -442,25 +506,41 @@ QualifiedMassSpectrumVectorMassDataIntegratorToMz:: integrateToMzArbitraryBinning() { - // qDebug(); + qDebug(); + + // If there are no data, nothing to do. + std::size_t mass_spectra_count = + mcsp_qualifiedMassSpectraToIntegrateVector->size(); + + if(!mass_spectra_count) + { + qDebug() << "The qualified mass spectrum vector is empty, nothing to do."; + + emit cancelOperationSignal(); + } + + qDebug() << "The number of mass spectra to handle:" << mass_spectra_count; + + emit setTaskDescriptionTextSignal("Integrating to a mass spectrum (binning)"); // This function needs to be called by integrateToMz() that has setup all the // required parameters. - emit setTaskDescriptionTextSignal("Integrating to a mass spectrum"); - // We need a processing flow to work, and, in particular, a processing step // from which to find the specifics of the calculation. if(!m_processingFlow.size()) qFatal("The processing flow cannot be empty. Program aborted."); + // In this case where binning is requested, we need to craft the bins, and for + // that we need proper mz integration params. + pappso::MzIntegrationParams local_mz_integration_params = m_processingFlow.getDefaultMzIntegrationParams(); if(!local_mz_integration_params.isValid()) { - qDebug() << "The mz integration paramas are not valid."; + qDebug() << "The mz integration params are not valid."; // If the mz integration params are not valid, then we cannot know the // start and end of the bins ! We need to resort to the statistical data @@ -479,28 +559,98 @@ // Now we can create the bins! std::vector bins = local_mz_integration_params.createBins(); - // qDebug() << "Created bins at:" - //<< QDateTime::currentDateTime().toString("yyyyMMdd-HH-mm-ss"); + QString bins_before = "Bins:\n"; + for(auto &&bin : bins) + bins_before += QString("%1\n").arg(bin, 0, 'f', 6); - // At this point, allocate a visitor that is specific for the calculation of - // the mass spectrum. Since we are not binning, we can use a visitor that - // integrates to a pappso::Trace, not a pappso::MassSpectrum. + // qDebug() << "Created bins at:" + //<< QDateTime::currentDateTime().toString("yyyyMMdd-HH-mm-ss"); - // But we want to parallelize the computation. Se we will allocate a vector of - // visitors (as many as possible for the available processor threads), each - // visitor having a subset of the initial data to integrate. - emit setProgressBarMaxValueSignal( - mcsp_qualifiedMassSpectraToIntegrateVector->size()); +#if 0 + QString fileName = "/tmp/massSpecArbitraryBins.txt-at-" + + QDateTime::currentDateTime().toString("yyyyMMdd-HH-mm-ss"); - // Determine the best number of threads to use and how many spectra to provide - // each of the threads. + qDebug() << "Writing the list of bins setup in the " + "mass spectrum in file " + << fileName; - // In the pair below, first is the ideal number of threads and second is the - // number of mass spectra per thread. + QFile file(fileName); + file.open(QIODevice::WriteOnly); + + QTextStream fileStream(&file); + + for(auto &&bin : bins) + fileStream << QString("%1\n").arg(bin, 0, 'f', 10); + + fileStream.flush(); + file.close(); +#endif + + + // When constructing this integrator, the processing flow passed as parameter + // was used to gather innermost ranges data. When the steps that match + // the innermost criterion, these are stored in m_innermostSteps2D. When the + // steps are non-2D steps, then only the m_xxRange values are updated. + + // If the m_innermostSteps2D vector of ProcessingSteps is non-empty, then, + // that means that we may have some MZ-related 2D processing steps to account + // at combination time, because that is precisely the only moment that we can + // do that work. To be able to provide selection polygon an mass + // spectrum-specific dt|rt data, we have the SelectionPolygonSpec class. There + // can be as many such class instances as required to document the integration + // boundaries rt/mz and dt/mz for example. This is why we need to fill in the + // vector of SelectionPolygonSpec and then set that to the combiner. + + // If the m_innermostSteps2D vector of ProcessingSteps is non-empty, then, + // that means that we may have some MZ-related 2D processing steps to account + // at combination time, because that is precisely the only moment that we can + // do that work. + + qDebug() << "Now filling-in the selectionpolygonspecs."; + + std::vector selection_polygon_specs; + + std::size_t selection_polygon_spec_count = + fillInSelectionPolygonSpecs(selection_polygon_specs); + + qDebug() << selection_polygon_spec_count + << "selection polygon specs were retained for the configuration of " + "the filter."; + + // Prepare the template for all the combiners we'll use in the different + // threads. + + pappso::MassSpectrumPlusCombiner template_plus_combiner( + local_mz_integration_params.getDecimalPlaces()); + + template_plus_combiner.setBins(bins); + + QString bins_after = "Bins:\n"; + for(auto &&bin : template_plus_combiner.getBins()) + bins_after += QString("%1\n").arg(bin, 0, 'f', 6); + + if(bins_before == bins_after) + qDebug() << "The copying of the bins in the template combiner worked."; + else + qFatal("Programming error."); + + // At this point, allocate a visitor that is specific for the calculation + // of the mass spectrum. Since we are not binning, we can use a visitor + // that integrates to a pappso::Trace, not a pappso::MassSpectrum. + + // But we want to parallelize the computation. Se we will allocate a + // vector of visitors (as many as possible for the available processor + // threads), each visitor having a subset of the initial data to + // integrate. + + // Determine the best number of threads to use and how many spectra to + // provide each of the threads. + + // In the pair below, first is the ideal number of threads and second is + // the number of mass spectra per thread. std::pair best_parallel_params = - bestParallelIntegrationParams( - mcsp_qualifiedMassSpectraToIntegrateVector->size()); + bestParallelIntegrationParams(mass_spectra_count); using MassSpecVector = std::vector; using VectorIterator = MassSpecVector::const_iterator; @@ -511,18 +661,20 @@ calculateIteratorPairs(best_parallel_params.first, best_parallel_params.second); - // Set aside a vector pappso::MapTrace shared pointers that will be getting - // the result of the integrations. There will be one such instance per thread - // executing. + // Set aside a vector pappso::MapTrace shared pointers that will be + // getting the result of the integrations. There will be one such instance + // per thread executing. std::vector vector_of_map_trace; for(std::size_t iter = 0; iter < iterators.size(); ++iter) vector_of_map_trace.push_back(std::make_shared()); - omp_set_num_threads(iterators.size()); + // Now that we have all the parallel material, we can start the parallel work. + emit setProgressBarMaxValueSignal(mass_spectra_count); - // qDebug() << "Will use" << iterators.size() << "threads"; + qDebug() << "Starting the iteration in the visitors."; + omp_set_num_threads(iterators.size()); #pragma omp parallel for ordered for(std::size_t iter = 0; iter < iterators.size(); ++iter) { @@ -530,9 +682,7 @@ // Get the iterator range that we need to deal in this thread. VectorIterator current_iterator = iterators.at(iter).first; - // For debugging purposes - // VectorIterator end_iterator = std::prev(iterators.at(iter).second); - VectorIterator end_iterator = iterators.at(iter).second; + VectorIterator end_iterator = iterators.at(iter).second; // Get the map for this thread. @@ -551,35 +701,12 @@ // setFilterResampleKeepXRange. pappso::MassSpectrumPlusCombiner mass_spectrum_plus_combiner( - local_mz_integration_params.getDecimalPlaces()); - - // We need to inform the combiner if we have to limit the mz range - // for the combinations. - - // These values are set in the in the base class constuctor. - - if(m_mzRange.first != std::numeric_limits::max() && - m_mzRange.second != std::numeric_limits::min()) - { - - // qDebug() << "The m_mzRange.first:" << m_mzRange.first - //<< "and m_mzRange.second:" << m_mzRange.second; - - mass_spectrum_plus_combiner.setFilterResampleKeepXRange( - pappso::FilterResampleKeepXRange(m_mzRange.first, - m_mzRange.second)); - } - // else - // qDebug() << "There is no limitation on the m/z range."; - - // Configure the binning mass spectrum combiner. - - mass_spectrum_plus_combiner.setBins(bins); + template_plus_combiner); // Now process each qualified mass spectrum in the iterator range. - // Remember the begin and end iterators point to a range of mass spectra - // in the mass spectra vector that holds *all* the mass spectra to be - // processed. + // Remember the begin and end iterators point to a range of mass + // spectra in the mass spectra vector that holds *all* the mass + // spectra to be processed. while(current_iterator != end_iterator) { // We want to be able to intercept any cancellation of the @@ -593,101 +720,107 @@ pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = *current_iterator; - if(qualified_mass_spectrum_csp == nullptr) - { - qFatal("The qualified_mass_spectrum_csp cannot be nullptr"); - } - // else - // qDebug() << "Current mass spectrum is valid with rt:" - //<< qualified_mass_spectrum_csp->getRtInMinutes(); - // Ensure that the qualified mass spectrum contains a mass spectrum - // that effectively contains the binary (mz,i) data. In particular, if - // that mass spectrum is not there, that might be because the data are - // not loaded in memory but need to be read from the file. + // that effectively contains the binary (mz,i) data. qualified_mass_spectrum_csp = checkQualifiedMassSpectrum(qualified_mass_spectrum_csp); - // Great, at this point we actually have the mass spectrum! + if(qualified_mass_spectrum_csp == nullptr) + qFatal( + "Programming error. Not possible that shared pointer to " + "qualified mass spectrum be nullptr."); - // We now need to ensure that the processing flow allows for this mass - // spectrum to be combined. + // Great, at this point we actually have the mass spectrum! - // Immediately check if the qualified mass spectrum is of a MS level - // that matches the greatest MS level found in the member processing - // flow instance. + // We now need to ensure that the processing flow allows for this + // mass spectrum to be combined. - bool check_failed = false; + // Immediately check if the qualified mass spectrum is of a MS + // level that matches the greatest MS level found in the member + // processing flow instance. if(!checkMsLevel(qualified_mass_spectrum_csp)) { - // qDebug() << "The MsLevel check returned false"; - check_failed = true; + //qDebug() << "The MsLevel check returned false"; + ++current_iterator; + continue; } if(!checkMsFragmentation(qualified_mass_spectrum_csp)) { - // qDebug() << "The MsFragmentation check returned false"; - check_failed = true; + //qDebug() << "The MsFragmentation check returned false"; + ++current_iterator; + continue; } + + // Make easy check about RT and DT. + if(!checkRtRange(qualified_mass_spectrum_csp)) { - // qDebug() << "The RtRange check returned false"; - check_failed = true; + //qDebug() << "checkRtRange failed check."; + ++current_iterator; + continue; } if(!checkDtRange(qualified_mass_spectrum_csp)) { - // qDebug() << "The DtRange check returned false"; - check_failed = true; + //qDebug() << "checkDtRange failed check."; + ++current_iterator; + continue; } - if(check_failed) + pappso::Trace filtered_trace; + + // It may be possible that the 2D steps limiting the m/z range + // have been followed by 1D steps further limiting the m/Z range. + // The point is, the 1D steps are not stored in + // selection_polygon_specs. However, by necessity, if there is at + // least one selection_polygon_spec, then the m_mzRange holds + // values. Futher, if there had been a 1D step limiting even more + // the m/z range, then that step would have been accounted for in + // m_mzRange. So we can account that limit right away. + + if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second)) { - // qDebug() << "The checks returned false"; + filtered_trace.initialize( + *qualified_mass_spectrum_csp->getMassSpectrumSPtr()); - ++current_iterator; - continue; + pappso::FilterResampleKeepXRange the_keep_filter( + m_mzRange.first, m_mzRange.second); + + filtered_trace = the_keep_filter.filter(filtered_trace); } -#if 0 + if(selection_polygon_specs.size()) + { + pappso::FilterResampleKeepPointInPolygon the_polygon_filter( + selection_polygon_specs); - // This code is no more necessary because we handle all checks above - // and both are equipotent unless the code above is much quicker - // because it avoids cycling too much into the various steps/specs by - // looking at innermost Dt|Mz|Rt ranges. - - // At this point we need to go deep in the processing flow's steps to - // check if the node matches the whole set of the steps' specs. - - // qDebug() << "The processing flow has" << m_processingFlow.size() << - // "steps."; - - // Boolean value needed because we need to break two loops. - bool should_increment_iterator_and_continue = false; - - for(auto &&step : m_processingFlow) - { - if(!checkProcessingStep(*step, - qualified_mass_spectrum_csp, - mass_spectrum_plus_combiner)) + if(!filtered_trace.size()) { - should_increment_iterator_and_continue = true; - break; + filtered_trace.initialize( + *qualified_mass_spectrum_csp->getMassSpectrumSPtr()); } - } - if(should_increment_iterator_and_continue) - { - ++current_iterator; - continue; - } -#endif + filtered_trace = the_polygon_filter.filter( + filtered_trace, + qualified_mass_spectrum_csp->getDtInMilliSeconds(), + qualified_mass_spectrum_csp->getRtInMinutes()); + } + + // No need to configure the combiner here, because we already have + // done that above. + + // qDebug() << "Going to combine a new qualified mass spectrum."; + + if(filtered_trace.size()) + mass_spectrum_plus_combiner.combine(*current_map_trace_sp, + filtered_trace); + else + mass_spectrum_plus_combiner.combine( + *current_map_trace_sp, + *qualified_mass_spectrum_csp->getMassSpectrumSPtr()); - mass_spectrum_plus_combiner.combine( - *current_map_trace_sp, - *qualified_mass_spectrum_csp->getMassSpectrumCstSPtr()); - - // qDebug() << "Processed one more spectrum:" + // qDebug() << "Processed one more qualified mass spectrum:" //<< qualified_mass_spectrum_csp->getMassSpectrumSPtr().get() //<< "with size:" << qualified_mass_spectrum_csp->size(); @@ -719,11 +852,12 @@ emit unlockTaskMonitorCompositeWidgetSignal(); emit setupProgressBarSignal(0, vector_of_map_trace.size() - 1); - // We might be here because the user cancelled the operation in the for loop - // above (visiting all the visitors). In this case m_isOperationCancelled is - // true. We want to set it back to false, so that the following loop is gone - // through. The user can ask that the operation be cancelled once more. But - // we want that at least the performed work be used to show the trace. + // We might be here because the user cancelled the operation in the for + // loop above (visiting all the visitors). In this case + // m_isOperationCancelled is true. We want to set it back to false, so + // that the following loop is gone through. The user can ask that the + // operation be cancelled once more. But we want that at least the + // performed work be used to show the trace. pappso::MassSpectrumPlusCombiner mass_spectrum_plus_combiner( local_mz_integration_params.getDecimalPlaces()); @@ -733,7 +867,8 @@ m_isOperationCancelled = false; int iter = 0; - // qDebug() << "The vector of map traces has:" << vector_of_map_trace.size() + // qDebug() << "The vector of map traces has:" << + // vector_of_map_trace.size() //<< "items."; for(auto &¤t_map_trace_sp : vector_of_map_trace) @@ -748,17 +883,17 @@ emit setStatusTextSignal(message); - //qDebug() << message; + // qDebug() << message; mass_spectrum_plus_combiner.combine(m_mapTrace, *current_map_trace_sp); emit setProgressBarCurrentValueSignal(iter); - //qDebug() << "Emitted current value:" << iter; + // qDebug() << "Emitted current value:" << iter; } // Write the data to file so that we can check. It works !!! - // pappso::Utils::appendToFile(m_mapTrace.toString(), "/tmp/prova.txt"); + pappso::Utils::appendToFile(m_mapTrace.toString(), "/tmp/prova.txt"); // At this point, we have really combined all the traces into a single map // trace! diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToMz.hpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToMz.hpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToMz.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToMz.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -87,7 +87,7 @@ public slots: - void integrateToMz(); + void integrate(); signals: protected: diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRt.cpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRt.cpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRt.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRt.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -33,6 +33,8 @@ /////////////////////// StdLib includes #include +#include + /////////////////////// OPENMP include #include @@ -48,6 +50,7 @@ /////////////////////// Local includes #include "QualifiedMassSpectrumVectorMassDataIntegratorToRt.hpp" +#include "../nongui/ProcessingStep.hpp" int qualifiedMassSpectrumVectorMassDataIntegratorToRtMetaTypeId = @@ -104,7 +107,7 @@ void -QualifiedMassSpectrumVectorMassDataIntegratorToRt::integrateToRt() +QualifiedMassSpectrumVectorMassDataIntegratorToRt::integrate() { qDebug(); @@ -138,20 +141,36 @@ if(!m_processingFlow.size()) qFatal("The processing flow cannot be empty. Program aborted."); - // Get the most recent step that holds all the specifics of this integration. - const ProcessingStep *most_recent_processing_step_p = - m_processingFlow.mostRecentStep(); - - // There must be at least one ProcessingSpec (and thus a type) in the - // processing step. - if(!most_recent_processing_step_p->processingTypes().size()) - qFatal("The processing step cannot be empty. Program aborted."); - - // We are integrating to rt so we need a spec description that matches - // "ANY_TO_RT". - - if(!most_recent_processing_step_p->matches("ANY_TO_RT")) - qFatal("There should be one ProcessingType = ANY_TO_RT. Program aborted."); + // When constructing this integrator, the processing flow passed as parameter + // was used to gather innermost ranges data. When the steps that match + // the innermost criterion, these are stored in m_innermostSteps2D. When the + // steps are non-2D steps, then only the m_xxRange values are updated. + + // If the m_innermostSteps2D vector of ProcessingSteps is non-empty, then, + // that means that we may have some MZ-related 2D processing steps to account + // at combination time, because that is precisely the only moment that we can + // do that work. To be able to provide selection polygon an mass + // spectrum-specific dt|rt data, we have the SelectionPolygonSpec class. There + // can be as many such class instances as required to document the integration + // boundaries rt/mz and dt/mz for example. This is why we need to fill in the + // vector of SelectionPolygonSpec and then set that to the combiner. + + // Note, however, that the hassle described above only is acceptable when the + // selection polygon is not square. If the selection polygon is square, then + // the ranges suffice, and they have been filled-in properly upon construction + // of this integrator. + + qDebug() << "Now filling-in the selection_polygon_specs for any 2D step that " + "has a source type involving the MZ data kind."; + + std::vector selection_polygon_specs; + + std::size_t selection_polygon_spec_count = + fillInSelectionPolygonSpecs(selection_polygon_specs); + + qDebug() << selection_polygon_spec_count + << "selection polygon specs were retained for the configuration of " + "the filter."; // Determine the best number of threads to use and how many spectra to provide // each of the threads. @@ -159,8 +178,7 @@ // In the pair below, first is the ideal number of threads and second is the // number of mass spectra per thread. std::pair best_parallel_params = - bestParallelIntegrationParams( - mcsp_qualifiedMassSpectraToIntegrateVector->size()); + bestParallelIntegrationParams(mass_spectra_count); // Handy alias. using MassSpecVector = std::vector; @@ -188,6 +206,8 @@ // Now that we have all the parallel material, we can start the parallel work. emit setProgressBarMaxValueSignal(mass_spectra_count); + qDebug() << "Starting the iteration in the visitors."; + omp_set_num_threads(iterators.size()); #pragma omp parallel for ordered for(std::size_t iter = 0; iter < iterators.size(); ++iter) @@ -225,6 +245,11 @@ qualified_mass_spectrum_csp = checkQualifiedMassSpectrum(qualified_mass_spectrum_csp); + if(qualified_mass_spectrum_csp == nullptr) + qFatal( + "Programming error. Not possible that shared pointer to " + "qualified mass spectrum be nullptr."); + // Great, at this point we actually have the mass spectrum! // We now need to ensure that the processing flow allows for this mass @@ -234,64 +259,92 @@ // that matches the greatest MS level found in the member processing // flow instance. - if(!checkMsLevel(qualified_mass_spectrum_csp) || - !checkRtRange(qualified_mass_spectrum_csp) || - !checkDtRange(qualified_mass_spectrum_csp)) + if(!checkMsLevel(qualified_mass_spectrum_csp)) { - // if(!checkMsLevel(qualified_mass_spectrum_csp)) - // qDebug() << "MS level did not check."; - - // if(!checkRtRange(qualified_mass_spectrum_csp)) - // qDebug() << "RT range did not check."; - - // if(!checkDtRange(qualified_mass_spectrum_csp)) - // qDebug() << "DT range did not check."; - - // qDebug() << "The checks returned false"; - + qDebug() << "The MsLevel check returned false"; + ++current_iterator; + continue; + } + if(!checkMsFragmentation(qualified_mass_spectrum_csp)) + { + qDebug() << "The MsFragmentation check returned false"; ++current_iterator; continue; } - // At this point we need to go deep in the processing flow's steps to - // check if the node matches the whole set of the steps' specs. - - // qDebug() << "The processing flow has" << m_processingFlow.size() << - // "steps."; - - // Boolean value needed because we need to break two loops. - bool should_increment_iterator_and_continue = false; + // Make easy check about RT and DT. - for(auto &&step : m_processingFlow) + if(!checkRtRange(qualified_mass_spectrum_csp)) { - if(!checkProcessingStep(*step, qualified_mass_spectrum_csp)) - { - should_increment_iterator_and_continue = true; - break; - } - } + qDebug() << "checkRtRange failed check."; - if(should_increment_iterator_and_continue) + ++current_iterator; + continue; + } + if(!checkDtRange(qualified_mass_spectrum_csp)) { + qDebug() << "checkDtRange failed check."; + ++current_iterator; continue; } double mass_spectrum_sum_y = 0; - // These values are set in the in the base class constuctor. + // At this point we need to account for any limitations in the m/z + // dimension of the data. These limitations might be as easy as having + // a single m/z range limit or as complex as having one or more 2D + // steps involving the m/z dimension in the m_innermostSteps2D, if the + // selection polygons are not rectangle. - if(m_mzRange.first != std::numeric_limits::max() && - m_mzRange.second != std::numeric_limits::min()) + // Let's get this immediately, we'll need it more than once, maybe. + double rt = qualified_mass_spectrum_csp->getRtInMinutes(); + + if(!selection_polygon_specs.size()) { - mass_spectrum_sum_y = - qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY( - m_mzRange.first, m_mzRange.second); + if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second)) + { + mass_spectrum_sum_y = + qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY( + m_mzRange.first, m_mzRange.second); + } + else + { + mass_spectrum_sum_y = + qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY(); + } } else { - mass_spectrum_sum_y = - qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY(); + // It may be possible that the 2D steps limiting the m/z range + // have been followed by 1D steps further limiting the m/Z range. + // The point is, the 1D steps are not stored in + // selection_polygon_specs. However, by necessity, if there is at + // least one selection_polygon_spec, then the m_mzRange holds + // values. Futher, if there had been a 1D step limiting even more + // the m/z range, then that step would have been accounted for in + // m_mzRange. So we can account that limit right away. + + if(std::isnan(m_mzRange.first) || std::isnan(m_mzRange.second)) + qFatal("Programming error."); + + pappso::Trace filtered_trace( + *qualified_mass_spectrum_csp->getMassSpectrumSPtr()); + + pappso::FilterResampleKeepXRange the_keep_filter( + m_mzRange.first, m_mzRange.second); + + filtered_trace = the_keep_filter.filter(filtered_trace); + + pappso::FilterResampleKeepPointInPolygon the_polygon_filter( + selection_polygon_specs); + + filtered_trace = the_polygon_filter.filter( + filtered_trace, + qualified_mass_spectrum_csp->getDtInMilliSeconds(), + qualified_mass_spectrum_csp->getRtInMinutes()); + + mass_spectrum_sum_y = filtered_trace.sumY(); } if(!mass_spectrum_sum_y) @@ -300,7 +353,6 @@ continue; } - double rt = qualified_mass_spectrum_csp->getRtInMinutes(); // Try to insert the pair into the map. Check if that was done or not. std::pair res = @@ -322,14 +374,12 @@ // Now we can go to the next mass spectrum. ++current_iterator; } - // End of - // while(current_iterator != end_iterator) + // End of + // while(current_iterator != end_iterator) -#if 0 - qDebug() << "At the end of the current iterator pair, current map:"; - for(auto &&pair : *current_tic_chrom_map_sp) - qDebug().noquote() << "(" << pair.first << "," << pair.second << ")"; -#endif + // qDebug() << "At the end of the current iterator pair, current map:"; + // for(auto &&pair : *current_tic_chrom_map_sp) + // qDebug().noquote() << "(" << pair.first << "," << pair.second << ")"; } // End of // #pragma omp parallel for ordered diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRtDt.cpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRtDt.cpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRtDt.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRtDt.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -34,6 +34,8 @@ /////////////////////// StdLib includes #include #include +#include + /////////////////////// OpenMP include #include @@ -48,7 +50,6 @@ /////////////////////// Local includes #include "QualifiedMassSpectrumVectorMassDataIntegratorToRtDt.hpp" -#include "ProcessingSpec.hpp" #include "ProcessingStep.hpp" #include "ProcessingType.hpp" @@ -154,10 +155,10 @@ using Map = std::map; const std::shared_ptr & -QualifiedMassSpectrumVectorMassDataIntegratorToRtDt::getDoubleMapTraceMapSPtr() +QualifiedMassSpectrumVectorMassDataIntegratorToRtDt::getRtMapTraceMapSPtr() const { - return m_doubleMapTraceMapSPtr; + return m_rtMapTraceMapSPtr; } pappso::DataKind @@ -169,20 +170,13 @@ void -QualifiedMassSpectrumVectorMassDataIntegratorToRtDt::integrate( - pappso::DataKind data_kind) +QualifiedMassSpectrumVectorMassDataIntegratorToRtDt::integrate() { - // qDebug(); + qDebug(); std::chrono::system_clock::time_point chrono_start_time = std::chrono::system_clock::now(); - // In this integration, we are going to craft the data to create a colormap - // that will plot rt data with either dt data or vice versa (depending on - // data_kind). - - m_lastIntegrationDataKind = data_kind; - // If there are no data, nothing to do. std::size_t mass_spectra_count = mcsp_qualifiedMassSpectraToIntegrateVector->size(); @@ -196,46 +190,70 @@ qDebug() << "The number of mass spectra to handle:" << mass_spectra_count; - // Nothing special to do about processing flow info because that must have - // been set before calling this function. - // We need to clear the map trace! m_mapTrace.clear(); emit setTaskDescriptionTextSignal( "Integrating to a TIC|XIC chromatogram / drift spectrum color map"); - // We need a processing flow to work, and, in particular, a processing step - // from which to find the specifics of the calculation. + // In this integration, we are going to craft the data to create a colormap + // that will plot dt data against rt data or vice versa. if(!m_processingFlow.size()) qFatal("The processing flow cannot be empty. Program aborted."); - // Get the most recent step that holds all the specifics of this integration. - const ProcessingStep *most_recent_processing_step_p = - m_processingFlow.mostRecentStep(); - - // There must be at least one ProcessingSpec (and thus a type) in the - // processing step. - if(!most_recent_processing_step_p->processingTypes().size()) - qFatal("The processing step cannot be empty. Program aborted."); - - if(!most_recent_processing_step_p->matches("ANY_TO_RT")) - qFatal("There should be one ProcessingType = ANY_TO_RT. Program aborted."); + // When constructing this integrator, the processing flow passed as parameter + // was used to gather innermost ranges data. When the steps that match + // the innermost criterion, these are stored in m_innermostSteps2D. When the + // steps are non-2D steps, then only the m_xxRange values are updated. + + // If the m_innermostSteps2D vector of ProcessingSteps is non-empty, then, + // that means that we may have some MZ-related 2D processing steps to account + // at combination time, because that is precisely the only moment that we can + // do that work. To be able to provide selection polygon an mass + // spectrum-specific dt|rt data, we have the SelectionPolygonSpec class. There + // can be as many such class instances as required to document the integration + // boundaries rt/mz and dt/mz for example. This is why we need to fill in the + // vector of SelectionPolygonSpec and then set that to the combiner. + + // Note, however, that the hassle described above only is acceptable when the + // selection polygon is not square. If the selection polygon is square, then + // the ranges suffice, and they have been filled-in properly upon construction + // of this integrator. + + qDebug() << "Now filling-in the selection_polygon_specs."; + + std::vector selection_polygon_specs; + + std::size_t selection_polygon_spec_count = + fillInSelectionPolygonSpecs(selection_polygon_specs); + + qDebug() << selection_polygon_spec_count + << "selection polygon specs were retained for the configuration of " + "the filter."; // Using a shared pointer make it easy to handle the copying of the map to // users of that map without bothering. - if(m_doubleMapTraceMapSPtr == nullptr) - m_doubleMapTraceMapSPtr = + if(m_rtMapTraceMapSPtr == nullptr) + m_rtMapTraceMapSPtr = std::make_shared>(); else - m_doubleMapTraceMapSPtr->clear(); + m_rtMapTraceMapSPtr->clear(); // In this function, rt is the x_axis and dt is the y_axis, for each (rt,dt) - // pair, the TIC intensity is the color. So we have m_doubleMapTraceMapSPtr = + // pair, the TIC intensity is the color. So we have m_rtMapTraceMapSPtr = // >. + // The logic here is that in IM-MS experiments, for a given retention time + // (rt), the might be hundrds of drift time-resolvec mass spectra. So we + // create a map that relates rt values with a MapTrace, itself relating dt + // values (map key) and TICint values (map value). During iterating in all the + // mass spectra, we look at the rt value of the mass spectrum, we then look at + // its dt value. We compute a TICint of the mass spectrum that we set in the + // MapTrace, associated with the dt value. That MapTrace is then set the + // member map that maps the rt value (map key) with the MapTrace (map value). + // We want to parallelize the computation. Se we will allocate a vector of // iterators (as many as possible for the available processor threads), each // iterator having a subset of the initial data to integrate. @@ -266,14 +284,14 @@ using Map = std::map; using MapSPtr = std::shared_ptr; - std::vector vector_of_double_maptrace_maps; + std::vector vector_of_rt_maptrace_maps; for(std::size_t iter = 0; iter < iterators.size(); ++iter) - vector_of_double_maptrace_maps.push_back(std::make_shared()); + vector_of_rt_maptrace_maps.push_back(std::make_shared()); // Now that we have all the parallel material, we can start the parallel work. emit setProgressBarMaxValueSignal(mass_spectra_count); - qDebug() << "number of iterators:" << iterators.size(); + qDebug() << "Starting the iteration in the visitors."; omp_set_num_threads(iterators.size()); #pragma omp parallel for ordered @@ -287,8 +305,7 @@ // Get the map for this thread. - MapSPtr current_double_maptrace_map_sp = - vector_of_double_maptrace_maps.at(iter); + MapSPtr iterated_rt_maptrace_map_sp = vector_of_rt_maptrace_maps.at(iter); while(current_iterator != end_iterator) { @@ -316,6 +333,11 @@ qualified_mass_spectrum_csp = checkQualifiedMassSpectrum(qualified_mass_spectrum_csp); + if(qualified_mass_spectrum_csp == nullptr) + qFatal( + "Programming error. Not possible that shared pointer to " + "qualified mass spectrum be nullptr."); + // Great, at this point we actually have the mass spectrum! // We now need to ensure that the processing flow allows for this mass @@ -325,129 +347,127 @@ // that matches the greatest MS level found in the member processing // flow instance. - if(!checkMsLevel(qualified_mass_spectrum_csp) || - !checkRtRange(qualified_mass_spectrum_csp) || - !checkDtRange(qualified_mass_spectrum_csp)) + if(!checkMsLevel(qualified_mass_spectrum_csp)) { - // if(!checkMsLevel(qualified_mass_spectrum_csp)) - // qDebug() << "MS level did not check."; - - // if(!checkRtRange(qualified_mass_spectrum_csp)) - // qDebug() << "RT range did not check."; - - // if(!checkDtRange(qualified_mass_spectrum_csp)) - // qDebug() << "DT range did not check."; - - qDebug() << "The checks returned false"; - + qDebug() << "The MsLevel check returned false"; ++current_iterator; continue; } - - // At this point we need to go deep in the processing flow's steps to - // check if the node matches the whole set of the steps' specs. - - // qDebug() << "The processing flow has" << m_processingFlow.size() << - // "steps."; - - // Boolean value needed because we need to break two loops. - bool should_increment_iterator_and_continue = false; - - for(auto &&step : m_processingFlow) - { - if(!checkProcessingStep(*step, qualified_mass_spectrum_csp)) - { - should_increment_iterator_and_continue = true; - break; - } - } - - if(should_increment_iterator_and_continue) + if(!checkMsFragmentation(qualified_mass_spectrum_csp)) { + qDebug() << "The MsFragmentation check returned false"; ++current_iterator; continue; } - // Great, at this point we actually know that we have to account for - // the mass spectrum and we need to get the dt|rt value for it. - - double first_key; // that is, either rt or dt. - double second_key; // that is, either rt or dt. + // Make easy check about RT and DT. - if(m_lastIntegrationDataKind == pappso::DataKind::rt) + if(!checkRtRange(qualified_mass_spectrum_csp)) { - first_key = qualified_mass_spectrum_csp->getRtInMinutes(); - second_key = qualified_mass_spectrum_csp->getDtInMilliSeconds(); + qDebug() << "checkRtRange failed check."; + + ++current_iterator; + continue; } - else if(m_lastIntegrationDataKind == pappso::DataKind::dt) + if(!checkDtRange(qualified_mass_spectrum_csp)) { - first_key = qualified_mass_spectrum_csp->getDtInMilliSeconds(); - second_key = qualified_mass_spectrum_csp->getRtInMinutes(); + qDebug() << "checkDtRange failed check."; + + ++current_iterator; + continue; } - else - qFatal("Programming error."); - // We want to know what is the TIC intensity value of the spectrum. - // Note that we need to check if we are limited in the mz range that - // needs to be accounted for in the TIC sum calculation. + double dt_key = qualified_mass_spectrum_csp->getDtInMilliSeconds(); + double rt_key = qualified_mass_spectrum_csp->getRtInMinutes(); double mass_spectrum_sum_y = 0; - // These values are set in the in the base class constuctor. + // We want to know what is the TIC intensity value of the spectrum. - if(m_mzRange.first != std::numeric_limits::max() && - m_mzRange.second != std::numeric_limits::min()) - { - // qDebug() << "applying mz range filtering:" << m_mzRange.first - //<< "-" << m_mzRange.second; + // At this point we need to account for any limitations in the m/z + // dimension of the data. These limitations might be as easy as having + // a single m/z range limit or as complex as having one or more 2D + // steps involving the m/z dimension in the m_innermostSteps2D, if the + // selection polygons are not rectangle. - mass_spectrum_sum_y = - qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY( - m_mzRange.first, m_mzRange.second); + if(!selection_polygon_specs.size()) + { + if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second)) + { + mass_spectrum_sum_y = + qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY( + m_mzRange.first, m_mzRange.second); + } + else + { + mass_spectrum_sum_y = + qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY(); + } } else { - // qDebug() << "NOT applying mz range filtering."; + // It may be possible that the 2D steps limiting the m/z range + // have been followed by 1D steps further limiting the m/Z range. + // The point is, the 1D steps are not stored in + // selection_polygon_specs. However, by necessity, if there is at + // least one selection_polygon_spec, then the m_mzRange holds + // values. Futher, if there had been a 1D step limiting even more + // the m/z range, then that step would have been accounted for in + // m_mzRange. So we can account that limit right away. + + if(std::isnan(m_mzRange.first) || std::isnan(m_mzRange.second)) + qFatal("Programming error."); + + pappso::Trace filtered_trace( + *qualified_mass_spectrum_csp->getMassSpectrumSPtr()); + + pappso::FilterResampleKeepXRange the_keep_filter( + m_mzRange.first, m_mzRange.second); + + filtered_trace = the_keep_filter.filter(filtered_trace); - mass_spectrum_sum_y = - qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY(); + pappso::FilterResampleKeepPointInPolygon the_polygon_filter( + selection_polygon_specs); + + filtered_trace = + the_polygon_filter.filter(filtered_trace, dt_key, rt_key); + + mass_spectrum_sum_y = filtered_trace.sumY(); } if(!mass_spectrum_sum_y) { - // qDebug() << "The sum_y is 0"; - ++current_iterator; continue; } - // Now look into the map if we already encountered - // the first_key value. Store the found place in an iterator. + // Now look into the map that relates rt values + // with MapTraces, if we already encountered the rt_key value. Store + // the found place in an iterator. Map::iterator double_maptrace_map_iterator; double_maptrace_map_iterator = - current_double_maptrace_map_sp->find(first_key); + iterated_rt_maptrace_map_sp->find(rt_key); // Tells if the key was already found in the map. - if(double_maptrace_map_iterator != - current_double_maptrace_map_sp->end()) + if(double_maptrace_map_iterator != iterated_rt_maptrace_map_sp->end()) { // The map already contained a pair that had the key value == - // first_key. The ->second member of the iterator is the MapTrace - // that maps . So we now need to search for - // a map item that has key == second_key. + // rt_key (->first membero of the pair). The ->second member of + // the pair is the MapTrace that maps . So we + // now need to search for a map item that has key == dt_key. using MapIterator = std::map::iterator; std::pair res = double_maptrace_map_iterator->second.insert( - std::pair(second_key, mass_spectrum_sum_y)); + std::pair(dt_key, mass_spectrum_sum_y)); if(!res.second) { - // One other same second_key value was seen already. Only + // One other same dt_key value was seen already. Only // increment the y value. res.first->second += mass_spectrum_sum_y; @@ -456,23 +476,23 @@ else { - // This is the first time that we encounter first_key. So we need - // to create a new MapTrace for that first_key. That MapTrace + // This is the first time that we encounter dt_key. So we need + // to create a new MapTrace for that dt_key. That MapTrace // (std::map) will store the TIC values for all the - // second_key elements. + // dt_key elements. // Instantiate a new MapTrace in which we'll store all the TIC - // intensities for all the second_key map items. + // intensities for all the dt_key map items. pappso::MapTrace map_trace; map_trace.insert( - std::pair(second_key, mass_spectrum_sum_y)); + std::pair(dt_key, mass_spectrum_sum_y)); // Finally, store in the map map, the map_trace - // along with its first_key. + // along with its dt_key. - (*current_double_maptrace_map_sp)[first_key] = map_trace; + (*iterated_rt_maptrace_map_sp)[rt_key] = map_trace; } // At this point we have processed the qualified mass spectrum. @@ -496,7 +516,7 @@ // If the task was cancelled, the monitor widget was locked. We need to // unlock it. emit unlockTaskMonitorCompositeWidgetSignal(); - emit setupProgressBarSignal(0, vector_of_double_maptrace_maps.size() - 1); + emit setupProgressBarSignal(0, vector_of_rt_maptrace_maps.size() - 1); // We might be here because the user cancelled the operation in the for loop // above (visiting all the visitors). In this case m_isOperationCancelled is @@ -509,7 +529,7 @@ pappso::TracePlusCombiner combiner(0); - for(auto &&map_sp : vector_of_double_maptrace_maps) + for(auto &&map_sp : vector_of_rt_maptrace_maps) { // qDebug(); @@ -520,7 +540,7 @@ for(auto &&pair : *map_sp) { - // first is the first_key + // first is the dt_key // second is the pappso::MapTrace emit setStatusTextSignal( @@ -528,35 +548,34 @@ emit setProgressBarCurrentValueSignal(iter); - double first_key = pair.first; + double dt_key = pair.first; pappso::MapTrace current_maptrace = pair.second; - // Now search in the member if a first_key was found already. + // Now search in the member if a dt_key was found already. Map::iterator double_maptrace_map_iterator; - double_maptrace_map_iterator = - m_doubleMapTraceMapSPtr->find(first_key); + double_maptrace_map_iterator = m_rtMapTraceMapSPtr->find(dt_key); // Tells if the key was already found in the map. - if(double_maptrace_map_iterator != m_doubleMapTraceMapSPtr->end()) + if(double_maptrace_map_iterator != m_rtMapTraceMapSPtr->end()) { // qDebug() << "Adding new key value:" << rt_or_dt_key; // The map already contained a pair that had the key value == - // first_key. We want to sum, map item by map item all the map + // dt_key. We want to sum, map item by map item all the map // items in the current_maptrace MapTrace to // the combined one that will hold the final color map data: // double_maptrace_map_iterator->second. // For example, thread 1 yielded a map like - // this: >. rt is first_key and dt is second_key. + // this: >. rt is dt_key and dt is rt_key. // We search in the member map if an item has a - // value matching rt (that is, first_key). If found then we need + // value matching rt (that is, dt_key). If found then we need // to combine the iterated MapTrace into the member MapTrace for - // key first_key. It's like if MapTrace were a mass spectrum, but + // key dt_key. It's like if MapTrace were a mass spectrum, but // in fact m/z is replaced with dt. // qDebug() << "Before combination, map trace map size: " @@ -569,16 +588,16 @@ { // No map item was found with double equals to - // first_key. So we need to create a MapTrace ex nihilo. + // dt_key. So we need to create a MapTrace ex nihilo. pappso::MapTrace map_trace; combiner.combine(map_trace, current_maptrace); // Finally, store in the map, the map_trace along with its - // first_key. + // dt_key. - (*m_doubleMapTraceMapSPtr)[first_key] = map_trace; + (*m_rtMapTraceMapSPtr)[dt_key] = map_trace; } } } @@ -586,19 +605,19 @@ // We now need to go through the double map trace map to inspect its // characteristics. - if(!m_doubleMapTraceMapSPtr->size()) + if(!m_rtMapTraceMapSPtr->size()) { qDebug() << "There are no data in the double maptrace map."; return; } - m_colorMapMinKey = m_doubleMapTraceMapSPtr->begin()->first; - m_colorMapMaxKey = m_doubleMapTraceMapSPtr->rbegin()->first; + m_colorMapMinKey = m_rtMapTraceMapSPtr->begin()->first; + m_colorMapMaxKey = m_rtMapTraceMapSPtr->rbegin()->first; - m_colorMapKeyCellCount = m_doubleMapTraceMapSPtr->size(); + m_colorMapKeyCellCount = m_rtMapTraceMapSPtr->size(); - for(auto &&pair : *m_doubleMapTraceMapSPtr) + for(auto &&pair : *m_rtMapTraceMapSPtr) { pappso::MapTrace map_trace = pair.second; @@ -620,18 +639,10 @@ QString chrono_string; - if(m_lastIntegrationDataKind == pappso::DataKind::rt) - chrono_string = pappso::Utils::chronoIntervalDebugString( - "Integration to RT / DT colormap took:", - chrono_start_time, - chrono_end_time); - else if(m_lastIntegrationDataKind == pappso::DataKind::dt) - chrono_string = pappso::Utils::chronoIntervalDebugString( - "Integration to DT / RT colormap took:", - chrono_start_time, - chrono_end_time); - else - qFatal("Programming error."); + chrono_string = pappso::Utils::chronoIntervalDebugString( + "Integration to RT / DT colormap took:", + chrono_start_time, + chrono_end_time); emit logTextToConsoleSignal(chrono_string); diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRtDt.hpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRtDt.hpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRtDt.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRtDt.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -94,27 +94,38 @@ double getColorMapMaxMz() const; using Map = std::map; - const std::shared_ptr &getDoubleMapTraceMapSPtr() const; + const std::shared_ptr &getRtMapTraceMapSPtr() const; public slots: - void integrate(pappso::DataKind data_kind); + void integrate(); signals: protected: + // m_colorMapKeyCellCount: the number of rt values in the m_rtMapTraceMapSPtr + // map. std::size_t m_colorMapKeyCellCount = 0; + + // m_colorMapMzCellCount: the maximum number of m/z data points std::size_t m_colorMapMzCellCount = 0; + // The m_colorMapMinKey is the smallest rt value double m_colorMapMinKey = std::numeric_limits::max(); + // The m_colorMapMinKey is the greatest rt value double m_colorMapMaxKey = std::numeric_limits::min(); + // m_colorMapMinMz: the smallest m/z value of all the data double m_colorMapMinMz = std::numeric_limits::max(); + + // m_colorMapMinMz: the greatest m/z value of all the data double m_colorMapMaxMz = std::numeric_limits::min(); - std::shared_ptr m_doubleMapTraceMapSPtr = nullptr; + // The map relating rt value with MapTrace (that in turn relate dt values + // with TICint). + std::shared_ptr m_rtMapTraceMapSPtr = nullptr; pappso::DataKind m_lastIntegrationDataKind; }; diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRt.hpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRt.hpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRt.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToRt.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -85,7 +85,7 @@ public slots: - void integrateToRt(); + void integrate(); signals: diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToTicInt.cpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToTicInt.cpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToTicInt.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToTicInt.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -34,6 +34,8 @@ /////////////////////// StdLib includes #include #include +#include + /////////////////////// OpenMP include #include @@ -48,7 +50,6 @@ /////////////////////// Local includes #include "QualifiedMassSpectrumVectorMassDataIntegratorToTicInt.hpp" -#include "ProcessingSpec.hpp" #include "ProcessingStep.hpp" #include "ProcessingType.hpp" @@ -118,7 +119,7 @@ void -QualifiedMassSpectrumVectorMassDataIntegratorToTicInt::integrateToTicIntensity() +QualifiedMassSpectrumVectorMassDataIntegratorToTicInt::integrate() { qDebug(); @@ -153,24 +154,39 @@ const ProcessingStep *most_recent_processing_step_p = m_processingFlow.mostRecentStep(); - // There must be at least one ProcessingSpec (and thus a type) in the - // processing step. - - if(!most_recent_processing_step_p->processingTypes().size()) - qFatal("The processing step cannot be empty. Program aborted."); - - // We are integrating to m/z so we need a spec description that matches - // "ANY_TO_MZ". + if(!most_recent_processing_step_p->getDestProcessingType().bitMatches("INT")) + qFatal("There should be one ProcessingType = INT. Program aborted."); - if(!most_recent_processing_step_p->matches("ANY_TO_INT")) - qFatal("There should be one ProcessingType = ANY_TO_INT. Program aborted."); - - std::pair innermost_mz_range = - most_recent_processing_step_p->innermostRangeProcessingSpecsMatching( - ProcessingType("ANY_TO_INT")); - - qDebug() << "Innermost ANY_TO_INT range:" << innermost_mz_range.first << "--" - << innermost_mz_range.second; + // When constructing this integrator, the processing flow passed as parameter + // was used to gather innermost ranges data. When the steps that match + // the innermost criterion, these are stored in m_innermostSteps2D. When the + // steps are non-2D steps, then only the m_xxRange values are updated. + + // If the m_innermostSteps2D vector of ProcessingSteps is non-empty, then, + // that means that we may have some MZ-related 2D processing steps to account + // at combination time, because that is precisely the only moment that we can + // do that work. To be able to provide selection polygon an mass + // spectrum-specific dt|rt data, we have the SelectionPolygonSpec class. There + // can be as many such class instances as required to document the integration + // boundaries rt/mz and dt/mz for example. This is why we need to fill in the + // vector of SelectionPolygonSpec and then set that to the combiner. + + // Note, however, that the hassle described above only is acceptable when the + // selection polygon is not square. If the selection polygon is square, then + // the ranges suffice, and they have been filled-in properly upon construction + // of this integrator. + + qDebug() << "Now filling-in the selection_polygon_specs for any 2D step that " + "has a source type involving the MZ data kind."; + + std::vector selection_polygon_specs; + + std::size_t selection_polygon_spec_count = + fillInSelectionPolygonSpecs(selection_polygon_specs); + + qDebug() << selection_polygon_spec_count + << "selection polygon specs were retained for the configuration of " + "the filter."; // Determine the best number of threads to use and how many spectra to provide // each of the threads. @@ -201,6 +217,8 @@ // Now that we have all the parallel material, we can start the parallel work. emit setProgressBarMaxValueSignal(mass_spectra_count); + qDebug() << "Starting the iteration in the visitors."; + omp_set_num_threads(iterators.size()); #pragma omp parallel for ordered for(std::size_t iter = 0; iter < iterators.size(); ++iter) @@ -246,6 +264,11 @@ qualified_mass_spectrum_csp = checkQualifiedMassSpectrum(qualified_mass_spectrum_csp); + if(qualified_mass_spectrum_csp == nullptr) + qFatal( + "Programming error. Not possible that shared pointer to " + "qualified mass spectrum be nullptr."); + // Great, at this point we actually have the mass spectrum! // We now need to ensure that the processing flow allows for this mass @@ -255,56 +278,87 @@ // that matches the greatest MS level found in the member processing // flow instance. - if(!checkMsLevel(qualified_mass_spectrum_csp) || - !checkRtRange(qualified_mass_spectrum_csp) || - !checkDtRange(qualified_mass_spectrum_csp)) + if(!checkMsLevel(qualified_mass_spectrum_csp)) { - // if(!checkMsLevel(qualified_mass_spectrum_csp)) - // qDebug() << "MS level did not check."; - - // if(!checkRtRange(qualified_mass_spectrum_csp)) - // qDebug() << "RT range did not check."; - - // if(!checkDtRange(qualified_mass_spectrum_csp)) - // qDebug() << "DT range did not check."; - - // qDebug() << "The checks returned false"; - + qDebug() << "The MsLevel check returned false"; + ++current_iterator; + continue; + } + if(!checkMsFragmentation(qualified_mass_spectrum_csp)) + { + qDebug() << "The MsFragmentation check returned false"; ++current_iterator; continue; } - // At this point we need to go deep in the processing flow's steps to - // check if the node matches the whole set of the steps' specs. + // Make easy check about RT and DT. - // qDebug() << "The processing flow has" << m_processingFlow.size() << - // "steps."; + if(!checkRtRange(qualified_mass_spectrum_csp)) + { + qDebug() << "checkRtRange failed check."; - // for(auto &&step : m_processingFlow) - //{ - // if(!checkProcessingStep(*step, qualified_mass_spectrum_csp)) - //{ - //++current_iterator; - // continue; - //} - //} + ++current_iterator; + continue; + } + if(!checkDtRange(qualified_mass_spectrum_csp)) + { + qDebug() << "checkDtRange failed check."; - // Note that we need to check if we are limited in the mz range that - // needs to be accounted for in the TIC sum calculation. + ++current_iterator; + continue; + } - // These values are set in the in the base class constuctor. + // At this point we need to account for any limitations in the m/z + // dimension of the data. These limitations might be as easy as having + // a single m/z range limit or as complex as having one or more 2D + // steps involving the m/z dimension in the m_innermostSteps2D, if the + // selection polygons are not rectangle. - if(m_mzRange.first != std::numeric_limits::max() && - m_mzRange.second != std::numeric_limits::min()) + if(!selection_polygon_specs.size()) { - *current_tic_intensity_sp += - qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY( - m_mzRange.first, m_mzRange.second); + if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second)) + { + *current_tic_intensity_sp += + qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY( + m_mzRange.first, m_mzRange.second); + } + else + { + *current_tic_intensity_sp += + qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY(); + } } else { - *current_tic_intensity_sp += - qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY(); + // It may be possible that the 2D steps limiting the m/z range + // have been followed by 1D steps further limiting the m/Z range. + // The point is, the 1D steps are not stored in + // selection_polygon_specs. However, by necessity, if there is at + // least one selection_polygon_spec, then the m_mzRange holds + // values. Futher, if there had been a 1D step limiting even more + // the m/z range, then that step would have been accounted for in + // m_mzRange. So we can account that limit right away. + + if(std::isnan(m_mzRange.first) || std::isnan(m_mzRange.second)) + qFatal("Programming error."); + + pappso::Trace filtered_trace( + *qualified_mass_spectrum_csp->getMassSpectrumSPtr()); + + pappso::FilterResampleKeepXRange the_keep_filter( + m_mzRange.first, m_mzRange.second); + + filtered_trace = the_keep_filter.filter(filtered_trace); + + pappso::FilterResampleKeepPointInPolygon the_polygon_filter( + selection_polygon_specs); + + filtered_trace = the_polygon_filter.filter( + filtered_trace, + qualified_mass_spectrum_csp->getDtInMilliSeconds(), + qualified_mass_spectrum_csp->getRtInMinutes()); + + *current_tic_intensity_sp += filtered_trace.sumY(); } emit incrementProgressBarCurrentValueAndSetStatusTextSignal( diff -Nru minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToTicInt.hpp minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToTicInt.hpp --- minexpert2-7.4.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToTicInt.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/QualifiedMassSpectrumVectorMassDataIntegratorToTicInt.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -87,7 +87,7 @@ public slots: - void integrateToTicIntensity(); + void integrate(); signals: diff -Nru minexpert2-7.4.1/src/nongui/RtDtColorMapTreeNodeCombinerVisitor.cpp minexpert2-8.1.1/src/nongui/RtDtColorMapTreeNodeCombinerVisitor.cpp --- minexpert2-7.4.1/src/nongui/RtDtColorMapTreeNodeCombinerVisitor.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/RtDtColorMapTreeNodeCombinerVisitor.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -539,7 +539,7 @@ const ProcessingSpec *spec_p = type_spec_pair.second; - if(spec_p->hasValidRange()) + if(spec_p->hasValidOneDimensionRange()) { qDebug() << "Needed a m/z range filtering:" << spec_p->toString(); diff -Nru minexpert2-7.4.1/src/nongui/RtDtMzColorMapsTreeNodeCombinerVisitor.cpp minexpert2-8.1.1/src/nongui/RtDtMzColorMapsTreeNodeCombinerVisitor.cpp --- minexpert2-7.4.1/src/nongui/RtDtMzColorMapsTreeNodeCombinerVisitor.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/RtDtMzColorMapsTreeNodeCombinerVisitor.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -524,7 +524,7 @@ const ProcessingSpec *spec_p = type_spec_pair.second; - if(spec_p->hasValidRange()) + if(spec_p->hasValidOneDimensionRange()) { qDebug() << "Needed a m/z range filtering:" << spec_p->toString(); diff -Nru minexpert2-7.4.1/src/nongui/TicChromTreeNodeCombinerVisitor.cpp minexpert2-8.1.1/src/nongui/TicChromTreeNodeCombinerVisitor.cpp --- minexpert2-7.4.1/src/nongui/TicChromTreeNodeCombinerVisitor.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/TicChromTreeNodeCombinerVisitor.cpp 2021-04-26 11:28:25.000000000 +0000 @@ -32,6 +32,7 @@ /////////////////////// StdLib includes +#include /////////////////////// Qt includes @@ -57,7 +58,6 @@ const ProcessingFlow &processing_flow) : BaseMsRunDataSetTreeNodeVisitor(ms_run_data_set_csp, processing_flow) { - // qDebug() << "Processing flow has" << m_processingFlow.size() << "steps"; } @@ -102,14 +102,6 @@ //} -void -TicChromTreeNodeCombinerVisitor::setProcessingFlow( - const ProcessingFlow &processing_flow) -{ - m_processingFlow = processing_flow; -} - - const pappso::MapTrace & TicChromTreeNodeCombinerVisitor::getTicChromMapTrace() const { @@ -148,32 +140,40 @@ pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = checkQualifiedMassSpectrum(node); + if(qualified_mass_spectrum_csp == nullptr) + { + qFatal("Failed to read the mass spectral data from the file."); + } + + // Immediately check if the qualified mass spectrum is of a MS level that // matches the greatest MS level found in the member processing flow instance. - if(!checkMsLevel(node)) + if(!checkMsLevel(qualified_mass_spectrum_csp)) { // qDebug() << "The checkMsLevel failed. Returning false, mass spectrum // not " "accounted for."; + return false; } + // else + //{ + // qDebug() << "The MS level check succeeded."; + //} - // At this point we need to go deep in the processing flow's steps to check - // if the node matches the whole set of the steps' specs. + // Make easy check about RT and DT. - // qDebug() << "The processing flow has" << m_processingFlow.size() << - // "steps."; + if(!checkRtRange(qualified_mass_spectrum_csp)) + { + qDebug() << "checkRtRange failed check."; - for(auto &&step : m_processingFlow) + return false; + } + if(!checkDtRange(qualified_mass_spectrum_csp)) { - if(checkProcessingStep(*step, node)) - { - // qDebug() << "The node:" << &node << "matches the iterated step."; - } - else - { - return false; - } + qDebug() << "checkDtRange failed check."; + + return false; } // qDebug().noquote() << "The qualified mass spectrum:" @@ -187,11 +187,10 @@ double sumY = 0; - if(m_limitMzRangeStart != std::numeric_limits::max() && - m_limitMzRangeEnd != std::numeric_limits::max()) + if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second)) { sumY = qualified_mass_spectrum_csp->getMassSpectrumSPtr()->sumY( - m_limitMzRangeStart, m_limitMzRangeEnd); + m_mzRange.first, m_mzRange.second); } else { @@ -225,259 +224,6 @@ return true; } - - -bool -TicChromTreeNodeCombinerVisitor::checkProcessingStep( - const ProcessingStep &step, const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // A processing step is a collection of mapped items: - // std::map m_processingTypeSpecMap; - // - // For each item, we need to check if the node matches the spec. - - for(auto &&pair : step.getProcessingTypeSpecMap()) - { - if(checkProcessingSpec(pair, node)) - { - // qDebug() << "The node matches the iterated spec."; - } - else - { - // qDebug() << "The node does not match the iterated - // spec."; - - return false; - } - } - - return true; -} - - -bool -TicChromTreeNodeCombinerVisitor::checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // This is the most elemental component of a ProcessingFlow, so here we - // actually look into the node. - - const ProcessingSpec *spec_p = type_spec_pair.second; - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - if(qualified_mass_spectrum_csp == nullptr) - qFatal("Cannot be nullptr"); - - if(qualified_mass_spectrum_csp.get() == nullptr) - qFatal("Cannot be nullptr"); - - const MsFragmentationSpec fragmentation_spec = - spec_p->getMsFragmentationSpec(); - - if(fragmentation_spec.isValid()) - { - // qDebug() << "Node:" << &node << "Spec's fragmentation spec *is* valid:" - //<< fragmentation_spec.toString(); - - // For each member of the MsFragmentationSpec structure, check if it is to - // be used for the check. - - if(fragmentation_spec.getMsLevel()) - { - // qDebug() << "Node:" << &node - //<< "The fragmentation spec has ms levels."; - - // Logically, if the currently handled mass spectrum has a ms level - // that is greater than the fragmentation spec ms level, then that - // means that it should be visited: in the process of making data - // mining, one goes from the lowest ms level to higher ms levels, so - // we need to keep the mass spectrum. At some point down the - // processing datetime, a process spec will limit the mass spectra - // that are actually validated. - - if(qualified_mass_spectrum_csp->getMsLevel() >= - fragmentation_spec.getMsLevel()) - { - // qDebug() << "Node:" << &node - //<< "The ms level matches, with fragspec level:" - //<< fragmentation_spec.msLevelsToString() - //<< "and the node spectrum level:" - //<< qualified_mass_spectrum_csp->getMsLevel(); - } - else - { - // qDebug() << "Node:" << &node - //<< "The ms level does not match, with fragspec level:" - //<< fragmentation_spec.msLevelsToString() - //<< "and the node spectrum level:" - //<< qualified_mass_spectrum_csp->getMsLevel(); - - return false; - } - } - - if(fragmentation_spec.precursorMzValuesCount()) - { - const std::vector - &precursor_ion_data_vector = - qualified_mass_spectrum_csp->getPrecursorIonData(); - - if(!fragmentation_spec.containsMzPrecursors( - precursor_ion_data_vector)) - { - return false; - } - } - - if(fragmentation_spec.precursorSpectrumIndicesCount()) - { - if(!fragmentation_spec.containsSpectrumPrecursorIndex( - qualified_mass_spectrum_csp->getPrecursorSpectrumIndex())) - { - // qDebug() << "The precursor spectrum index does not match."; - - return false; - } - } - } - else - { - // Else, fragmentation is not a criterion for filtering data. So go on. - // qDebug() << "The fragmentation spec is *not* valid."; - } - - // qDebug() << "Frag spec ok, going on with the spec check."; - - ProcessingType type = type_spec_pair.first; - - // Because we are working on the TIC chromatogram visitor, we need to match - // the corresponding processing type that creates a TIC chromatogram right - // from the data file, apart from other processes that create a TIC chrom from - // other data settings, which in truth are called XIC chrom. - - if(type.bitMatches("RT_TO_ANY") || type.bitMatches("FILE_TO_RT")) - { - // qDebug(); - if(!checkProcessingTypeByRt(type_spec_pair, node)) - return false; - } - else if(type.bitMatches("MZ_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByMz(type_spec_pair, node)) - return false; - } - else if(type.bitMatches("DT_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByDt(type_spec_pair, node)) - return false; - } - - // At this point we seem to understand that the node matched! - - return true; -} // namespace minexpert - - -bool -TicChromTreeNodeCombinerVisitor::checkProcessingTypeByRt( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(spec_p->hasValidRange()) - { - double rt = qualified_mass_spectrum_csp->getRtInMinutes(); - - if(rt >= spec_p->getStart() && rt <= spec_p->getEnd()) - { - // qDebug() << "Returning true for Rt."; - return true; - } - else - return false; - } - - return true; -} - - -bool -TicChromTreeNodeCombinerVisitor::checkProcessingTypeByMz( - const std::pair &type_spec_pair, - [[maybe_unused]] const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // Are there specs about the m/z range to be accounted for in the - // computation? - - // Make a local copy of the type_spec_pair - std::pair local_type_spec_pair( - type_spec_pair); - - // Provide that copy for setting values in it to the function that gives the - // innmermost m/z range of all ProcessingSpec instances contained in the - // ProcessingFlow. - - if(m_processingFlow.innermostMzRange(local_type_spec_pair)) - { - m_limitMzRangeStart = local_type_spec_pair.second->getStart(); - m_limitMzRangeEnd = local_type_spec_pair.second->getEnd(); - } - else - { - // At this point there is no mz range-based criterion. - m_limitMzRangeStart = -1; - m_limitMzRangeEnd = -1; - } - - // Return true because we'll account that node whatever the mz range - // criterion. But, the limits will be accounted for in the visit() function at - // the moment of TIC calculation. - - return true; -} - - -bool -TicChromTreeNodeCombinerVisitor::checkProcessingTypeByDt( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(spec_p->hasValidRange()) - { - double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); - - if(dt >= spec_p->getStart() && dt <= spec_p->getEnd()) - return true; - else - return false; - } - - return true; -} } // namespace minexpert diff -Nru minexpert2-7.4.1/src/nongui/TicChromTreeNodeCombinerVisitor.hpp minexpert2-8.1.1/src/nongui/TicChromTreeNodeCombinerVisitor.hpp --- minexpert2-7.4.1/src/nongui/TicChromTreeNodeCombinerVisitor.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/TicChromTreeNodeCombinerVisitor.hpp 2021-04-26 11:28:25.000000000 +0000 @@ -76,10 +76,6 @@ virtual ~TicChromTreeNodeCombinerVisitor(); - // virtual void nodesToProcess(std::size_t nodes_to_process) override; - - virtual void setProcessingFlow(const ProcessingFlow &processing_flow); - const pappso::MapTrace &getTicChromMapTrace() const; TicChromTreeNodeCombinerVisitor & @@ -88,26 +84,6 @@ // Overrides the base class. virtual bool visit(const pappso::MsRunDataSetTreeNode &node) override; - virtual bool - checkProcessingStep(const ProcessingStep &step, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByRt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByMz( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByDt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - protected: pappso::MapTrace m_ticChromMapTrace; }; diff -Nru minexpert2-7.4.1/src/nongui/TraceTreeNodeCombinerVisitor.cpp minexpert2-8.1.1/src/nongui/TraceTreeNodeCombinerVisitor.cpp --- minexpert2-7.4.1/src/nongui/TraceTreeNodeCombinerVisitor.cpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/TraceTreeNodeCombinerVisitor.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,476 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright(C) 2009,...,2019 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - - -/////////////////////// StdLib includes - - -/////////////////////// Qt includes -#include - - -/////////////////////// pappsomspp includes - - -/////////////////////// Local includes -#include "TraceTreeNodeCombinerVisitor.hpp" - - -namespace msxps -{ -namespace minexpert -{ - - -TraceTreeNodeCombinerVisitor::TraceTreeNodeCombinerVisitor( - MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow, - pappso::TracePlusCombinerSPtr &trace_combiner_sp) - : BaseMsRunDataSetTreeNodeVisitor(ms_run_data_set_csp, processing_flow), - msp_combiner(trace_combiner_sp) -{ - // qDebug() << "Processing flow has" << m_processingFlow.size() << "steps"; -} - - -TraceTreeNodeCombinerVisitor::TraceTreeNodeCombinerVisitor( - MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow, - pappso::TracePlusCombinerSPtr &trace_combiner_sp, - const pappso::MzIntegrationParams &mz_integration_params) - : BaseMsRunDataSetTreeNodeVisitor(ms_run_data_set_csp, processing_flow), - msp_combiner(trace_combiner_sp), - m_mzIntegrationParams(mz_integration_params) -{ -} - - -TraceTreeNodeCombinerVisitor::TraceTreeNodeCombinerVisitor( - const TraceTreeNodeCombinerVisitor &other) - : BaseMsRunDataSetTreeNodeVisitor(other), - msp_combiner(other.msp_combiner), - m_mzIntegrationParams(other.m_mzIntegrationParams), - m_mapTrace(other.m_mapTrace) -{ -} - - -TraceTreeNodeCombinerVisitor & -TraceTreeNodeCombinerVisitor::operator=( - const TraceTreeNodeCombinerVisitor &other) -{ - if(this == &other) - return *this; - - BaseMsRunDataSetTreeNodeVisitor::operator=(other); - - m_mzIntegrationParams = other.m_mzIntegrationParams; - m_mapTrace = other.m_mapTrace; - msp_combiner = other.msp_combiner; - - return *this; -} - - -TraceTreeNodeCombinerVisitor::~TraceTreeNodeCombinerVisitor() -{ -} - - -void -TraceTreeNodeCombinerVisitor::setCombiner( - const pappso::TracePlusCombinerSPtr &trace_combiner_sp) -{ - msp_combiner = trace_combiner_sp; -} - - -pappso::TracePlusCombinerSPtr -TraceTreeNodeCombinerVisitor::getCombiner() -{ - return msp_combiner; -} - - -const pappso::MapTrace & -TraceTreeNodeCombinerVisitor::getMapTrace() const -{ - return m_mapTrace; -} - - -void -TraceTreeNodeCombinerVisitor::setMzIntegrationParams( - const pappso::MzIntegrationParams &mz_integration_params) -{ - m_mzIntegrationParams = mz_integration_params; -} - - -const pappso::MzIntegrationParams & -TraceTreeNodeCombinerVisitor::getMzIntegrationParams() -{ - return m_mzIntegrationParams; -} - - -bool -TraceTreeNodeCombinerVisitor::visit(const pappso::MsRunDataSetTreeNode &node) -{ - - // We visit a node, such that we can compute the trace. - - // qDebug() << "Visiting node:" << node.toString(); - - if(!m_isProgressFeedbackSilenced) - { - // Whatever the status of this node (to be or not processed) let the user - // know that we have gone through one more. - - // The "%c" format refers to the current value in the task monitor widget - // that will craft the new text according to the current value after - // having incremented it in the call below. This is necessary because this - // visitor might be in a thread and the we need to account for all the - // thread when giving feedback to the user. - - emit incrementProgressBarCurrentValueAndSetStatusTextSignal( - 1, "Processed %c nodes"); - } - - // qDebug().noquote() << "Visiting node:" << &node << "text format:" << - // node.toString() - //<< "with quaified mass spectrum:" - //<< node.getQualifiedMassSpectrum()->toString(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - checkQualifiedMassSpectrum(node); - - // Immediately check if the qualified mass spectrum is of a MS level that - // matches the greatest MS level found in the member processing flow instance. - - if(!checkMsLevel(node)) - return false; - - // At this point we need to go deep in the processing flow's steps to check - // if the node matches the whole set of the steps' specs. - - // qDebug() << "The processing flow has" << m_processingFlow.size() << - // "steps."; - - for(auto &&step : m_processingFlow) - { - if(checkProcessingStep(*step, node)) - { - // qDebug() << "The node:" << &node << "matches the iterated step."; - } - else - { - return false; - } - } - - // qDebug().noquote() << "The qualified mass spectrum:" - //<< qualified_mass_spectrum_csp->toString() - //<< "rt in minutes:" << qualified_mass_spectrum_csp->getRtInMinutes() - //<< "dt in milliseconds:" - //<< qualified_mass_spectrum_csp->getDtInMilliSeconds(); - - // qDebug() << "The current qualified mass spectrum has size:" - //<< qualified_mass_spectrum_csp->size(); - - m_mzIntegrationParams.updateSmallestMz( - qualified_mass_spectrum_csp->getMassSpectrumSPtr()->front().x); - m_mzIntegrationParams.updateGreatestMz( - qualified_mass_spectrum_csp->getMassSpectrumSPtr()->back().x); - - // At this point, we need to do the combination! - - msp_combiner->combine(m_mapTrace, - *(qualified_mass_spectrum_csp->getMassSpectrumSPtr())); - - return true; -} - - -bool -TraceTreeNodeCombinerVisitor::checkProcessingStep( - const ProcessingStep &step, const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // A processing step is a collection of mapped items: - // std::map m_processingTypeSpecMap; - // - // For each item, we need to check if the node matches the spec. - - for(auto &&pair : step.getProcessingTypeSpecMap()) - { - if(checkProcessingSpec(pair, node)) - { - // qDebug() << "The node matches the iterated spec."; - } - else - { - // qDebug() << "The node does not match the iterated - // spec."; - - return false; - } - } - - return true; -} - - -bool -TraceTreeNodeCombinerVisitor::checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // This is the most elemental component of a ProcessingFlow, so here we - // actually look into the node. - - const ProcessingSpec *spec_p = type_spec_pair.second; - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const MsFragmentationSpec fragmentation_spec = - spec_p->getMsFragmentationSpec(); - - if(fragmentation_spec.isValid()) - { - // qDebug() << "Node:" << &node << "Spec's fragmentation spec *is* valid:" - //<< fragmentation_spec.toString(); - - // For each member of the MsFragmentationSpec structure, check if it is - // to be used for the check. - -#if 0 - if(fragmentation_spec.getMinimumMsLevel()) - { - // qDebug() << "Node:" << &node - //<< "The fragmentation spec has ms levels."; - - // Logically, if the currently handled mass spectrum has a ms level - // that is greater than the fragmentation spec ms level, then that - // means that it should be visited: in the process of making data - // mining, one goes from the lowest ms level to higher ms levels, so - // we need to keep the mass spectrum. At some point down the - // processing datetime, a process spec will limit the mass spectra - // that are actually validated. - - if(qualified_mass_spectrum_csp->getMsLevel() >= - fragmentation_spec.getMinimumMsLevel()) - { - // qDebug() << "Node:" << &node - //<< "The ms level matches, with fragspec level:" - //<< fragmentation_spec.msLevelsToString() - //<< "and the node spectrum level:" - //<< qualified_mass_spectrum_csp->getMsLevel(); - } - else - { - // qDebug() << "Node:" << &node - //<< "The ms level does not match, with fragspec level:" - //<< fragmentation_spec.msLevelsToString() - //<< "and the node spectrum level:" - //<< qualified_mass_spectrum_csp->getMsLevel(); - - return false; - } - } - -#endif - - if(fragmentation_spec.precursorMzValuesCount()) - { - const std::vector - &precursor_ion_data_vector = - qualified_mass_spectrum_csp->getPrecursorIonData(); - - if(!fragmentation_spec.containsMzPrecursors( - precursor_ion_data_vector)) - { - return false; - } - } - - if(fragmentation_spec.precursorSpectrumIndicesCount()) - { - if(!fragmentation_spec.containsSpectrumPrecursorIndex( - qualified_mass_spectrum_csp->getPrecursorSpectrumIndex())) - { - // qDebug() << "Node:" << &node - //<< "The precursor spectrum index does not match."; - - return false; - } - } - } - else - { - // Else, fragmentation is not a criterion for filtering data. So go on. - // qDebug() << "The fragmentation spec is *not* valid."; - } - - // qDebug() << "Frag spec ok, going on with the spec check."; - - ProcessingType type = type_spec_pair.first; - - if(type.bitMatches("RT_TO_ANY") || type.bitMatches("FILE_TO_MZ")) - { - // qDebug(); - if(!checkProcessingTypeByRt(type_spec_pair, node)) - return false; - } - else if(type.bitMatches("MZ_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByMz(type_spec_pair, node)) - return false; - } - else if(type.bitMatches("DT_TO_ANY")) - { - // qDebug(); - if(!checkProcessingTypeByDt(type_spec_pair, node)) - return false; - } - - // At this point we seem to understand that the node matched! - - return true; -} - - -bool -TraceTreeNodeCombinerVisitor::checkProcessingTypeByRt( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(spec_p->hasValidRange()) - { - double rt = qualified_mass_spectrum_csp->getRtInMinutes(); - - if(rt >= spec_p->getStart() && rt <= spec_p->getEnd()) - { - // qDebug() << "Returning true for Rt."; - return true; - } - else - return false; - } - - return true; -} - - -bool -TraceTreeNodeCombinerVisitor::checkProcessingTypeByMz( - const std::pair &type_spec_pair, - [[maybe_unused]] const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - // Are there specs about the m/z range to be accounted for in the - // computation? - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(spec_p->hasValidRange()) - { - // qDebug() << "Needed a m/z range filtering:" << spec_p->toString(); - - // The point is that if there are more than one spec in the the flow's - // steps that limit the m/z range, we want to be sure to perform the - // combination using the innermost range. So ask the ProcessingFlow to - // actually compute that innermost m/z range. - - // Make a local copy of the type_spec_pair - std::pair local_type_spec_pair( - type_spec_pair); - - if(m_processingFlow.innermostMzRange(local_type_spec_pair)) - { - msp_combiner->setFilterResampleKeepXRange( - pappso::FilterResampleKeepXRange( - local_type_spec_pair.second->getStart(), - local_type_spec_pair.second->getEnd())); - } - else - qFatal( - "Cannot be that there is no innermost m/z range if there is a valid " - "m/z range in a spec."); - } - - return true; -} - - -bool -TraceTreeNodeCombinerVisitor::checkProcessingTypeByDt( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) -{ - // qDebug(); - - pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp = - node.getQualifiedMassSpectrum(); - - const ProcessingSpec *spec_p = type_spec_pair.second; - - if(spec_p->hasValidRange()) - { - double dt = qualified_mass_spectrum_csp->getDtInMilliSeconds(); - - if(dt >= spec_p->getStart() && dt <= spec_p->getEnd()) - return true; - else - return false; - } - - return true; -} - - -} // namespace minexpert - -} // namespace msxps diff -Nru minexpert2-7.4.1/src/nongui/TraceTreeNodeCombinerVisitor.hpp minexpert2-8.1.1/src/nongui/TraceTreeNodeCombinerVisitor.hpp --- minexpert2-7.4.1/src/nongui/TraceTreeNodeCombinerVisitor.hpp 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/src/nongui/TraceTreeNodeCombinerVisitor.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -/* BEGIN software license - * - * msXpertSuite - mass spectrometry software suite - * ----------------------------------------------- - * Copyright(C) 2009,...,2019 Filippo Rusconi - * - * http://www.msxpertsuite.org - * - * This file is part of the msXpertSuite project. - * - * The msXpertSuite project is the successor of the massXpert project. This - * project now includes various independent modules: - * - * - massXpert, model polymer chemistries and simulate mass spectrometric data; - * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner; - * - * 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 . - * - * END software license - */ - -#pragma once - -/////////////////////// StdLib includes - - -/////////////////////// Qt includes - - -/////////////////////// pappsomspp includes -#include -#include -#include -#include -#include - - -/////////////////////// Local includes -#include "ProcessingFlow.hpp" -#include "MsRunDataSet.hpp" -#include "BaseMsRunDataSetTreeNodeVisitor.hpp" -#include - - -namespace msxps -{ -namespace minexpert -{ - -class MassDataIntegrator; - -class TraceTreeNodeCombinerVisitor; - -typedef std::shared_ptr - TraceTreeNodeCombinerVisitorSPtr; - -class TraceTreeNodeCombinerVisitor : public BaseMsRunDataSetTreeNodeVisitor -{ - - friend class MassDataIntegrator; - - public: - TraceTreeNodeCombinerVisitor( - MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow, - pappso::TracePlusCombinerSPtr &trace_combiner_sp); - - TraceTreeNodeCombinerVisitor( - MsRunDataSetCstSPtr ms_run_data_set_csp, - const ProcessingFlow &processing_flow, - pappso::TracePlusCombinerSPtr &trace_combiner_sp, - const pappso::MzIntegrationParams &mz_integration_params); - - TraceTreeNodeCombinerVisitor(const TraceTreeNodeCombinerVisitor &other); - - virtual ~TraceTreeNodeCombinerVisitor(); - - void setCombiner(const pappso::TracePlusCombinerSPtr &trace_combiner_sp); - pappso::TracePlusCombinerSPtr getCombiner(); - - const pappso::MapTrace &getMapTrace() const; - - void setMzIntegrationParams(const pappso::MzIntegrationParams &mz_integration_params); - const pappso::MzIntegrationParams &getMzIntegrationParams(); - - TraceTreeNodeCombinerVisitor & - operator=(const TraceTreeNodeCombinerVisitor &other); - - // Overrides the base class. - virtual bool visit(const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool - checkProcessingStep(const ProcessingStep &step, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingSpec( - const std::pair &type_spec_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByRt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByMz( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - virtual bool checkProcessingTypeByDt( - const std::pair &spec_type_pair, - const pappso::MsRunDataSetTreeNode &node) override; - - protected: - pappso::TracePlusCombinerSPtr msp_combiner; - - pappso::MzIntegrationParams m_mzIntegrationParams; - pappso::MapTrace m_mapTrace; -}; - - -} // namespace minexpert - -} // namespace msxps diff -Nru minexpert2-7.4.1/TODO minexpert2-8.1.1/TODO --- minexpert2-7.4.1/TODO 2021-02-20 13:46:49.000000000 +0000 +++ minexpert2-8.1.1/TODO 2021-04-26 11:28:25.000000000 +0000 @@ -1,3 +1,7 @@ +Implement a threshold for the color maps (noise removal). + +Export color map data as a matrix file. + When removing an ms run data set, if the plot widgets are empty, close them. In the About dialog, set some menus to download mass spectrometric data