diff --git a/docs/source/interfaces/Engineering Diffraction.rst b/docs/source/interfaces/Engineering Diffraction.rst index a3d34483279ef69db96d061e3e0f5ae5be09ebe7..ebd3ef8a4450eb61320f84bd5a74823252543b97 100644 --- a/docs/source/interfaces/Engineering Diffraction.rst +++ b/docs/source/interfaces/Engineering Diffraction.rst @@ -335,24 +335,24 @@ Fitting .. warning:: The input workspace must be converted into a focused file first. The steps to complete this are found here: :ref:`focus-Engineering_Diffraction-ref` -The Fitting tab provides a graphical interface which fits an expected -diffraction pattern and visualises them. The pattern is specified by -providing a list of dSpacing values where Bragg peaks are expected. +The Fitting tab provides a graphical interface which fits and +visualises an expected diffraction pattern. The pattern is specified +by providing a list of dSpacing values where Bragg peaks are expected. The algorithm :ref:`EnggFitPeaks<algm-EnggFitPeaks>` is used to background fit peaks in those areas using a peak fitting function. To use the Fitting tab, user is required to follow these steps: -1. A focused file as Focus Run input by browsing or entering single/multi - run number, *User may click Load button to load the focused file to the +1. Load run(s) to perform fitting on by browsing for focused nexus + files *User may click Load button to load the focused file to the canvas* 2. List of expected peaks which can be either by browsing a (*CSV*) file, manually selecting peaks from the canvas using peak picker tool after loading the focused file or by entering the peaks list within the text-field 3. Next click on the *Fit* button if you would like to fit single focused file or you can click *Fit All* button which will enable user to - batch-process all the runs and banks when a range of run number is given, - *Fit All* process may also be used when when a single run number is given + batch-process all the runs and banks when several files are loaded. + *Fit All* process may also be used when a single run number is given or a file is browsed .. _ExpectedPeaks-Engineering_Diffraction-ref: @@ -362,44 +362,25 @@ Parameters These parameters are required to process Fitting successfully: -Focused Run #: - Focused workspace directory or selected using the browse button. - Users may also select the file/s by simply entering the file run number - or a range of consecutive run number separated by dash (`-`), for - example: "194547-194550" or "241391-241399". - - It is compulsory for these file/s to be located within the focused output directory. - Focused workspace can be generated with the help of - :ref:`focus-Engineering_Diffraction-ref` tab, the output folder - directory can be set in the :ref:`setting-Engineering_Diffraction-ref` - tab under the *Focusing settings* section. - - When a valid range of consecutive run numbers is given, the interface will - automatically import and add the run number/s to the list on the right side - of the graph, from where each run number can be selected from by click on it. - The interface will then automatically update the Plot Bank combo-box - according to the bank files found for each entered/selected run-number. +Focused Run files: + .nxs files containing focused diffraction data. These should be the result + of focusing data with the :ref:`focus-Engineering_Diffraction-ref` tab. Peaks: A list of dSpacing values to be translated into TOF to find expected peaks. These peaks can be manually written or imported by selecting a (*CSV*) file. -Plot Bank/Bank List: - These GUI widgets will only be enabled when multiple focused bank - files are found within the working directory or focused output directory. - This would enable user to select the desired bank which they would like to - plot with the help of Plot Bank combo-box or Bank List. Output ^^^^^^ Once the Fit button has been clicked Mantid will process the data. Please wait until the Fitting process has completed. Upon completion you should be able to -view on the Fitting tab which will contain: +view the Fitting tab which will contain: - The focused workspace plotted in the background in gray crosses. -- The expected peaks plotted in various colours over lapping the +- The expected peaks plotted in various colours overlapping the focused workspace peaks. Within the :ref:`Preview-Engineering_Diffraction-ref` section a user is diff --git a/docs/source/release/v3.12.0/diffraction.rst b/docs/source/release/v3.12.0/diffraction.rst index 4780fb6604e94559fb886774c44a522d68fe770a..024f0496cdc5a37455361c86839fc7ae49df4653 100644 --- a/docs/source/release/v3.12.0/diffraction.rst +++ b/docs/source/release/v3.12.0/diffraction.rst @@ -33,9 +33,10 @@ Engineering Diffraction latest version of GSAS-II, allowing Rietveld and Pawley refinement within Mantid. - Usability improvements in the GUI: - - The "Invalid RB number" popup window in the GUI has been replaced with a more user-friendly message - - Improved progress reporting for Calibration and Focus - + + The "Invalid RB number" popup window in the GUI has been replaced with a more user-friendly message + + Improved progress reporting for Calibration and Focus + + Enabled multi-run fitting and plotting in the Fitting tab + Single Crystal Diffraction -------------------------- - :ref:`FilterPeaks <algm-FilterPeaks>` now supports filtering peaks by TOF, d-spacing, and wavelength. diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingModel.cpp b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingModel.cpp index 80927dd5a03df8b1ab38b0055aff33c21d591fac..0120f9b14f2a63dd968424523328156969c204d3 100644 --- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingModel.cpp +++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingModel.cpp @@ -150,7 +150,6 @@ void EnggDiffFittingModel::createFittedPeaksWS(const int runNumber, const auto focusedWS = getFocusedWorkspace(runNumber, bank); const size_t numberOfPeaks = fitFunctionParams->rowCount(); - const std::string fittedPeaksWSName = "engggui_fitting_single_peaks"; for (size_t i = 0; i < numberOfPeaks; ++i) { const auto functionDescription = createFunctionString(fitFunctionParams, i); @@ -169,26 +168,28 @@ void EnggDiffFittingModel::createFittedPeaksWS(const int runNumber, singlePeakWSName); if (i == 0) { - cloneWorkspace(focusedWS, fittedPeaksWSName); - setDataToClonedWS(singlePeakWSName, fittedPeaksWSName); + cloneWorkspace(focusedWS, FITTED_PEAKS_WS_NAME); + setDataToClonedWS(singlePeakWSName, FITTED_PEAKS_WS_NAME); } else { const std::string clonedWSName = "__engggui_cloned_peaks_" + std::to_string(i); cloneWorkspace(focusedWS, clonedWSName); setDataToClonedWS(singlePeakWSName, clonedWSName); - appendSpectra(fittedPeaksWSName, clonedWSName); + appendSpectra(FITTED_PEAKS_WS_NAME, clonedWSName); } } const std::string alignedWSName = FOCUSED_WS_NAME + "_d"; - alignDetectors(getFocusedWorkspace(runNumber, bank), alignedWSName); - alignDetectors(fittedPeaksWSName, fittedPeaksWSName); + cloneWorkspace(focusedWS, alignedWSName); + alignDetectors(alignedWSName, alignedWSName); + + alignDetectors(FITTED_PEAKS_WS_NAME, FITTED_PEAKS_WS_NAME); const auto &ADS = Mantid::API::AnalysisDataService::Instance(); const auto fittedPeaksWS = - ADS.retrieveWS<Mantid::API::MatrixWorkspace>(fittedPeaksWSName); + ADS.retrieveWS<Mantid::API::MatrixWorkspace>(FITTED_PEAKS_WS_NAME); addToRunMap(runNumber, bank, m_fittedPeaksMap, fittedPeaksWS); const auto alignedFocusedWS = @@ -196,6 +197,21 @@ void EnggDiffFittingModel::createFittedPeaksWS(const int runNumber, addToRunMap(runNumber, bank, m_alignedWorkspaceMap, alignedFocusedWS); } +size_t EnggDiffFittingModel::getNumFocusedWorkspaces() const { + size_t numWorkspaces = 0; + + for (const auto &bank : m_focusedWorkspaceMap) { + numWorkspaces += bank.size(); + } + return numWorkspaces; +} + +bool EnggDiffFittingModel::hasFittedPeaksForRun(const int runNumber, + const size_t bank) const { + return m_fittedPeaksMap[bank - 1].find(runNumber) != + m_fittedPeaksMap[bank - 1].end(); +} + Mantid::API::MatrixWorkspace_sptr EnggDiffFittingModel::getAlignedWorkspace(const int runNumber, const size_t bank) const { @@ -255,7 +271,7 @@ void EnggDiffFittingModel::rebinToFocusedWorkspace( void EnggDiffFittingModel::cloneWorkspace( const Mantid::API::MatrixWorkspace_sptr inputWorkspace, - const std::string &outputWSName) { + const std::string &outputWSName) const { auto cloneWSAlg = Mantid::API::AlgorithmManager::Instance().create("CloneWorkspace"); cloneWSAlg->initialize(); @@ -275,7 +291,7 @@ void EnggDiffFittingModel::setDataToClonedWS(const std::string &wsToCopyName, } void EnggDiffFittingModel::appendSpectra(const std::string &ws1Name, - const std::string &ws2Name) { + const std::string &ws2Name) const { auto appendSpectraAlg = Mantid::API::AlgorithmManager::Instance().create("AppendSpectra"); @@ -363,8 +379,8 @@ void EnggDiffFittingModel::loadWorkspace(const std::string &filename, loadAlg->execute(); } -void EnggDiffFittingModel::renameWorkspace(API::MatrixWorkspace_sptr inputWS, - const std::string &newName) { +void EnggDiffFittingModel::renameWorkspace(API::Workspace_sptr inputWS, + const std::string &newName) const { auto renameAlg = API::AlgorithmManager::Instance().create("RenameWorkspace"); renameAlg->setProperty("InputWorkspace", inputWS); renameAlg->setProperty("OutputWorkspace", newName); @@ -402,6 +418,64 @@ std::vector<int> EnggDiffFittingModel::getAllRunNumbers() const { return runNumbers; } +void EnggDiffFittingModel::mergeTables( + const API::ITableWorkspace_sptr tableToCopy, + API::ITableWorkspace_sptr targetTable) const { + for (size_t i = 0; i < tableToCopy->rowCount(); ++i) { + API::TableRow rowToCopy = tableToCopy->getRow(i); + API::TableRow newRow = targetTable->appendRow(); + + for (size_t j = 0; j < tableToCopy->columnCount(); ++j) { + double valueToCopy; + rowToCopy >> valueToCopy; + newRow << valueToCopy; + } + } +} + +void EnggDiffFittingModel::addAllFitResultsToADS() const { + auto fitParamsTable = Mantid::API::WorkspaceFactory::Instance().createTable(); + renameWorkspace(fitParamsTable, FIT_RESULTS_TABLE_NAME); + + const auto runNumberBankPairs = getRunNumbersAndBankIDs(); + + for (const auto &runNumberBankPair : runNumberBankPairs) { + const int runNumber = runNumberBankPair.first; + const size_t bank = runNumberBankPair.second; + + const auto singleWSFitResults = getFitResults(runNumber, bank); + + if (runNumberBankPair == *runNumberBankPairs.begin()) { + // First element - copy column headings over + const auto columnHeaders = singleWSFitResults->getColumnNames(); + for (const auto &header : columnHeaders) { + fitParamsTable->addColumn("double", header); + } + } + mergeTables(singleWSFitResults, fitParamsTable); + } +} + +void EnggDiffFittingModel::addAllFittedPeaksToADS() const { + const auto runNumberBankPairs = getRunNumbersAndBankIDs(); + if (runNumberBankPairs.size() < 1) { + return; + } + const auto firstWSLabel = runNumberBankPairs[0]; + auto fittedPeaksWS = + getFittedPeaksWS(firstWSLabel.first, firstWSLabel.second); + cloneWorkspace(fittedPeaksWS, FITTED_PEAKS_WS_NAME); + + for (size_t i = 1; i < runNumberBankPairs.size(); ++i) { + const auto wsLabel = runNumberBankPairs[i]; + const int runNumber = wsLabel.first; + const size_t bank = wsLabel.second; + + auto wsToAppend = getFittedPeaksWS(runNumber, bank); + appendSpectra(FITTED_PEAKS_WS_NAME, wsToAppend->getName()); + } +} + namespace { std::string stripWSNameFromFilename(const std::string &fullyQualifiedFilename) { @@ -537,6 +611,8 @@ const std::string EnggDiffFittingModel::FOCUSED_WS_NAME = "engggui_fitting_focused_ws"; const std::string EnggDiffFittingModel::FIT_RESULTS_TABLE_NAME = "engggui_fitting_fitpeaks_params"; +const std::string EnggDiffFittingModel::FITTED_PEAKS_WS_NAME = + "engggui_fitting_single_peaks"; const double EnggDiffFittingModel::DEFAULT_DIFA = 0.0; const double EnggDiffFittingModel::DEFAULT_DIFC = 18400.0; diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingModel.h b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingModel.h index f5366fa79eb90a1004703211d83c0655cab9a507..da71e2494d5ddbb6fecb80c167f66f381927de9e 100644 --- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingModel.h +++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingModel.h @@ -49,6 +49,15 @@ public: void createFittedPeaksWS(const int runNumber, const size_t bank) override; + size_t getNumFocusedWorkspaces() const override; + + void addAllFitResultsToADS() const override; + + void addAllFittedPeaksToADS() const override; + + bool hasFittedPeaksForRun(const int runNumber, + const size_t bank) const override; + protected: void addFocusedWorkspace(const int runNumber, const size_t bank, const Mantid::API::MatrixWorkspace_sptr ws, @@ -57,6 +66,9 @@ protected: void addFitResults(const int runNumber, const size_t bank, const Mantid::API::ITableWorkspace_sptr ws); + void mergeTables(const Mantid::API::ITableWorkspace_sptr tableToCopy, + Mantid::API::ITableWorkspace_sptr targetTable) const; + private: static const size_t MAX_BANKS = 2; static const double DEFAULT_DIFC; @@ -64,6 +76,7 @@ private: static const double DEFAULT_TZERO; static const std::string FOCUSED_WS_NAME; static const std::string FIT_RESULTS_TABLE_NAME; + static const std::string FITTED_PEAKS_WS_NAME; RunMap<MAX_BANKS, Mantid::API::MatrixWorkspace_sptr> m_focusedWorkspaceMap; RunMap<MAX_BANKS, std::string> m_wsFilenameMap; @@ -96,12 +109,13 @@ private: const std::string &outputWSName); void cloneWorkspace(const Mantid::API::MatrixWorkspace_sptr inputWorkspace, - const std::string &outputWSName); + const std::string &outputWSName) const; void setDataToClonedWS(const std::string &wsToCopyName, const std::string &targetWSName); - void appendSpectra(const std::string &ws1Name, const std::string &ws2Name); + void appendSpectra(const std::string &ws1Name, + const std::string &ws2Name) const; std::tuple<double, double, double> getDifcDifaTzero(Mantid::API::MatrixWorkspace_const_sptr ws); @@ -119,8 +133,8 @@ private: void loadWorkspace(const std::string &filename, const std::string &wsName); - void renameWorkspace(Mantid::API::MatrixWorkspace_sptr inputWS, - const std::string &newName); + void renameWorkspace(Mantid::API::Workspace_sptr inputWS, + const std::string &newName) const; void groupWorkspaces(const std::vector<std::string> &workspaceNames, const std::string &outputWSName); diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresWorker.h b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresWorker.h index 743a3bdacc548f44da0146b013e72eeda28aadbc..7159b3b7a8ab96094ed8fcb77be2881dfdc26091 100644 --- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresWorker.h +++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresWorker.h @@ -41,16 +41,22 @@ class EnggDiffFittingWorker : public QObject { public: // for fitting (single peak fits) - EnggDiffFittingWorker(EnggDiffFittingPresenter *pres, const int runNumber, - const size_t bank, const std::string &ExpectedPeaks) - : m_pres(pres), m_runNumber(runNumber), m_bank(bank), - m_expectedPeaks(ExpectedPeaks) {} + EnggDiffFittingWorker( + EnggDiffFittingPresenter *pres, + const std::vector<std::pair<int, size_t>> &runNumberBankPairs, + const std::string &expectedPeaks) + : m_pres(pres), m_runNumberBankPairs(runNumberBankPairs), + m_expectedPeaks(expectedPeaks) {} private slots: void fitting() { try { - m_pres->doFitting(m_runNumber, m_bank, m_expectedPeaks); + for (const auto &runNumberBankPair : m_runNumberBankPairs) { + const int runNumber = runNumberBankPair.first; + const size_t bank = runNumberBankPair.second; + m_pres->doFitting(runNumber, bank, m_expectedPeaks); + } } catch (std::exception &ex) { Mantid::Kernel::Logger log("EngineeringDiffractionFitting"); log.error(ex.what()); @@ -65,8 +71,7 @@ private: EnggDiffFittingPresenter *m_pres; /// sample run to process - const int m_runNumber; - const size_t m_bank; + const std::vector<std::pair<int, size_t>> m_runNumberBankPairs; // parameters for fitting, list of peaks const std::string m_expectedPeaks; }; diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.cpp b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.cpp index 4a90eab4eaa92e0b50f39e999f0f60ce81e6fc98..58f440e8060f1725eda1af331a32432c16db39f6 100644 --- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.cpp +++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.cpp @@ -1,11 +1,11 @@ #include "EnggDiffFittingPresenter.h" +#include "EnggDiffFittingPresWorker.h" +#include "IEnggDiffFittingModel.h" #include "MantidAPI/Axis.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidAPI/Run.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidQtWidgets/LegacyQwt/QwtHelper.h" -#include "IEnggDiffFittingModel.h" -#include "EnggDiffFittingPresWorker.h" #include <boost/algorithm/string.hpp> #include <boost/lexical_cast.hpp> @@ -85,8 +85,6 @@ std::string generateXAxisLabel(Mantid::Kernel::Unit_const_sptr unit) { } } -int EnggDiffFittingPresenter::g_fitting_runno_counter = 0; - /** * Constructs a presenter for a fitting tab/widget view, which has a * handle on the current calibration (produced and updated elsewhere). @@ -102,7 +100,8 @@ EnggDiffFittingPresenter::EnggDiffFittingPresenter( boost::shared_ptr<IEnggDiffractionParam> mainParam) : m_fittingFinishedOK(false), m_workerThread(nullptr), m_mainCalib(mainCalib), m_mainParam(mainParam), m_view(view), - m_model(std::move(model)), m_viewHasClosed(false) {} + m_model(std::move(model)), m_viewHasClosed(false), m_multiRunMode(false) { +} EnggDiffFittingPresenter::~EnggDiffFittingPresenter() { cleanup(); } @@ -143,10 +142,6 @@ void EnggDiffFittingPresenter::notify( processStart(); break; - case IEnggDiffFittingPresenter::FittingRunNo: - fittingRunNoChanged(); - break; - case IEnggDiffFittingPresenter::Load: processLoad(); break; @@ -196,12 +191,13 @@ EnggDiffFittingPresenter::outFilesUserDir(const std::string &addToDir) { } void EnggDiffFittingPresenter::startAsyncFittingWorker( - const int runNumber, const size_t bank, const std::string &expectedPeaks) { + const std::vector<std::pair<int, size_t>> &runNumberBankPairs, + const std::string &expectedPeaks) { delete m_workerThread; m_workerThread = new QThread(this); EnggDiffFittingWorker *worker = - new EnggDiffFittingWorker(this, runNumber, bank, expectedPeaks); + new EnggDiffFittingWorker(this, runNumberBankPairs, expectedPeaks); worker->moveToThread(m_workerThread); connect(m_workerThread, SIGNAL(started()), worker, SLOT(fitting())); @@ -238,15 +234,18 @@ void EnggDiffFittingPresenter::fittingFinished() { m_view->showStatus("Single peak fitting process finished. Ready"); + if (!m_view->listWidgetHasSelectedRow()) { + m_view->setFittingListWidgetCurrentRow(0); + } + + if (m_multiRunMode) { + m_model->addAllFitResultsToADS(); + m_model->addAllFittedPeaksToADS(); + } + try { // should now plot the focused workspace when single peak fitting // process fails - const auto listLabel = m_view->getFittingListWidgetCurrentValue(); - int runNumber; - size_t bank; - std::tie(runNumber, bank) = - runAndBankNumberFromListWidgetLabel(listLabel); - plotFitPeaksCurves(); } catch (std::runtime_error &re) { @@ -276,496 +275,32 @@ void EnggDiffFittingPresenter::fittingFinished() { m_view->showStatus( "Single peak fitting process did not complete successfully"); } - // Reset once whole process is completed - g_multi_run.clear(); // enable the GUI + m_view->enableFitAllButton(m_model->getNumFocusedWorkspaces() > 1); m_view->enableCalibrateFocusFitUserActions(true); -} - -// Fitting Tab Run Number & Bank handling here -void EnggDiffFittingPresenter::fittingRunNoChanged() { - - // receive the run number from the text-field - const std::string userPathInput = m_view->getFittingRunNo(); - - if (m_previousInput == userPathInput || userPathInput.empty()) { - // Short circuit the checks and skip any warnings - // or errors as the user has not changed anything - // just clicked the box. Additionally this resolves an - // issue where QT will return the cursor and produce a new - // warning when the current warning is closed - return; - } else { - m_previousInput = userPathInput; - } - - // file name - const Poco::Path pocoUserPathInput(userPathInput); - - std::vector<std::string> foundFullFilePaths; - - // returns empty if no directory is found - const std::string parsedUserInput = pocoUserPathInput.toString(); - - // split directory if 'ENGINX_' found by '_.' - std::vector<std::string> splitBaseName; - if (parsedUserInput.find(m_view->getCurrentInstrument() + "_") != - std::string::npos) { - boost::split(splitBaseName, parsedUserInput, boost::is_any_of("_.")); - } - - try { - // if input file is a directory and successfully splitBaseName - // or when default bank is set or changed, the text-field is updated with - // selected bank directory which would trigger this function again - if (pocoUserPathInput.isFile() && !splitBaseName.empty()) { - foundFullFilePaths = processFullPathInput(pocoUserPathInput); - // if given a multi-run - } else if (userPathInput.find("-") != std::string::npos) { - foundFullFilePaths = processMultiRun(userPathInput); - // try to process using single run - } else { - foundFullFilePaths = processSingleRun(userPathInput); - } - } catch (std::invalid_argument &ia) { - // If something went wrong stop and print error only - g_log.error("Failed to process user input. Error was: "); - g_log.error(ia.what()); - return; - } - - // if single or multi run-number - // set the text-field to directory here to the first in - // the vector if its not empty - if (foundFullFilePaths.empty()) { - m_view->userWarning( - "Error finding file(s)", - "Unable to find one or more files with a name matching the run" - " number or range input. Please check the files are present in" - " the focused output directory and the input is correct."); - } else if (!pocoUserPathInput.isFile()) { - // foundFiles is not empty and this is a directory - const std::string firstDir = foundFullFilePaths[0]; - m_view->setFittingRunNo(firstDir); - } -} - -/** - * Verifies and uses the user input path (i.e. a browsed file) - * to update drop down for available banks and various widgets on the GUI - * - * @param filePath The user entered file path as a Poco Path - * - * @return The full file path as a vector of strings to make this - * consistent with the other file processing methods - */ -std::vector<std::string> -EnggDiffFittingPresenter::processFullPathInput(const Poco::Path &filePath) { - - std::vector<std::string> foundRunNumbers; - std::vector<std::string> foundFullFilePaths; - - // Handle files the user browsed to separately - try { - foundRunNumbers = - getAllBrowsedFilePaths(filePath.toString(), foundFullFilePaths); - } catch (std::runtime_error &e) { - const std::string eMsg(e.what()); - g_log.error("Error loading browsed file: " + eMsg); - - m_view->userWarning( - "Run Number Not Found", - "The run number specified could not be located " - "in the focused output directory. Please check that the " - "correct directory is set for Output Folder under Focusing Settings " - "on the settings tab and that the input is correct"); - // Bring it back to a known state of 0 found - foundFullFilePaths.clear(); - return foundFullFilePaths; - } - - // Update UI to reflect found files - // Update the list of files found in the view - m_view->setFittingRunNumVec(foundFullFilePaths); - - const bool multiRunMode = m_view->getFittingMultiRunMode(); - const bool singleRunMode = m_view->getFittingSingleRunMode(); - // if not run mode or bank mode: to avoid recreating widgets - if (!multiRunMode && !singleRunMode) { - // Skips this step if it is multiple run because widget already - // updated - setRunNoItems(foundRunNumbers, false); - } - - return foundFullFilePaths; + m_multiRunMode = false; } void EnggDiffFittingPresenter::processSelectRun() { const auto listLabel = m_view->getFittingListWidgetCurrentValue(); - int runNumber; - size_t bank; - std::tie(runNumber, bank) = runAndBankNumberFromListWidgetLabel(listLabel); - - const auto ws = m_model->getFocusedWorkspace(runNumber, bank); - plotFocusedFile(false, ws); -} - -/** - * Takes the full path of a file which has been selected through - * browse, the run number the user has input and stores the - * full file paths of all files (specifically all banks) associated - * with that run number. Then updates the view to display all run - * numbers for multi-runs - * - * @param inputFullPath The user inputted path in the view - * @param foundFullFilePaths The full paths of all associated files found - * - * @return Vector of all run numbers for which a full file path was found - */ -std::vector<std::string> EnggDiffFittingPresenter::getAllBrowsedFilePaths( - const std::string &inputFullPath, - std::vector<std::string> &foundFullFilePaths) { - // to track the FittingRunnoChanged loop number - if (g_fitting_runno_counter == 0) { - g_multi_run_directories.clear(); - } - - g_fitting_runno_counter++; - - // Files take the form 'ENGINX_123456_focused_bank_1' so create - // a string similar to 'ENGINX_123456_focused_bank' to allow us - // to search for additional banks] - const std::string baseName = getBaseNameFromStr(inputFullPath); - const std::vector<std::string> splitBaseName = - splitFittingDirectory(baseName); - - // TODO look at removal of hard coded filename positions - // Produced <INST>_<RunNumber>_focused for subsequent lookup - const std::string baseFilenamePrefix = - splitBaseName[0] + "_" + splitBaseName[1] + "_" + splitBaseName[2]; - - Poco::Path pocoFullFilePath; - if (!pocoFullFilePath.tryParse(inputFullPath)) { - // File path isn't valid - m_view->userWarning("Bad file path entered", - "The entered file path could not " - " be opened. Please check the file and/or directory " - "exists."); - - throw std::runtime_error( - "The file path entered could not be parsed" - " this usually indicates a syntax error or bad path input"); - } - - const std::string workingDirectory = pocoFullFilePath.parent().toString(); - - // Find all files which match this baseFilenamePrefix - - // like a poor mans regular expression for files - if (!findFilePathFromBaseName(workingDirectory, baseFilenamePrefix, - foundFullFilePaths)) { - // I can't see this ever being thrown if the user is browsing to files but - // better to be safe and give an informative message - throw std::runtime_error("Could not find any files matching the generated" - " pattern: " + - baseFilenamePrefix); - } - - // Store the run number as found - std::vector<std::string> runNoVec; - runNoVec.push_back(splitBaseName[1]); - - return runNoVec; -} - -/** - * Processes a multi run input to the interface - * such as '12345-12350' by splitting it into '12345' to '12350' - * then calling enableMultiRun - * @param userInput The user input from the view - * - * @return List of found full file paths for the files specified - */ -std::vector<std::string> -EnggDiffFittingPresenter::processMultiRun(const std::string &userInput) { - - // Split user input into the first and last run number - std::vector<std::string> firstLastRunNoVec; - boost::split(firstLastRunNoVec, userInput, boost::is_any_of("-")); - - // Then store them in their own strings - std::string firstRun; - std::string lastRun; - if (!firstLastRunNoVec.empty()) { - firstRun = firstLastRunNoVec[0]; - lastRun = firstLastRunNoVec[1]; - - m_view->setFittingMultiRunMode(true); - } - return enableMultiRun(firstRun, lastRun); -} - -std::vector<std::string> EnggDiffFittingPresenter::processSingleRun( - const std::string &userInputBasename) { - - const auto focusDir = m_view->focusingDir(); - - // Check there is a folder to search for this file - // this will be changed to respect user directories as well later - if (focusDir.empty()) { - m_view->userWarning("Focus directory not set.", - "Please check that a valid directory is " - "set for Output Folder under Focusing Settings on the " - "settings tab. " - "Please try again"); - - m_view->enableFitAllButton(false); - } - - // Next check input is a run number only as this is currently all - // that we can handle - if (!isDigit(userInputBasename)) { - m_view->userWarning( - "Invalid Run Number", - "Invalid format of run number has been entered. There was" - " non-numeric digits present in the input. Please try again"); - m_view->enableFitAllButton(false); - throw std::invalid_argument("User input contained non-numeric characters"); - } - - if (userInputBasename.empty()) { - - m_view->userWarning("Invalid Run Number", - "Invalid format of run number has been entered. " - " The input was blank. Please try again"); - m_view->enableFitAllButton(false); - throw std::invalid_argument("User input was blank"); - } - - if (g_fitting_runno_counter == 0) { - g_multi_run_directories.clear(); - } - - // to track the FittingRunnoChanged loop number - g_fitting_runno_counter++; - - // Inform the view we are using single run mode - m_view->setFittingSingleRunMode(true); - - std::vector<std::string> foundFilePaths; - const bool wasFound = - findFilePathFromBaseName(focusDir, userInputBasename, foundFilePaths); - - if (!wasFound) { - // Skip all UI update code - return foundFilePaths; - } - - const bool fittingMultiRunMode = m_view->getFittingMultiRunMode(); - if (!fittingMultiRunMode) { - // Wrap the current run number in a vector and pass through - // We cant use an initializer list as MSVC doesn't support this yet - std::vector<std::string> strFocusedFileVector; - strFocusedFileVector.push_back(userInputBasename); - setRunNoItems(strFocusedFileVector, false); - } - - // Update the list of found runs shown in the view - m_view->setFittingRunNumVec(foundFilePaths); - - // add bank to the combo-box and list view - // recreates bank widget for every run (multi-run) depending on - // number of banks file found for given run number in folder - - return foundFilePaths; -} - -/** - * Finds the full file path (including extensions) for files that - * match the given base filename (without ext) in the given folder. - * - * @param directoryToSearch The directory to search for these files - * @param baseFileNamesToFind The base filename to find in this folder - * @param foundFullFilePath Holds the path of the files if one was found - * which matched the given base filename - * - * @return True if any files were found or false if none were - */ -bool EnggDiffFittingPresenter::findFilePathFromBaseName( - const std::string &directoryToSearch, - const std::string &baseFileNamesToFind, - std::vector<std::string> &foundFullFilePath) { - - bool found = false; - - // Ask for an iterator of all files/folders in 'directoryToSearch' - Poco::DirectoryIterator directoryIter; - Poco::DirectoryIterator directoryIterEnd; - - try { - directoryIter = directoryToSearch; - } catch (Poco::FileNotFoundException) { - // UNIX will throw if the directory is blank however Windows - // will continue then fail to find the file in a non existent - // directory - this ultimately results in the same thing. - return false; - } - - try { - // Walk through every file within that folder looking for required files - while (directoryIter != directoryIterEnd) { - - // Get files and not folders (don't recurse down) - if (directoryIter->isFile()) { - - // Store the full path so if we get a matching file we know its path - const std::string fullPathToCheck = directoryIter->path(); - - // Get base name e.g. (ENGINX0012345) - // Poco forces us to create a file from path to ask for base name - // There must be a better way of doing this - const Poco::Path PocoFileName = directoryIter->path(); - const std::string baseFileName = PocoFileName.getBaseName(); - - // Look for the user input by comparing the base name of the - // current file with the user input - if (baseFileName.find(baseFileNamesToFind) != std::string::npos) { - foundFullFilePath.emplace_back(fullPathToCheck); - found = true; - - // if only first loop in Fitting Runno then add directory - if (g_fitting_runno_counter == 1) { - g_multi_run_directories.push_back(fullPathToCheck); - } - } - } - ++directoryIter; - } - - } catch (std::runtime_error &re) { - m_view->userWarning("Invalid file", - "File not found in the following directory; " + - directoryToSearch + ". " + re.what()); - } - - return found; -} - -/** - * Tests the user input for a multi run is valid and generates - * all values between that range (e.g. 1-10 produces 1,2,3...) - * to then look up those runs in the focus directory and find - * their full file paths. Additionally it updates the GUI to reflect - * if all runs were found or not - * - * @param firstRun The first run number of the range as a string - * @param lastRun The last run number of the range as a string - * - * @return A vector containing all file paths which were found - */ -std::vector<std::string> -EnggDiffFittingPresenter::enableMultiRun(const std::string &firstRun, - const std::string &lastRun) { - - std::vector<std::string> fittingRunNoDirVec; - - // Perform input checks first - // Are both values either side of '-' the user input digits - if (!isDigit(firstRun) || !isDigit(lastRun)) { - m_view->userWarning("Invalid Run Number", - "Invalid format of multi-run number has been entered. " - "Please try again"); - m_view->enableFitAllButton(false); - throw std::invalid_argument("Both values are not numerical entries"); - } - - // Convert strings to integers for remainder of function - const int firstNum = std::stoi(firstRun); - const int lastNum = std::stoi(lastRun); - const size_t range = abs(lastNum - firstNum); - - // Cap the maximum number of runs we can process at 200 - constexpr size_t maximumNumberOfRuns = 200; - - if (range > maximumNumberOfRuns) { - m_view->userWarning("Range too large", - "The specified run number range is too large." - " A maximum of 200 entries can be processed a time."); - m_view->enableFitAllButton(false); - throw std::invalid_argument("Number of runs is greater than 200"); - } - - // By performing this check we can make optimizations and assumptions - // about the ordering of values - if (firstNum > lastNum) { - m_view->userWarning("Range not ascending", - "The range specified was not ascending. " - "The last run number needs to be" - " larger than the start run number"); - throw std::invalid_argument("Run range is not ascending"); - } - - std::string workingDirectory = m_view->focusingDir(); - - if (workingDirectory.empty()) { - m_view->userWarning("Invalid Input", - "Please check that a valid directory is " - "set for Output Folder under Focusing Settings on the " - "settings tab. " - "Please try again"); - throw std::invalid_argument("Focus directory not set correctly"); - } - - // --- All checks complete lets process the multi run input --- - - // Reserve the number of elements needed so we don't allocate multiple times - std::vector<std::string> RunNumberVec; - RunNumberVec.reserve(range); - - for (int i = firstNum; i <= lastNum; i++) { - // Populate vector with list of runs - RunNumberVec.push_back(std::to_string(i)); - } - - // clear previous directories set before findFilePathsFromBaseName - if (g_fitting_runno_counter == 0) { - g_multi_run_directories.clear(); - } - // to track the FittingRunnoChanged loop number - g_fitting_runno_counter++; - - // rewrite the vector of run number which is available - std::vector<std::string> foundRunNumber; - - bool foundAllRuns = true; + if (listLabel) { + int runNumber; + size_t bank; + std::tie(runNumber, bank) = runAndBankNumberFromListWidgetLabel(*listLabel); - for (const auto &runNumber : RunNumberVec) { - // Get full path for every run selected - std::vector<std::string> foundFileNames; - if (findFilePathFromBaseName(workingDirectory, runNumber, foundFileNames)) { - // Append those that were found with fittingRunNoDirVec - fittingRunNoDirVec.insert(fittingRunNoDirVec.end(), - foundFileNames.cbegin(), foundFileNames.cend()); + if (m_model->hasFittedPeaksForRun(runNumber, bank)) { + plotFitPeaksCurves(); } else { - // We couldn't find this one - set the flag and break out of loop - foundAllRuns = false; - break; + const auto ws = m_model->getFocusedWorkspace(runNumber, bank); + plotFocusedFile(m_model->hasFittedPeaksForRun(runNumber, bank), ws); } } - - if (foundAllRuns) { - setRunNoItems(RunNumberVec, true); - } else { - // Set the size to 0 as some were not found - fittingRunNoDirVec.clear(); - } - - return fittingRunNoDirVec; } void EnggDiffFittingPresenter::processStart() {} void EnggDiffFittingPresenter::processLoad() { - const std::string filenames = m_view->getFittingRunNo(); + const std::string filenames = m_view->getFocusedFileNames(); if (filenames.empty()) { m_view->userWarning("No file selected", "Please enter filename(s) to load"); return; @@ -797,6 +332,8 @@ void EnggDiffFittingPresenter::processLoad() { std::for_each( listWidgetLabels.begin(), listWidgetLabels.end(), [&](const std::string &listLabel) { m_view->addRunNoItem(listLabel); }); + + m_view->enableFitAllButton(m_model->getNumFocusedWorkspaces() > 1); } void EnggDiffFittingPresenter::processShutDown() { @@ -813,21 +350,27 @@ void EnggDiffFittingPresenter::processLogMsg() { } void EnggDiffFittingPresenter::processFitAllPeaks() { + m_multiRunMode = true; std::string fittingPeaks = m_view->getExpectedPeaksInput(); const std::string normalisedPeakCentres = stripExtraCommas(fittingPeaks); m_view->setPeakList(normalisedPeakCentres); + const auto workspaceLabels = m_model->getRunNumbersAndBankIDs(); + g_log.debug() << "Focused files found are: " << normalisedPeakCentres << '\n'; - for (const auto &dir : g_multi_run_directories) { - g_log.debug() << dir << '\n'; + for (const auto &workspaceLabel : workspaceLabels) { + g_log.debug() << listWidgetLabelFromRunAndBankNumber( + workspaceLabel.first, workspaceLabel.second) << '\n'; } - if (!g_multi_run_directories.empty()) { + if (!workspaceLabels.empty()) { - for (size_t i = 0; i < g_multi_run_directories.size(); i++) { + for (const auto &workspaceLabel : workspaceLabels) { + const int runNumber = workspaceLabel.first; + const size_t bank = workspaceLabel.second; try { - validateFittingInputs(g_multi_run_directories[i], + validateFittingInputs(m_model->getWorkspaceFilename(runNumber, bank), normalisedPeakCentres); } catch (std::invalid_argument &ia) { m_view->userWarning("Error in the inputs required for fitting", @@ -836,39 +379,33 @@ void EnggDiffFittingPresenter::processFitAllPeaks() { } } - const std::string outWSName = "engggui_fitting_fit_peak_ws"; g_log.notice() << "EnggDiffraction GUI: starting new multi-run " - "single peak fits into workspace '" + - outWSName + "'. This " - "may take some seconds... \n"; - + << "single peak fits. This may take some seconds...\n"; m_view->showStatus("Fitting multi-run single peaks..."); // disable GUI to avoid any double threads m_view->enableCalibrateFocusFitUserActions(false); m_view->enableFitAllButton(false); - // doFitting() - // WORK OUT WHAT TO DO HERE - // startAsyncFittingWorker(g_multi_run_directories, fitPeaksData); - + startAsyncFittingWorker(workspaceLabels, normalisedPeakCentres); } else { m_view->userWarning("Error in the inputs required for fitting", - "Invalid files have been selected for Fit All process"); - m_view->enableFitAllButton(false); + "No runs were loaded for fitting"); } } void EnggDiffFittingPresenter::processFitPeaks() { - if (!m_view->listWidgetHasSelectedRow()) { + const auto listLabel = m_view->getFittingListWidgetCurrentValue(); + + if (!listLabel) { m_view->userWarning("No run selected", "Please select a run to fit from the list"); return; } - const auto listLabel = m_view->getFittingListWidgetCurrentValue(); + int runNumber; size_t bank; - std::tie(runNumber, bank) = runAndBankNumberFromListWidgetLabel(listLabel); + std::tie(runNumber, bank) = runAndBankNumberFromListWidgetLabel(*listLabel); std::string fittingPeaks = m_view->getExpectedPeaksInput(); const std::string normalisedPeakCentres = stripExtraCommas(fittingPeaks); @@ -897,7 +434,8 @@ void EnggDiffFittingPresenter::processFitPeaks() { // disable GUI to avoid any double threads m_view->enableCalibrateFocusFitUserActions(false); - startAsyncFittingWorker(runNumber, bank, normalisedPeakCentres); + startAsyncFittingWorker({std::make_pair(runNumber, bank)}, + normalisedPeakCentres); } void EnggDiffFittingPresenter::validateFittingInputs( @@ -928,25 +466,6 @@ void EnggDiffFittingPresenter::validateFittingInputs( } } -/** -* Splits the file name in to sections of '_' and 'ENGINX' text -* within the filename -* -* @param selectedfPath is the selected file's path -* -* @return std::vector<std::string> of splitted file name with run -* number & bank -*/ -std::vector<std::string> EnggDiffFittingPresenter::splitFittingDirectory( - const std::string &selectedfPath) { - - Poco::Path PocofPath(selectedfPath); - std::string selectedbankfName = PocofPath.getBaseName(); - std::vector<std::string> splitBaseName; - boost::split(splitBaseName, selectedbankfName, boost::is_any_of("_.")); - return splitBaseName; -} - void EnggDiffFittingPresenter::doFitting(const int runNumber, const size_t bank, const std::string &expectedPeaks) { g_log.notice() << "EnggDiffraction GUI: starting new fitting with run " @@ -1090,61 +609,6 @@ void EnggDiffFittingPresenter::fittingWriteFile(const std::string &fileDir) { } } -void EnggDiffFittingPresenter::setRunNoItems( - const std::vector<std::string> &runNumVector, bool multiRun) { - try { - if (!runNumVector.empty()) { - - // delete previous run number added to the list - m_view->clearFittingListWidget(); - - // enable fit button only when run number provided - m_view->enableFitAllButton(true); - - for (size_t i = 0; i < runNumVector.size(); i++) { - - std::string currentRun = (runNumVector[i]); - - // adding to widget - m_view->addRunNoItem(currentRun); - g_multi_run.push_back(currentRun); - } - - // change to selected run number item - if (multiRun) { - m_view->enableFittingListWidget(true); - - auto currentIndex = m_view->getFittingListWidgetCurrentRow(); - if (currentIndex == -1) - m_view->setFittingListWidgetCurrentRow(0); - } else { - m_view->enableFittingListWidget(false); - } - } - - else { - // upon invalid file - // disable the widgets when only one related file found - m_view->enableFittingListWidget(false); - m_view->enableFitAllButton(false); - m_view->clearFittingListWidget(); - - m_view->userWarning( - "Run Number Not Found", - "The run number specified could not be located " - "in the focused output directory. Please check that the " - "correct directory is set for Output Folder under Focusing Settings " - "on the settings tab."); - } - - } catch (std::runtime_error &re) { - m_view->userWarning("Unable to insert items: ", - "Could not add list widget; " + - static_cast<std::string>(re.what()) + - ". Please try again"); - } -} - bool EnggDiffFittingPresenter::isDigit(const std::string &text) const { return std::all_of(text.cbegin(), text.cend(), ::isdigit); } @@ -1199,9 +663,14 @@ void EnggDiffFittingPresenter::plotFitPeaksCurves() { m_view->resetCanvas(); const auto listLabel = m_view->getFittingListWidgetCurrentValue(); + if (!listLabel) { + m_view->userWarning("Invalid run number or bank", + "Tried to plot a focused file which does not exist"); + return; + } int runNumber; size_t bank; - std::tie(runNumber, bank) = runAndBankNumberFromListWidgetLabel(listLabel); + std::tie(runNumber, bank) = runAndBankNumberFromListWidgetLabel(*listLabel); const auto ws = m_model->getAlignedWorkspace(runNumber, bank); // plots focused workspace diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.h b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.h index fb6e72d6124b1e4adbbd0b37705fd4587eb730bb..fac5c57504bbdfe00b4006e11faea57d3c3a50dd 100644 --- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.h +++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.h @@ -80,9 +80,6 @@ public: void plotFitPeaksCurves(); - void setRunNoItems(const std::vector<std::string> &runNumVector, - bool multiRun); - protected: void processStart(); void processLoad(); @@ -97,7 +94,6 @@ protected: protected slots: void fittingFinished(); - void fittingRunNoChanged(); private: bool isDigit(const std::string &text) const; @@ -105,25 +101,15 @@ private: void warnFileNotFound(const std::exception &ex); // Methods related single peak fits - virtual void startAsyncFittingWorker(const int runNumber, const size_t bank, - const std::string &expectedPeaks); + virtual void startAsyncFittingWorker( + const std::vector<std::pair<int, size_t>> &runNumberBankPairs, + const std::string &expectedPeaks); std::string getBaseNameFromStr(const std::string &filePath) const; void validateFittingInputs(const std::string &focusedRunNo, const std::string &expectedPeaks); - // TODO make this const when the global is removed - bool findFilePathFromBaseName(const std::string &directoryToSearch, - const std::string &baseFileNamesToFind, - std::vector<std::string> &foundFullFilePath); - - std::vector<std::string> - splitFittingDirectory(const std::string &selectedfPath); - - std::vector<std::string> enableMultiRun(const std::string &firstRun, - const std::string &lastRun); - void browsePeaksToFit(); void addPeakToList(); @@ -134,34 +120,12 @@ private: void fittingWriteFile(const std::string &fileDir); - std::vector<std::string> - getAllBrowsedFilePaths(const std::string &inputFullPath, - std::vector<std::string> &foundFullFilePaths); - - std::vector<std::string> processMultiRun(const std::string &userInput); - - std::vector<std::string> - processSingleRun(const std::string &userInputBasename); - - std::vector<std::string> processFullPathInput(const Poco::Path &pocoFilePath); - - static int g_fitting_runno_counter; - - // name of the workspace with the focused ws being used for fitting - static const std::string g_focusedFittingWSName; - - // input run number - used for output file name - std::vector<std::string> g_multi_run; - // Holds the previous user input so we can short circuit further checks std::string m_previousInput; /// true if the last fitting completed successfully bool m_fittingFinishedOK; - // directories of all the run numbers when multi-run option - std::vector<std::string> g_multi_run_directories; - QThread *m_workerThread; /// interface for the 'current' calibration @@ -181,6 +145,9 @@ private: /// Handle the user selecting a different run to plot void processSelectRun(); + + /// Whether the user is doing fitting on multiple runs + bool m_multiRunMode; }; } // namespace CustomInterfaces diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.cpp b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.cpp index 1b9bd973d2869d03cac5ccb50a5f28ed8936255b..ea8e973b8a5db1584603c498c204251b59ea1a75 100644 --- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.cpp +++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.cpp @@ -93,13 +93,6 @@ void EnggDiffFittingViewQtWidget::doSetup() { connect(m_ui.lineEdit_pushButton_run_num, SIGNAL(returnPressed()), this, SLOT(loadClicked())); - connect(this, SIGNAL(getBanks()), this, SLOT(FittingRunNo())); - - connect(this, SIGNAL(setBank()), this, SLOT(listViewFittingRun())); - - connect(m_ui.listWidget_fitting_run_num, SIGNAL(itemSelectionChanged()), this, - SLOT(listViewFittingRun())); - connect(m_ui.pushButton_fitting_browse_peaks, SIGNAL(released()), this, SLOT(browseClicked())); @@ -234,10 +227,6 @@ void EnggDiffFittingViewQtWidget::fitAllClicked() { m_presenter->notify(IEnggDiffFittingPresenter::FitAllPeaks); } -void EnggDiffFittingViewQtWidget::FittingRunNo() { - m_presenter->notify(IEnggDiffFittingPresenter::FittingRunNo); -} - void EnggDiffFittingViewQtWidget::addClicked() { m_presenter->notify(IEnggDiffFittingPresenter::addPeaks); } @@ -250,32 +239,6 @@ void EnggDiffFittingViewQtWidget::saveClicked() { m_presenter->notify(IEnggDiffFittingPresenter::savePeaks); } -void EnggDiffFittingViewQtWidget::setBankDir(int idx) { - - const size_t runNoDirSize = m_fitting_runno_dir_vec.size(); - // idx must correspond to an element and the vector cant be empty - if (size_t(idx) < runNoDirSize && runNoDirSize > 0) { - - std::string bankDir = m_fitting_runno_dir_vec[idx]; - Poco::Path fpath(bankDir); - - setFittingRunNo(bankDir); - } -} - -void EnggDiffFittingViewQtWidget::listViewFittingRun() { - - if (m_fittingMutliRunMode) { - auto listView = m_ui.listWidget_fitting_run_num; - auto currentRow = listView->currentRow(); - auto item = listView->item(currentRow); - QString itemText = item->text(); - - setFittingRunNo(itemText.toStdString()); - FittingRunNo(); - } -} - void EnggDiffFittingViewQtWidget::listWidget_fitting_run_num_clicked( QListWidgetItem *clickedItem) { const auto label = clickedItem->text(); @@ -474,16 +437,15 @@ void EnggDiffFittingViewQtWidget::browseFitFocusedRun() { return; } - // MantidQt::API::AlgorithmInputHistory::Instance().setPreviousDirectory(paths[0]); - setFittingRunNo(paths.join(",").toStdString()); - // getBanks(); + setFocusedFileNames(paths.join(",").toStdString()); } -void EnggDiffFittingViewQtWidget::setFittingRunNo(const std::string &path) { - m_ui.lineEdit_pushButton_run_num->setText(QString::fromStdString(path)); +void EnggDiffFittingViewQtWidget::setFocusedFileNames( + const std::string &paths) { + m_ui.lineEdit_pushButton_run_num->setText(QString::fromStdString(paths)); } -std::string EnggDiffFittingViewQtWidget::getFittingRunNo() const { +std::string EnggDiffFittingViewQtWidget::getFocusedFileNames() const { return m_ui.lineEdit_pushButton_run_num->text().toStdString(); } @@ -503,9 +465,12 @@ int EnggDiffFittingViewQtWidget::getFittingListWidgetCurrentRow() const { return m_ui.listWidget_fitting_run_num->currentRow(); } -std::string +boost::optional<std::string> EnggDiffFittingViewQtWidget::getFittingListWidgetCurrentValue() const { - return m_ui.listWidget_fitting_run_num->currentItem()->text().toStdString(); + if (listWidgetHasSelectedRow()) { + return m_ui.listWidget_fitting_run_num->currentItem()->text().toStdString(); + } + return boost::none; } bool EnggDiffFittingViewQtWidget::listWidgetHasSelectedRow() const { diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h index 920069365ea4a95888b4621ca7be359b9474ff34..89bc6b600821fad94c19b146669433e309cc8797 100644 --- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h +++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingViewQtWidget.h @@ -89,9 +89,9 @@ public: std::vector<std::string> logMsgs() const override { return m_logMsgs; } - void setFittingRunNo(const std::string &path) override; + void setFocusedFileNames(const std::string &paths) override; - std::string getFittingRunNo() const override; + std::string getFocusedFileNames() const override; void enableFitAllButton(bool enable) const override; @@ -101,7 +101,8 @@ public: int getFittingListWidgetCurrentRow() const override; - std::string getFittingListWidgetCurrentValue() const override; + boost::optional<std::string> + getFittingListWidgetCurrentValue() const override; bool listWidgetHasSelectedRow() const override; @@ -176,14 +177,11 @@ private slots: void loadClicked(); void fitClicked(); void fitAllClicked(); - void FittingRunNo(); void addClicked(); void browseClicked(); void saveClicked(); void plotSeparateWindow(); void showToolTipHelp(); - void setBankDir(int idx); - void listViewFittingRun(); void listWidget_fitting_run_num_clicked(QListWidgetItem *listWidget); private: diff --git a/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingModel.h b/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingModel.h index ac9cc49425f3920971e11561242f32bf67bb1700..75dd6c5ff5d0ad509382a464c90814375b198269 100644 --- a/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingModel.h +++ b/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingModel.h @@ -47,6 +47,15 @@ public: const std::string &filename) const = 0; virtual void createFittedPeaksWS(const int runNumber, const size_t bank) = 0; + + virtual size_t getNumFocusedWorkspaces() const = 0; + + virtual void addAllFitResultsToADS() const = 0; + + virtual void addAllFittedPeaksToADS() const = 0; + + virtual bool hasFittedPeaksForRun(const int runNumber, + const size_t bank) const = 0; }; } // namespace MantidQt diff --git a/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingPresenter.h b/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingPresenter.h index 8c5d25fd1c42f84a9168994e56e7faf43188ea6b..b4feb86ea796b4b48241f163b46762a588fd3cb4 100644 --- a/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingPresenter.h +++ b/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingPresenter.h @@ -42,17 +42,16 @@ public: /// These are user actions, triggered from the (passive) view, that need /// handling by the presenter enum Notification { - Start, ///< Start and setup interface - FittingRunNo, ///< Creates widgets and handles multi/run numbers - Load, ///< Load the focused file to the canvas - FitPeaks, ///< Preforms single peak fits - FitAllPeaks, ///< Preforms multiple runs in sequence single peak fits - addPeaks, ///< Adds peak to the list - browsePeaks, ///< Browse peaks to the list - savePeaks, ///< Save the peaks list - ShutDown, ///< closing the interface - LogMsg, ///< need to send a message to the Mantid log system - selectRun, ///< update plot with new run selected from list widget + Start, ///< Start and setup interface + Load, ///< Load the focused file to the canvas + FitPeaks, ///< Preforms single peak fits + FitAllPeaks, ///< Preforms multiple runs in sequence single peak fits + addPeaks, ///< Adds peak to the list + browsePeaks, ///< Browse peaks to the list + savePeaks, ///< Save the peaks list + ShutDown, ///< closing the interface + LogMsg, ///< need to send a message to the Mantid log system + selectRun, ///< update plot with new run selected from list widget }; /** diff --git a/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingView.h b/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingView.h index a0b5a7bc9708eacb21246104770976d804c267c2..0a6e94ba927da53912e8981cba387c96276569d4 100644 --- a/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingView.h +++ b/qt/scientific_interfaces/EnggDiffraction/IEnggDiffFittingView.h @@ -9,6 +9,7 @@ #include <string> #include <vector> +#include <boost/optional.hpp> class QwtData; @@ -51,11 +52,12 @@ public: virtual ~IEnggDiffFittingView() = default; /** - * returns directory of the file name to preform fitting on + * Get value of the input files text box * - * @return directory as std::string + * @return (hopefully) comma-separated list of focused files to load for + * fitting */ - virtual std::string getFittingRunNo() const = 0; + virtual std::string getFocusedFileNames() const = 0; /** * A list of dSpacing values to be translated into TOF @@ -155,7 +157,8 @@ public: /** * @return The text on the current selected row of the list widget */ - virtual std::string getFittingListWidgetCurrentValue() const = 0; + virtual boost::optional<std::string> + getFittingListWidgetCurrentValue() const = 0; /** * @return Whether the list widget currently has an item selected @@ -170,11 +173,11 @@ public: virtual void setFittingListWidgetCurrentRow(int idx) const = 0; /** - * sets the fitting run number according to path + * Set value of the text box for input filenames * - * @param path of the selected focused run file + * @param path Comma-separated list of files to add */ - virtual void setFittingRunNo(const std::string &path) = 0; + virtual void setFocusedFileNames(const std::string &path) = 0; /** * gets the global vector in view containing focused file directory diff --git a/qt/scientific_interfaces/test/EnggDiffFittingModelMock.h b/qt/scientific_interfaces/test/EnggDiffFittingModelMock.h index 7804bee1797f949b95afd2e6eba9e1b3e1ccc234..a1beceaf42ba80227a9e889c0d79f1c3e89f702c 100644 --- a/qt/scientific_interfaces/test/EnggDiffFittingModelMock.h +++ b/qt/scientific_interfaces/test/EnggDiffFittingModelMock.h @@ -55,8 +55,17 @@ public: MOCK_METHOD2(createFittedPeaksWS, void(const int runNumber, const size_t bank)); + + MOCK_CONST_METHOD0(getNumFocusedWorkspaces, size_t()); + + MOCK_CONST_METHOD0(addAllFitResultsToADS, void()); + + MOCK_CONST_METHOD0(addAllFittedPeaksToADS, void()); + + MOCK_CONST_METHOD2(hasFittedPeaksForRun, + bool(const int runNumber, const size_t bank)); }; GCC_DIAG_ON_SUGGEST_OVERRIDE -#endif // MANTID_CUSTOM_INTERFACES_ENGGDIFFFITTINGMODELMOCK_H \ No newline at end of file +#endif // MANTID_CUSTOM_INTERFACES_ENGGDIFFFITTINGMODELMOCK_H diff --git a/qt/scientific_interfaces/test/EnggDiffFittingModelTest.h b/qt/scientific_interfaces/test/EnggDiffFittingModelTest.h index 2c953c450cc14437b4c4f528918102d264de7f1c..7728152d21767483e989c7b24f0acbc392896588 100644 --- a/qt/scientific_interfaces/test/EnggDiffFittingModelTest.h +++ b/qt/scientific_interfaces/test/EnggDiffFittingModelTest.h @@ -30,6 +30,9 @@ public: void addFitParams(const int runNumber, const size_t bank, Mantid::API::ITableWorkspace_sptr ws); + + void mergeTablesExposed(API::ITableWorkspace_sptr tableToCopy, + API::ITableWorkspace_sptr targetTable); }; inline void EnggDiffFittingModelAddWSExposed::addWorkspace( @@ -44,6 +47,12 @@ inline void EnggDiffFittingModelAddWSExposed::addFitParams( addFitResults(runNumber, bank, ws); } +inline void EnggDiffFittingModelAddWSExposed::mergeTablesExposed( + API::ITableWorkspace_sptr tableToCopy, + API::ITableWorkspace_sptr targetTable) { + mergeTables(tableToCopy, targetTable); +} + void addSampleWorkspaceToModel(const int runNumber, const int bank, EnggDiffFittingModelAddWSExposed &model) { API::MatrixWorkspace_sptr ws = @@ -99,6 +108,23 @@ API::ITableWorkspace_sptr createFitParamsTable() { return table; } +template <size_t numColumns, size_t numRows> +API::ITableWorkspace_sptr createDummyTable( + const std::array<std::string, numColumns> &columnHeadings, + const std::array<std::array<double, numColumns>, numRows> tableContents) { + auto table = API::WorkspaceFactory::Instance().createTable(); + for (const auto &header : columnHeadings) { + table->addColumn("double", header); + } + for (const auto &row : tableContents) { + API::TableRow newRow = table->appendRow(); + for (const auto value : row) { + newRow << value; + } + } + return table; +} + } // anonymous namespace class EnggDiffFittingModelTest : public CxxTest::TestSuite { @@ -187,6 +213,59 @@ public: TS_ASSERT_EQUALS(fittedPeaksWS->getNumberHistograms(), 4); } + void test_getNumFocusedWorkspaces() { + auto model = EnggDiffFittingModelAddWSExposed(); + + addSampleWorkspaceToModel(123, 1, model); + addSampleWorkspaceToModel(456, 2, model); + addSampleWorkspaceToModel(789, 1, model); + + TS_ASSERT_EQUALS(model.getNumFocusedWorkspaces(), 3); + } + + void test_mergeTables() { + auto model = EnggDiffFittingModelAddWSExposed(); + + const size_t numberOfColumns = 3; + const size_t numberOfRows = 2; + + const std::array<std::string, numberOfColumns> columnHeadings = { + {"X", "Y", "Z"}}; + + const std::array<std::array<double, numberOfColumns>, numberOfRows> + targetTableValues = {{{{1, 2, 3}}, {{4, 5, 6}}}}; + + auto targetTable = createDummyTable(columnHeadings, targetTableValues); + + const std::array<std::array<double, numberOfColumns>, numberOfRows> + copyTableValues = {{{{7, 8, 9}}, {{10, 11, 12}}}}; + + auto copyTable = createDummyTable(columnHeadings, copyTableValues); + + TS_ASSERT_THROWS_NOTHING(model.mergeTablesExposed(copyTable, targetTable)); + + TS_ASSERT_EQUALS(targetTable->columnCount(), numberOfColumns); + TS_ASSERT_EQUALS(targetTable->rowCount(), numberOfRows * 2); + + for (size_t rowIndex = 0; rowIndex < numberOfRows * 2; ++rowIndex) { + std::cout << "ROW " << rowIndex << "\n"; + API::TableRow row = targetTable->getRow(rowIndex); + const double expectedX = static_cast<double>(rowIndex) * 3 + 1; + const double expectedY = static_cast<double>(rowIndex) * 3 + 2; + const double expectedZ = static_cast<double>(rowIndex) * 3 + 3; + + // x, y and z must be initialized to keep RHEL7 happy + auto x = expectedX + 1; + auto y = expectedY + 1; + auto z = expectedZ + 1; + + TS_ASSERT_THROWS_NOTHING(row >> x >> y >> z); + TS_ASSERT_EQUALS(x, expectedX); + TS_ASSERT_EQUALS(y, expectedY); + TS_ASSERT_EQUALS(z, expectedZ); + } + } + private: const static std::string FOCUSED_WS_FILENAME; const static int FOCUSED_WS_RUN_NUMBER; diff --git a/qt/scientific_interfaces/test/EnggDiffFittingPresenterTest.h b/qt/scientific_interfaces/test/EnggDiffFittingPresenterTest.h index 9d4471766a1a0b39cdb861c55a1350f2bfd550dd..a5e0bab0b4338db3f871707d325f3d1c03c4a4be 100644 --- a/qt/scientific_interfaces/test/EnggDiffFittingPresenterTest.h +++ b/qt/scientific_interfaces/test/EnggDiffFittingPresenterTest.h @@ -1,10 +1,10 @@ #ifndef MANTID_CUSTOMINTERFACES_ENGGDIFFFITTINGPRESENTERTEST_H #define MANTID_CUSTOMINTERFACES_ENGGDIFFFITTINGPRESENTERTEST_H +#include "../EnggDiffraction/EnggDiffFittingPresenter.h" #include "MantidAPI/FrameworkManager.h" #include "MantidKernel/make_unique.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" -#include "../EnggDiffraction/EnggDiffFittingPresenter.h" #include "EnggDiffFittingModelMock.h" #include "EnggDiffFittingViewMock.h" @@ -33,8 +33,12 @@ public: private: // not async at all - void startAsyncFittingWorker(const int runNumber, const size_t bank, - const std::string &ExpectedPeaks) override { + void startAsyncFittingWorker( + const std::vector<std::pair<int, size_t>> &runNumberBankPairs, + const std::string &ExpectedPeaks) override { + assert(runNumberBankPairs.size() == 1); + const auto runNumber = runNumberBankPairs[0].first; + const auto bank = runNumberBankPairs[0].second; doFitting(runNumber, bank, ExpectedPeaks); fittingFinished(); } @@ -105,7 +109,7 @@ public: MantidQt::CustomInterfaces::EnggDiffFittingPresenter pres( &mockView, std::move(mockModel), nullptr, nullptr); - EXPECT_CALL(mockView, getFittingRunNo()).Times(1).WillOnce(Return("")); + EXPECT_CALL(mockView, getFocusedFileNames()).Times(1).WillOnce(Return("")); EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); @@ -131,9 +135,9 @@ public: MantidQt::CustomInterfaces::EnggDiffFittingPresenter pres( &mockView, std::move(mockModel), nullptr, nullptr); - EXPECT_CALL(mockView, listWidgetHasSelectedRow()) + EXPECT_CALL(mockView, getFittingListWidgetCurrentValue()) .Times(1) - .WillOnce(Return(false)); + .WillOnce(Return(boost::none)); // should not get to the point where the status is updated EXPECT_CALL(mockView, setPeakList(testing::_)).Times(0); @@ -157,9 +161,9 @@ public: EnggDiffFittingPresenterNoThread pres(&mockView); // inputs from user - EXPECT_CALL(mockView, listWidgetHasSelectedRow()) + EXPECT_CALL(mockView, getFittingListWidgetCurrentValue()) .Times(1) - .WillOnce(Return(false)); + .WillOnce(Return(boost::none)); // should not get to the point where the status is updated EXPECT_CALL(mockView, setPeakList(testing::_)).Times(0); @@ -186,12 +190,10 @@ public: EnggDiffFittingPresenterNoThread pres(&mockView, std::move(mockModel)); - EXPECT_CALL(mockView, listWidgetHasSelectedRow()) - .Times(1) - .WillOnce(Return(true)); EXPECT_CALL(mockView, getFittingListWidgetCurrentValue()) .Times(1) - .WillOnce(Return("123_1")); + .WillOnce(Return(boost::optional<std::string>( + boost::optional<std::string>("123_1")))); EXPECT_CALL(*mockModel_ptr, getWorkspaceFilename(testing::_, testing::_)) .Times(1) .WillOnce(Return("")); @@ -219,197 +221,27 @@ public: testing::Mock::VerifyAndClearExpectations(mockModel_ptr)) } - // Fitting test begin here - void test_fitting_runno_valid_single_run() { - testing::NiceMock<MockEnggDiffFittingView> mockView; - EnggDiffFittingPresenterNoThread pres(&mockView); - - // inputs from user - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(1) - .WillRepeatedly(Return(std::string(g_focusedBankFile))); - - EXPECT_CALL(mockView, getFittingRunNumVec()).Times(0); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - - // No errors/0 warnings. There will be no errors or warnings - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(2); - - pres.notify(IEnggDiffFittingPresenter::FittingRunNo); - } - - void test_fitting_runno_invalid_run() { - testing::NiceMock<MockEnggDiffFittingView> mockView; - EnggDiffFittingPresenterNoThread pres(&mockView); - - // inputs from user - invalid run given this can't be numerical - // only as that has the chance of matching a file so use a prefix - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(1) - .WillOnce(Return(std::string("ENGINX1"))); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - EXPECT_CALL(mockView, getFittingRunNumVec()).Times(0); - - // No errors/1 warnings. There will be an warning for invalid run number - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(2); - - pres.notify(IEnggDiffFittingPresenter::FittingRunNo); - } - - void test_fitting_with_blank_input() { - testing::StrictMock<MockEnggDiffFittingView> mockView; - EnggDiffFittingPresenterNoThread pres(&mockView); - - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(1) - .WillOnce(Return(std::string(""))); - - pres.notify(IEnggDiffFittingPresenter::FittingRunNo); - - testing::Mock::VerifyAndClearExpectations(&mockView); - } - - void test_fitting_file_not_found_with_multiple_runs() { - testing::NiceMock<MockEnggDiffFittingView> mockView; - EnggDiffFittingPresenterNoThread pres(&mockView); - // 23931-23934 - std::vector<std::string> RunNumDir; - RunNumDir.emplace_back("241391"); - RunNumDir.emplace_back("241392"); - RunNumDir.emplace_back("241393"); - RunNumDir.emplace_back("241394"); - - // empty vector - std::vector<std::string> splittedFileVec; - - // inputs from user - given multiple run - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(1) - .WillOnce(Return(g_focusedFittingRunNo)); - - EXPECT_CALL(mockView, getFittingRunNumVec()).Times(0); - - // SplitFittingDir() - - // could possibly feature to create unique path - EXPECT_CALL(mockView, focusingDir()).Times(1); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - - // No errors/1 warnings. The warning will be produced because there - // is no focus output directory within the settings tab - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); - - pres.notify(IEnggDiffFittingPresenter::FittingRunNo); - } - - void diable_test_fitting_runno_single_run() { - testing::NiceMock<MockEnggDiffFittingView> mockView; - EnggDiffFittingPresenterNoThread pres(&mockView); - - // focus directory need to be set for this in the settings - - // 23931-23934 - std::vector<std::string> RunNumDir; - RunNumDir.emplace_back("241391"); - - // empty vector - std::vector<std::string> splittedFileVec; - - // inputs from user - given multiple run - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(2) - .WillRepeatedly(Return("241391")); - - EXPECT_CALL(mockView, getFittingRunNumVec()) - .Times(1) - .WillOnce(Return(RunNumDir)); - - EXPECT_CALL(mockView, getFittingMultiRunMode()) - .Times(1) - .WillOnce(Return(false)); - - EXPECT_CALL(mockView, setFittingRunNumVec(testing::_)).Times(1); - - EXPECT_CALL(mockView, addRunNoItem(testing::_)).Times(1); - - EXPECT_CALL(mockView, addBankItem(testing::_)).Times(1); - - EXPECT_CALL(mockView, focusingDir()).Times(0); - - // should not get to the point where the status is updated - EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); - - // No errors/0 warnings. - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0); - - pres.notify(IEnggDiffFittingPresenter::FittingRunNo); - } - - void test_fitting_runno_browsed_run_add_run_item() { - testing::NiceMock<MockEnggDiffFittingView> mockView; - EnggDiffFittingPresenterNoThread pres(&mockView); - // Tests the browse directory file - std::vector<std::string> RunNumDir; - RunNumDir.emplace_back("241395"); - - std::vector<std::string> splittedFileVec; - splittedFileVec.emplace_back("ENGINX"); - splittedFileVec.emplace_back("241395"); - splittedFileVec.emplace_back("focused"); - splittedFileVec.emplace_back("bank"); - splittedFileVec.emplace_back("1"); - - // inputs from user - given multiple run - EXPECT_CALL(mockView, getFittingRunNo()) - .Times(1) - .WillOnce(Return(g_focusedBankFile)); - - EXPECT_CALL(mockView, getFittingRunNumVec()).Times(0); - - EXPECT_CALL(mockView, getFittingMultiRunMode()).Times(0); - - EXPECT_CALL(mockView, setFittingRunNumVec(testing::_)).Times(0); - - EXPECT_CALL(mockView, addBankItem(testing::_)).Times(0); - - EXPECT_CALL(mockView, setBankIdComboBox(testing::_)).Times(0); - - EXPECT_CALL(mockView, addRunNoItem(testing::_)).Times(0); - - EXPECT_CALL(mockView, setFittingListWidgetCurrentRow(testing::_)).Times(0); - - EXPECT_CALL(mockView, focusingDir()).Times(0); - - // No errors/1 warnings. File entered is not found - EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); - EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(2); - - pres.notify(IEnggDiffFittingPresenter::FittingRunNo); - } - // Fit All Peaks test begin here void test_fit_all_runno_valid_single_run() { testing::NiceMock<MockEnggDiffFittingView> mockView; - EnggDiffFittingPresenterNoThread pres(&mockView); + auto mockModel = Mantid::Kernel::make_unique< + testing::NiceMock<MockEnggDiffFittingModel>>(); + auto *mockModel_ptr = mockModel.get(); + + EnggDiffFittingPresenterNoThread pres(&mockView, std::move(mockModel)); - EXPECT_CALL(mockView, getFittingRunNo()).Times(0); EXPECT_CALL(mockView, getExpectedPeaksInput()) .Times(1) .WillOnce(Return("2.3445,3.3433,4.5664")); + EXPECT_CALL(*mockModel_ptr, getRunNumbersAndBankIDs()) + .Times(1) + .WillOnce(Return( + std::vector<std::pair<int, size_t>>({std::make_pair(123, 1)}))); + EXPECT_CALL(mockView, setPeakList(testing::_)).Times(1); - EXPECT_CALL(mockView, enableFitAllButton(testing::_)).Times(1); + EXPECT_CALL(mockView, enableFitAllButton(testing::_)).Times(0); // should not get to the point where the status is updated EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); @@ -425,9 +257,12 @@ public: // This would test the fitting tab with invalid expected peaks but should only // produce a warning void test_fit_all_with_invalid_expected_peaks() { - return; // EARLY RETURN, AS FIT ALL IS NOT YET ENABLED testing::NiceMock<MockEnggDiffFittingView> mockView; - EnggDiffFittingPresenterNoThread pres(&mockView); + auto mockModel = Mantid::Kernel::make_unique< + testing::NiceMock<MockEnggDiffFittingModel>>(); + auto *mockModel_ptr = mockModel.get(); + + EnggDiffFittingPresenterNoThread pres(&mockView, std::move(mockModel)); // inputs from user EXPECT_CALL(mockView, getExpectedPeaksInput()) @@ -435,6 +270,11 @@ public: .WillOnce(Return(",3.5,7.78,r43d")); EXPECT_CALL(mockView, setPeakList(testing::_)).Times(1); + EXPECT_CALL(*mockModel_ptr, getRunNumbersAndBankIDs()) + .Times(1) + .WillOnce(Return( + std::vector<std::pair<int, size_t>>({std::make_pair(123, 1)}))); + // should not get to the point where the status is updated EXPECT_CALL(mockView, showStatus(testing::_)).Times(0); @@ -442,7 +282,7 @@ public: EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0); EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1); - pres.notify(IEnggDiffFittingPresenter::FitPeaks); + pres.notify(IEnggDiffFittingPresenter::FitAllPeaks); TSM_ASSERT( "Mock not used as expected. Some EXPECT_CALL conditions were not " "satisfied.", @@ -698,7 +538,7 @@ public: nullptr, nullptr); EXPECT_CALL(mockView, setPeakList(testing::_)).Times(0); - EXPECT_CALL(mockView, getFittingRunNo()).Times(0); + EXPECT_CALL(mockView, getFocusedFileNames()).Times(0); EXPECT_CALL(mockView, getFittingRunNumVec()).Times(0); EXPECT_CALL(mockView, focusingDir()).Times(0); diff --git a/qt/scientific_interfaces/test/EnggDiffFittingViewMock.h b/qt/scientific_interfaces/test/EnggDiffFittingViewMock.h index 48ae082bf897677d2af0ad0c2123bc47ffed3798..e654e5c3eff7fdcfd4a2bdc08fdf8a0bd62e9bae 100644 --- a/qt/scientific_interfaces/test/EnggDiffFittingViewMock.h +++ b/qt/scientific_interfaces/test/EnggDiffFittingViewMock.h @@ -40,7 +40,7 @@ public: MOCK_METHOD1(enggRunPythonCode, std::string(const std::string &)); // virtual std::string fittingRunNo() const; - MOCK_CONST_METHOD0(getFittingRunNo, std::string()); + MOCK_CONST_METHOD0(getFocusedFileNames, std::string()); // virtual std::string getExpectedPeaksInput() const; MOCK_CONST_METHOD0(getExpectedPeaksInput, std::string()); @@ -103,7 +103,8 @@ public: MOCK_CONST_METHOD1(setFittingListWidgetCurrentRow, void(int idx)); // gets current value of the fitting list widget - MOCK_CONST_METHOD0(getFittingListWidgetCurrentValue, std::string()); + MOCK_CONST_METHOD0(getFittingListWidgetCurrentValue, + boost::optional<std::string>()); // sets the peak list according to the QString given MOCK_CONST_METHOD1(setPeakList, void(const std::string &peakList)); @@ -118,7 +119,7 @@ public: MOCK_METHOD1(setFittingRunNumVec, void(std::vector<std::string> assignVec)); // sets the fitting run number according to path - MOCK_METHOD1(setFittingRunNo, void(const std::string &path)); + MOCK_METHOD1(setFocusedFileNames, void(const std::string &path)); // To determine whether the current loop is multi-run or single to avoid // regenerating the list - view widget when not required