From e577396e8d881816e48fca37ce236bfde44eb87f Mon Sep 17 00:00:00 2001
From: Tom Perkins <thomas.perkins@stfc.ac.uk>
Date: Mon, 11 Jul 2016 14:08:28 +0100
Subject: [PATCH] Handle fitted workspaces after sequential fit

Process workspaces after a combined sequential fit over runs in which each
run involves a simultaneous fit over groups/periods. Results table should work
properly.

re #15518
---
 .../Muon/MuonAnalysisFitDataPresenter.h       |  6 +-
 .../Muon/MuonSequentialFitDialog.h            |  6 ++
 .../src/Muon/MuonAnalysisFitDataPresenter.cpp | 35 +++++---
 .../src/Muon/MuonSequentialFitDialog.cpp      | 80 ++++++++++++++++---
 4 files changed, 101 insertions(+), 26 deletions(-)

diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataPresenter.h
index 6a69243cc3a..16c91c50494 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataPresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataPresenter.h
@@ -86,9 +86,11 @@ public:
   /// Create workspaces to fit
   void createWorkspacesToFit(const std::vector<std::string> &names) const;
   /// Rename fit workspaces, add logs and generate params table
-  void handleFittedWorkspaces(const std::string &groupName) const;
+  void handleFittedWorkspaces(const std::string &baseName,
+                              const std::string &groupName = "") const;
   /// Extract workspaces from group and move up a level
-  void extractFittedWorkspaces(const std::string &groupName) const;
+  void extractFittedWorkspaces(const std::string &baseName,
+                               const std::string &groupName = "") const;
 
 public slots:
   /// Transforms fit results when a simultaneous fit finishes
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.h
index 83dfd690ebb..55b2a439f21 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.h
@@ -77,6 +77,12 @@ private:
   /// Helper function to create new item for Diagnosis table
   QTableWidgetItem *createTableWidgetItem(const QString &text);
 
+  /// Reorganise workspaces after fit of one run finished
+  void finishAfterRun(const std::string &labelGroupName,
+                      const Mantid::API::IAlgorithm_sptr &fitAlg,
+                      bool simultaneous,
+                      const Mantid::API::MatrixWorkspace_sptr &firstWS) const;
+
   // -- MEMBER VARIABLES -----------------------------------------------
 
   /// UI form
diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitDataPresenter.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitDataPresenter.cpp
index f044ba89943..96eed5a5de8 100644
--- a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitDataPresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitDataPresenter.cpp
@@ -418,15 +418,17 @@ void MuonAnalysisFitDataPresenter::handleFitFinished(
 /**
  * Rename fitted workspaces so they can be linked to the input and found by the
  * results table generation code. Add special logs and generate params table.
- * @param groupName :: [input] Name of group that workspaces belong to
+ * @param baseName :: [input] Base name for workspaces
+ * @param groupName :: [input] Name of group that workspaces belong to. Leave
+ * empty to be the same as baseName (usual case).
  */
 void MuonAnalysisFitDataPresenter::handleFittedWorkspaces(
-    const std::string &groupName) const {
+    const std::string &baseName, const std::string &groupName) const {
   AnalysisDataServiceImpl &ads = AnalysisDataService::Instance();
   const auto resultsGroup =
-      ads.retrieveWS<WorkspaceGroup>(groupName + "_Workspaces");
+      ads.retrieveWS<WorkspaceGroup>( baseName + "_Workspaces");
   const auto paramsTable =
-      ads.retrieveWS<ITableWorkspace>(groupName + "_Parameters");
+      ads.retrieveWS<ITableWorkspace>(baseName + "_Parameters");
   if (resultsGroup && paramsTable) {
     const size_t offset = paramsTable->rowCount() - resultsGroup->size();
     for (size_t i = 0; i < resultsGroup->size(); i++) {
@@ -438,7 +440,7 @@ void MuonAnalysisFitDataPresenter::handleFittedWorkspaces(
       addSpecialLogs(oldName, wsDetails);
       // Generate new name and rename workspace
       std::ostringstream newName;
-      newName << groupName << "_" << wsDetails.label << "_"
+      newName << baseName << "_" << wsDetails.label << "_"
               << wsDetails.itemName << "_" << wsDetails.periods;
       ads.rename(oldName, newName.str() + "_Workspace");
       // Generate new parameters table for this dataset
@@ -446,28 +448,37 @@ void MuonAnalysisFitDataPresenter::handleFittedWorkspaces(
       if (fitTable) {
         const std::string fitTableName = newName.str() + "_Parameters";
         ads.add(fitTableName, fitTable);
-        ads.addToGroup(groupName, fitTableName);
+        // If user has specified a group to add to, add to that.
+        // Otherwise the group is called the same thing as the base name.
+        const std::string groupToAddTo =
+            groupName.empty() ? baseName : groupName;
+        ads.addToGroup(groupToAddTo, fitTableName);
       }
     }
     // Now that we have split parameters table, can delete it
-    ads.remove(groupName + "_Parameters");
+    ads.remove(baseName + "_Parameters");
   }
 }
 
 /**
  * Moves all workspaces in group "groupName_Workspaces" up a level into
  * "groupName"
- * @param groupName :: [input] Name of upper group e.g. "MuonSimulFit_Label"
+ * @param baseName :: [input] Base name for workspaces
+ * @param groupName :: [input] Name of upper group e.g. "MuonSimulFit_Label". If
+ * empty, use same as baseName.
  */
 void MuonAnalysisFitDataPresenter::extractFittedWorkspaces(
-    const std::string &groupName) const {
+    const std::string &baseName, const std::string &groupName) const {
   AnalysisDataServiceImpl &ads = AnalysisDataService::Instance();
-  const std::string resultsGroupName = groupName + "_Workspaces";
+  const std::string resultsGroupName = baseName + "_Workspaces";
   const auto resultsGroup = ads.retrieveWS<WorkspaceGroup>(resultsGroupName);
-  if (ads.doesExist(groupName) && resultsGroup) {
+  // If user has specified a group to add to, add to that.
+  // Otherwise the group is called the same thing as the base name.
+  const std::string groupToAddTo = groupName.empty() ? baseName : groupName;
+  if (ads.doesExist(groupToAddTo) && resultsGroup) {
     for (const auto &name : resultsGroup->getNames()) {
       ads.removeFromGroup(resultsGroupName, name);
-      ads.addToGroup(groupName, name);
+      ads.addToGroup(groupToAddTo, name);
     }
     ads.remove(resultsGroupName); // should be empty now
   }
diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonSequentialFitDialog.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonSequentialFitDialog.cpp
index fddf4fe7ecb..fddef594562 100644
--- a/MantidQt/CustomInterfaces/src/Muon/MuonSequentialFitDialog.cpp
+++ b/MantidQt/CustomInterfaces/src/Muon/MuonSequentialFitDialog.cpp
@@ -4,6 +4,8 @@
 #include "MantidAPI/AlgorithmProxy.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/TableRow.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataPresenter.h"
@@ -471,22 +473,15 @@ void MuonSequentialFitDialog::continueFit() {
       break;
     }
 
+    // Copy log values and group created fit workspaces
+    finishAfterRun(labelGroupName, fit, datasetsPerRun > 1, matrixWS);
+
     // If fit was simultaneous, transform results
     if (datasetsPerRun > 1) {
-      m_dataPresenter->handleFittedWorkspaces(wsBaseName);
-      m_dataPresenter->extractFittedWorkspaces(wsBaseName);
+      m_dataPresenter->handleFittedWorkspaces(wsBaseName, labelGroupName);
+      m_dataPresenter->extractFittedWorkspaces(wsBaseName, labelGroupName);
     }
 
-    // Make sure created fit workspaces end up in the group
-    // TODO: this really should use loop
-    ads.addToGroup(labelGroupName, wsBaseName + "_NormalisedCovarianceMatrix");
-    ads.addToGroup(labelGroupName, wsBaseName + "_Parameters");
-    ads.addToGroup(labelGroupName, wsBaseName + "_Workspace");
-
-    // Copy log values
-    auto fitWs = ads.retrieveWS<MatrixWorkspace>(wsBaseName + "_Workspace");
-    fitWs->copyExperimentInfoFrom(matrixWS.get());
-
     // Add information about the fit to the diagnosis table
     addDiagnosisEntry(runTitle, fit->getProperty("OutputChi2OverDof"),
                       functionToFit);
@@ -499,6 +494,67 @@ void MuonSequentialFitDialog::continueFit() {
   setState(Stopped);
 }
 
+/**
+ * Handle reorganising workspaces after fit of a single run has finished
+ * Group output together and copy log values
+ * @param labelGroupName :: [input] Label for group
+ * @param fitAlg :: [input] Pointer to fit algorithm
+ * @param simultaneous :: [input] Whether several groups/periods were fitted
+ * simultaneously or not
+ * @param firstWS :: [input] Pointer to first input workspace (to copy logs
+ * from)
+ */
+void MuonSequentialFitDialog::finishAfterRun(
+    const std::string &labelGroupName, const IAlgorithm_sptr &fitAlg,
+    bool simultaneous, const MatrixWorkspace_sptr &firstWS) const {
+  auto &ads = AnalysisDataService::Instance();
+  const std::string wsBaseName = fitAlg->getPropertyValue("Output");
+  if (simultaneous) {
+    // copy logs
+    auto fitWSGroup =
+        ads.retrieveWS<WorkspaceGroup>(wsBaseName + "_Workspaces");
+    for (size_t i = 0; i < fitWSGroup->size(); i++) {
+      auto fitWs =
+          boost::dynamic_pointer_cast<MatrixWorkspace>(fitWSGroup->getItem(i));
+      if (fitWs) {
+        fitWs->copyExperimentInfoFrom(firstWS.get());
+      }
+    }
+    // insert workspace names into table
+    try {
+      const std::string paramTableName =
+          fitAlg->getProperty("OutputParameters");
+      const auto paramTable = ads.retrieveWS<ITableWorkspace>(paramTableName);
+      if (paramTable) {
+        Mantid::API::TableRow f0Row = paramTable->appendRow();
+        f0Row << "f0=" + fitAlg->getPropertyValue("InputWorkspace") << 0.0
+              << 0.0;
+        for (size_t i = 1; i < fitWSGroup->size(); i++) {
+          const std::string suffix = boost::lexical_cast<std::string>(i);
+          const auto wsName =
+              fitAlg->getPropertyValue("InputWorkspace_" + suffix);
+          Mantid::API::TableRow row = paramTable->appendRow();
+          row << "f" + suffix + "=" + wsName << 0.0 << 0.0;
+        }
+      }
+    } catch (const Mantid::Kernel::Exception::NotFoundError &) {
+      // Not a fatal error, but shouldn't happen
+      g_log.warning(
+          "Could not find output parameters table for simultaneous fit");
+    }
+    // Group output together
+    ads.addToGroup(labelGroupName, wsBaseName + "_NormalisedCovarianceMatrix");
+    ads.addToGroup(labelGroupName, wsBaseName + "_Parameters");
+    ads.addToGroup(labelGroupName, wsBaseName + "_Workspaces");
+  } else {
+    ads.addToGroup(labelGroupName, wsBaseName + "_NormalisedCovarianceMatrix");
+    ads.addToGroup(labelGroupName, wsBaseName + "_Parameters");
+    ads.addToGroup(labelGroupName, wsBaseName + "_Workspace");
+    auto fitWs = ads.retrieveWS<MatrixWorkspace>(wsBaseName + "_Workspace");
+    fitWs->copyExperimentInfoFrom(firstWS.get());
+  }
+}
+
 /**
  * Stop fitting process.
  */
-- 
GitLab