From 801a4890e7a9bc5cfab837c413e031fa77fd03a1 Mon Sep 17 00:00:00 2001
From: Owen Arnold <owen.arnold@stfc.ac.uk>
Date: Mon, 29 Jun 2015 12:49:05 +0100
Subject: [PATCH] refs #12776. Write individual period logs.

---
 .../inc/MantidDataHandling/LoadEventNexus.h   |  8 +-
 .../DataHandling/src/LoadEventNexus.cpp       | 74 ++++++++++---------
 .../DataHandling/src/LoadNexusLogs.cpp        |  4 +
 .../DataHandling/src/LoadTOFRawNexus.cpp      |  5 +-
 .../DataHandling/test/LoadEventNexusTest.h    | 10 +++
 .../DataHandling/test/LoadNexusLogsTest.h     | 28 ++++++-
 6 files changed, 85 insertions(+), 44 deletions(-)

diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadEventNexus.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadEventNexus.h
index 383ae1bf6c6..eee8e2f5621 100644
--- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadEventNexus.h
+++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadEventNexus.h
@@ -11,6 +11,7 @@
 #include "MantidDataObjects/Events.h"
 #include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/TimeSeriesProperty.h"
+#include <memory>
 
 namespace Mantid {
 
@@ -58,7 +59,7 @@ private:
 
 public:
 
-  void setNPeriods(size_t nPeriods);
+  void setNPeriods(size_t nPeriods,  std::unique_ptr<const Kernel::TimeSeriesProperty<int> >& periodLog);
 
   void reserveEventListAt(size_t wi, size_t size){
       for(size_t i = 0; i < m_WsVec.size(); ++i){
@@ -252,7 +253,7 @@ public:
   static boost::shared_ptr<BankPulseTimes>
   runLoadNexusLogs(const std::string &nexusfilename,
                    API::MatrixWorkspace_sptr localWorkspace, Algorithm &alg,
-                   bool returnpulsetimes, int& size_t);
+                   bool returnpulsetimes, int& size_t, std::unique_ptr<const Kernel::TimeSeriesProperty<int> >& periodLog);
 
   static void loadEntryMetadata(const std::string &nexusfilename,
                                 Mantid::API::MatrixWorkspace_sptr WS,
@@ -430,9 +431,6 @@ private:
   /// to open the nexus file with specific exception handling/message
   void safeOpenFile(const std::string fname);
 
-  /// Fetch the periods corresponding to the frame
-  std::vector<int> fetchFramePeriods();
-
   /// Was the instrument loaded?
   bool m_instrument_loaded_correctly;
 
diff --git a/Code/Mantid/Framework/DataHandling/src/LoadEventNexus.cpp b/Code/Mantid/Framework/DataHandling/src/LoadEventNexus.cpp
index 645dd5e6735..d6403d34432 100644
--- a/Code/Mantid/Framework/DataHandling/src/LoadEventNexus.cpp
+++ b/Code/Mantid/Framework/DataHandling/src/LoadEventNexus.cpp
@@ -1424,33 +1424,6 @@ void LoadEventNexus::createWorkspaceIndexMaps(const bool monitors,
                                             pixelID_to_wi_offset, true);
 }
 
-/**
- * Fetch the period numbers corresponding to each frame.
- * @return vector of period numbers, should have as many as we have frames. Indexes correspond to period numbers.
- */
-std::vector<int> LoadEventNexus::fetchFramePeriods()
-{
-    std::vector<int> periodLog(1, BankPulseTimes::FirstPeriod); // One entry, all period 1. in call any of the below is missing.
-    try {
-      m_file->openGroup(m_top_entry_name, "NXentry");
-      m_file->openGroup("framelog", "NXcollection");
-      try {
-        m_file->openGroup("period_log", "NXlog");
-        m_file->openData("value");
-        std::vector<int> temp;
-        m_file->getData(temp);
-        periodLog = temp;
-        m_file->closeData();
-        m_file->closeGroup();
-      } catch (::NeXus::Exception &) {
-      }
-      m_file->closeGroup();
-      m_file->closeGroup();
-    } catch (::NeXus::Exception & ex) {
-    }
-    return periodLog;
-}
-
 //-----------------------------------------------------------------------------
 /**
 * Load events from the file.
@@ -1473,11 +1446,12 @@ void LoadEventNexus::loadEvents(API::Progress *const prog,
   // Initialize the counter of bad TOFs
   bad_tofs = 0;
   int nPeriods = 1;
+  std::unique_ptr<const TimeSeriesProperty<int> > periodLog(new const TimeSeriesProperty<int>("period_log"));
   if (!m_logs_loaded_correctly) {
     if (loadlogs) {
       prog->doReport("Loading DAS logs");
 
-      m_allBanksPulseTimes = runLoadNexusLogs(m_filename, m_ws, *this, true, nPeriods);
+      m_allBanksPulseTimes = runLoadNexusLogs(m_filename, m_ws, *this, true, nPeriods, periodLog);
 
       run_start = m_ws->getFirstPulseTime();
       m_logs_loaded_correctly = true;
@@ -1496,7 +1470,7 @@ void LoadEventNexus::loadEvents(API::Progress *const prog,
                                    true);
     }
   }
-  m_ws->setNPeriods(nPeriods); // This is how many workspaces we are going to make.
+  m_ws->setNPeriods(nPeriods, periodLog); // This is how many workspaces we are going to make.
 
   // Make sure you have a non-NULL m_allBanksPulseTimes
   if (m_allBanksPulseTimes == NULL) {
@@ -1786,14 +1760,14 @@ void LoadEventNexus::loadEvents(API::Progress *const prog,
     numProg += bankNames.size() * 3; // 3 = second proc task
   Progress *prog2 = new Progress(this, 0.3, 1.0, numProg);
 
-  const std::vector<int> periodLog =  fetchFramePeriods();
+  const std::vector<int> periodLogVec =  periodLog->valuesAsVector();
 
   for (size_t i = bank0; i < bankn; i++) {
     // We make tasks for loading
     if (bankNumEvents[i] > 0)
       pool.schedule(new LoadBankFromDiskTask(
           this, bankNames[i], classType, bankNumEvents[i], oldNeXusFileNames,
-          prog2, diskIOMutex, scheduler, periodLog));
+          prog2, diskIOMutex, scheduler, periodLogVec));
   }
   // Start and end all threads
   pool.joinAll();
@@ -1850,15 +1824,35 @@ EventWorkspace_sptr DecoratorWorkspace::createEmptyEventWorkspace() const {
   return eventWS;
 }
 
-void DecoratorWorkspace::setNPeriods(size_t nPeriods) {
+void DecoratorWorkspace::setNPeriods(size_t nPeriods, std::unique_ptr<const TimeSeriesProperty<int> >& periodLog) {
 
   // Create vector where size is the number of periods and initialize workspaces in each.
   auto temp = m_WsVec[0];
   m_WsVec = std::vector<DataObjects::EventWorkspace_sptr>(
       nPeriods);
 
+  std::vector<int> periodNumbers = periodLog->valuesAsVector();
+  std::set<int> uniquePeriods(periodNumbers.begin(), periodNumbers.end());
+  const bool addBoolTimeSeries = (uniquePeriods.size() == nPeriods);
+
   for (size_t i = 0; i < m_WsVec.size(); ++i) {
+    const int periodNumber = int(i+1);
     m_WsVec[i] =  createEmptyEventWorkspace();
+    if(addBoolTimeSeries) {
+        std::stringstream buffer;
+        buffer << "period " << periodNumber;
+        auto * periodBoolLog = new Kernel::TimeSeriesProperty<bool>(buffer.str());
+        for(int j = 0; j < int(periodLog->size()); ++j){
+            periodBoolLog->addValue(periodLog->nthTime(j), periodNumber == periodLog->nthValue(j));
+        }
+        Run& mutableRun =  m_WsVec[i]->mutableRun();
+        mutableRun.addProperty(periodBoolLog);
+
+        Kernel::PropertyWithValue<int> *currentPeriodProperty =
+            new Kernel::PropertyWithValue<int>("current_period", periodNumber);
+        mutableRun.addProperty(currentPeriodProperty);
+    }
+
     copyLogs(temp, m_WsVec[i]); // Copy all logs from dummy workspace to period workspaces.
     m_WsVec[i]->setInstrument(temp->getInstrument());
   }
@@ -2935,13 +2929,15 @@ void LoadEventNexus::filterDuringPause(API::MatrixWorkspace_sptr workspace) {
 * @param alg :: Handle of the algorithm
 * @param returnpulsetimes :: flag to return shared pointer for BankPulseTimes,
 *otherwise NULL.
+* @param nPeriods : Number of periods (write to)
+* @param periodLog : Period logs DateAndTime to int map.
 *
 * @return Pulse times given in the DAS logs
 */
 boost::shared_ptr<BankPulseTimes>
 LoadEventNexus::runLoadNexusLogs(const std::string &nexusfilename,
                                  API::MatrixWorkspace_sptr localWorkspace,
-                                 API::Algorithm &alg, bool returnpulsetimes, int& nPeriods) {
+                                 API::Algorithm &alg, bool returnpulsetimes, int& nPeriods, std::unique_ptr<const TimeSeriesProperty<int> >& periodLog) {
   // --------------------- Load DAS Logs -----------------
   // The pulse times will be empty if not specified in the DAS logs.
   // BankPulseTimes * out = NULL;
@@ -2957,10 +2953,16 @@ LoadEventNexus::runLoadNexusLogs(const std::string &nexusfilename,
                                                      localWorkspace);
     loadLogs->execute();
 
-    if(localWorkspace->run().hasProperty("nperiods")){
-        nPeriods  = localWorkspace->run().getPropertyValueAsType<int>("nperiods");
+    const Run& run = localWorkspace->run();
+    // Get the number of periods
+    if(run.hasProperty("nperiods")){
+        nPeriods  = run.getPropertyValueAsType<int>("nperiods");
+    }
+    // Get the period log. Map of DateAndTime to Period int values.
+    if(run.hasProperty("period_log")){
+        auto* temp = run.getProperty("period_log");
+        periodLog.reset(dynamic_cast<TimeSeriesProperty<int>*>(temp->clone()));
     }
-
 
     // If successful, we can try to load the pulse times
     Kernel::TimeSeriesProperty<double> *log =
diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusLogs.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusLogs.cpp
index 4188589f3c0..d20d6326ae8 100644
--- a/Code/Mantid/Framework/DataHandling/src/LoadNexusLogs.cpp
+++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusLogs.cpp
@@ -315,6 +315,10 @@ void LoadNexusLogs::loadLogs(
     } else if (log_class == "IXseblock") {
       loadSELog(file, itr->first, workspace);
     }
+    else if(log_class == "NXcollection"){
+        int jj = 0;
+        ++jj;
+    }
   }
   loadVetoPulses(file, workspace);
 
diff --git a/Code/Mantid/Framework/DataHandling/src/LoadTOFRawNexus.cpp b/Code/Mantid/Framework/DataHandling/src/LoadTOFRawNexus.cpp
index 51aee612360..72748a24ce7 100644
--- a/Code/Mantid/Framework/DataHandling/src/LoadTOFRawNexus.cpp
+++ b/Code/Mantid/Framework/DataHandling/src/LoadTOFRawNexus.cpp
@@ -518,8 +518,9 @@ void LoadTOFRawNexus::exec() {
   prog->doReport("Loading DAS logs");
   g_log.debug() << "Loading DAS logs" << std::endl;
 
-  int nPeriods = 1;
-  LoadEventNexus::runLoadNexusLogs(filename, WS, *this, false, nPeriods);
+  int nPeriods = 1; // Unused
+  std::unique_ptr<const TimeSeriesProperty<int> > periodLog(new const TimeSeriesProperty<int>("period_log")); // Unused
+  LoadEventNexus::runLoadNexusLogs(filename, WS, *this, false, nPeriods, periodLog);
 
   // Load the instrument
   prog->report("Loading instrument");
diff --git a/Code/Mantid/Framework/DataHandling/test/LoadEventNexusTest.h b/Code/Mantid/Framework/DataHandling/test/LoadEventNexusTest.h
index 631a751229d..2c5224e30a4 100644
--- a/Code/Mantid/Framework/DataHandling/test/LoadEventNexusTest.h
+++ b/Code/Mantid/Framework/DataHandling/test/LoadEventNexusTest.h
@@ -633,6 +633,16 @@ void test_extract_nperiod_data() {
       EventWorkspace_sptr ws = boost::dynamic_pointer_cast<EventWorkspace>(outGroup->getItem(i));
       TS_ASSERT(ws);
       TSM_ASSERT("Non-zero events in each period", ws->getNumberEvents() > 0);
+
+      std::stringstream buffer;
+      buffer << "period " << i+1;
+      std::string periodBoolLog = buffer.str();
+
+      const int currentPeriod = ws->run().getPropertyValueAsType<int>("current_period");
+
+      TSM_ASSERT("Each period should have a boolean array for masking period numbers", ws->run().hasProperty(periodBoolLog));
+      TSM_ASSERT_EQUALS("Current period is not what was expected.", currentPeriod, i+1);
+
   }
 
 }
diff --git a/Code/Mantid/Framework/DataHandling/test/LoadNexusLogsTest.h b/Code/Mantid/Framework/DataHandling/test/LoadNexusLogsTest.h
index 508365f3962..a7aef732b8f 100644
--- a/Code/Mantid/Framework/DataHandling/test/LoadNexusLogsTest.h
+++ b/Code/Mantid/Framework/DataHandling/test/LoadNexusLogsTest.h
@@ -108,7 +108,7 @@ public:
     TS_ASSERT_EQUALS(dlog->size(),172);
   }
 
-  void test_extract_nperiod_log(){
+  void test_extract_nperiod_log_from_event_nexus(){
 
       auto testWS = createTestWorkspace();
       auto run = testWS->run();
@@ -131,6 +131,32 @@ public:
 
   }
 
+  void test_extract_periods_log_from_event_nexus(){
+
+      auto testWS = createTestWorkspace();
+      auto run = testWS->run();
+      TSM_ASSERT("Should not have nperiods until we run LoadNexusLogs", !run.hasProperty("nperiods"));
+      LoadNexusLogs loader;
+
+      loader.setChild(true);
+      loader.initialize();
+      loader.setProperty("Workspace", testWS);
+      loader.setPropertyValue("Filename", "LARMOR00003368.nxs");
+      loader.execute();
+      run = testWS->run();
+
+      const bool hasPeriods = run.hasProperty("period_log");
+      TSM_ASSERT("Should have period_log now we have run LoadNexusLogs", hasPeriods);
+
+      auto* temp = run.getProperty("period_log");
+      auto * periodLog = dynamic_cast<TimeSeriesProperty<int>*>(temp);
+      TSM_ASSERT("Period log should be an int time series property", periodLog);
+
+      std::vector<int> periodValues = periodLog->valuesAsVector();
+      std::set<int> uniquePeriods(periodValues.begin(), periodValues.end());
+      TSM_ASSERT_EQUALS("Should have 4 periods in total", 4, uniquePeriods.size());
+  }
+
 private:
   
   API::MatrixWorkspace_sptr createTestWorkspace()
-- 
GitLab