From 49dd1cffe9ff1d99a6a20ce365690def4ed3b213 Mon Sep 17 00:00:00 2001
From: Janik Zikovsky <zikovskyjl@ornl.gov>
Date: Fri, 7 Oct 2011 21:16:28 +0000
Subject: [PATCH] Refs #3930: Method on MDHistoWorkspace to get the signal at a
 given coordinate

---
 .../API/inc/MantidAPI/IMDWorkspace.h          | 15 ++++++++
 .../Framework/Kernel/inc/MantidKernel/VMD.h   |  7 ++++
 Code/Mantid/Framework/Kernel/test/VMDTest.h   | 10 ++++++
 .../inc/MantidMDEvents/MDHistoWorkspace.h     |  5 +++
 .../MantidMDEvents/MDHistoWorkspaceIterator.h |  4 ++-
 .../MDEvents/src/MDHistoWorkspace.cpp         | 34 +++++++++++++++++--
 .../MDEvents/test/MDHistoWorkspaceTest.h      | 31 ++++++++++++++---
 7 files changed, 97 insertions(+), 9 deletions(-)

diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/IMDWorkspace.h b/Code/Mantid/Framework/API/inc/MantidAPI/IMDWorkspace.h
index 353e93021ae..144b32d6cc1 100644
--- a/Code/Mantid/Framework/API/inc/MantidAPI/IMDWorkspace.h
+++ b/Code/Mantid/Framework/API/inc/MantidAPI/IMDWorkspace.h
@@ -67,6 +67,21 @@ namespace Mantid
       /// Creates a new iterator pointing to the first cell in the workspace
       virtual IMDIterator* createIterator() const;
 
+      /// Returns the (normalized) signal at a given coordinates
+      virtual signal_t getSignalAtCoord(const coord_t * coords) const
+      {
+        UNUSED_ARG(coords);
+        throw std::runtime_error("getSignalAtCoord() not implemented.");
+      }
+
+      //-------------------------------------------------------------------------------------------
+      /// Returns the (normalized) signal at a given coordinates
+      /// @param coords :: coordinate as a VMD vector
+      signal_t getSignalAtCoord(const Mantid::Kernel::VMD & coords) const
+      {
+        return this->getSignalAtCoord(coords.getBareArray());
+      }
+
       virtual ~IMDWorkspace();
 
     };
diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/VMD.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/VMD.h
index 41db502ef3f..156f37b26bd 100644
--- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/VMD.h
+++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/VMD.h
@@ -256,6 +256,13 @@ namespace Kernel
     double& operator[](const size_t index)
     { return data[index]; }
 
+    //-------------------------------------------------------------------------------------------
+    /** @return the bare data array directly. */
+    const double * getBareArray() const
+    {
+      return data;
+    }
+
     //-------------------------------------------------------------------------------------------
     /** Return a simple string representation of the vector
      * @param separator :: string to place between values, one space is the default
diff --git a/Code/Mantid/Framework/Kernel/test/VMDTest.h b/Code/Mantid/Framework/Kernel/test/VMDTest.h
index 7a5f1c02130..5404c00d2ee 100644
--- a/Code/Mantid/Framework/Kernel/test/VMDTest.h
+++ b/Code/Mantid/Framework/Kernel/test/VMDTest.h
@@ -65,6 +65,16 @@ public:
     TS_ASSERT_DELTA( a[3], 4.0, 1e-5);
   }
 
+  void test_getBareArray()
+  {
+    VMD b(1,2,3,4);
+    const double * a = b.getBareArray();
+    TS_ASSERT_DELTA( a[0], 1.0, 1e-5);
+    TS_ASSERT_DELTA( a[1], 2.0, 1e-5);
+    TS_ASSERT_DELTA( a[2], 3.0, 1e-5);
+    TS_ASSERT_DELTA( a[3], 4.0, 1e-5);
+  }
+
   void test_operators_throw_ifNonMatchingDimensions()
   {
     VMD a(1,2,3);
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h
index 09acc592242..e3e2185aaef 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h
@@ -92,6 +92,8 @@ namespace MDEvents
 
     Mantid::Kernel::VMD getCenter(size_t linearIndex) const;
 
+    /// Returns the (normalized) signal at a given coordinates
+    signal_t getSignalAtCoord(const coord_t * coords) const;
 
     /// Sets the signal at the specified index.
     void setSignalAt(size_t index, signal_t value)
@@ -245,6 +247,9 @@ namespace MDEvents
     /// Vector of the length of the box in each dimension
     coord_t * m_boxLength;
 
+    /// Vector of the origin in each dimension
+    coord_t * m_origin;
+
     /// For converting to/from linear index to tdimensions
     size_t * m_indexMaker;
     /// Max index into each dimension
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspaceIterator.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspaceIterator.h
index 526905bd39f..94f0ca9a3fe 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspaceIterator.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspaceIterator.h
@@ -12,7 +12,9 @@ namespace MDEvents
 {
 
   /** An implementation of IMDIterator that iterates through
-    a MDHistoWorkspace.
+    a MDHistoWorkspace. It treats the bin in the workspace as
+    a box containing a single "event", at the center of each bin
+    and with the proper signal/error.
     
     @author Janik Zikovsky
     @date 2011-10-06
diff --git a/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp b/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp
index 273ce0f4d99..de208753e4f 100644
--- a/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp
+++ b/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp
@@ -7,8 +7,7 @@
 #include "MantidMDEvents/MDHistoWorkspaceIterator.h"
 
 using namespace Mantid::Kernel;
-using Mantid::Geometry::IMDDimension_sptr;
-using Mantid::Geometry::IMDDimension;
+using namespace Mantid::Geometry;
 
 namespace Mantid
 {
@@ -55,6 +54,7 @@ namespace MDEvents
     delete [] m_boxLength;
     delete [] m_indexMaker;
     delete [] m_indexMax;
+    delete [] m_origin;
   }
 
   //----------------------------------------------------------------------------------------------
@@ -191,10 +191,14 @@ namespace MDEvents
       } // (for each dimension)
     }
 
-    // Now set the m_boxLength
+    // Now set the m_boxLength and origin
     m_boxLength = new coord_t[nd];
+    m_origin = new coord_t[nd];
     for (size_t d=0; d<nd; d++)
+    {
       m_boxLength[d] = m_dimensions[d]->getX(1) - m_dimensions[d]->getX(0);
+      m_origin[d] = m_dimensions[d]->getX(0);
+    }
 
     // The index calculator
     m_indexMax = new size_t[numDimensions];
@@ -235,6 +239,7 @@ namespace MDEvents
     return out;
   }
 
+
   //----------------------------------------------------------------------------------------------
   /** Return the position of the center of a bin at a given position
    *
@@ -256,6 +261,29 @@ namespace MDEvents
   }
 
 
+  //----------------------------------------------------------------------------------------------
+  /** Get the signal at a particular coordinate in the workspace.
+   *
+   * @param coords :: numDimensions-sized array of the coordinates to look at
+   * @return the (normalized) signal at a given coordinates.
+   *         NaN if outside the range of this workspace
+   */
+  signal_t MDHistoWorkspace::getSignalAtCoord(const coord_t * coords) const
+  {
+    // Build up the linear index, dimension by dimension
+    size_t linearIndex = 0;
+    for (size_t d=0; d<numDimensions; d++)
+    {
+      coord_t x = coords[d] - m_origin[d];
+      size_t ix = size_t(x / m_boxLength[d]);
+      if (ix >= m_indexMax[d] || (x<0))
+        return std::numeric_limits<signal_t>::quiet_NaN();
+      linearIndex += ix * m_indexMaker[d];
+    }
+    return m_signals[linearIndex];
+  }
+
+
   //----------------------------------------------------------------------------------------------
   /// Creates a new iterator pointing to the first cell in the workspace
   Mantid::API::IMDIterator* MDHistoWorkspace::createIterator() const
diff --git a/Code/Mantid/Framework/MDEvents/test/MDHistoWorkspaceTest.h b/Code/Mantid/Framework/MDEvents/test/MDHistoWorkspaceTest.h
index a1dee5a07ad..5424bd4dc95 100644
--- a/Code/Mantid/Framework/MDEvents/test/MDHistoWorkspaceTest.h
+++ b/Code/Mantid/Framework/MDEvents/test/MDHistoWorkspaceTest.h
@@ -1,23 +1,25 @@
 #ifndef MANTID_MDEVENTS_MDHISTOWORKSPACETEST_H_
 #define MANTID_MDEVENTS_MDHISTOWORKSPACETEST_H_
 
+#include "MantidAPI/IMDIterator.h"
 #include "MantidGeometry/MDGeometry/MDHistoDimension.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
+#include "MantidKernel/VMD.h"
 #include "MantidMDEvents/MDHistoWorkspace.h"
+#include "MantidMDEvents/MDHistoWorkspaceIterator.h"
+#include "MantidTestHelpers/MDEventsTestHelper.h"
 #include <boost/math/special_functions/fpclassify.hpp>
 #include <cxxtest/TestSuite.h>
 #include <iomanip>
 #include <iostream>
-#include "MantidKernel/VMD.h"
-#include "MantidAPI/IMDIterator.h"
-#include "MantidMDEvents/MDHistoWorkspaceIterator.h"
+#include "MantidAPI/IMDWorkspace.h"
 
 using namespace Mantid::MDEvents;
 using namespace Mantid::Geometry;
+using namespace Mantid::API;
+using namespace Mantid::Kernel;
 using namespace Mantid;
-using Mantid::Kernel::VMD;
-using Mantid::API::IMDIterator;
 
 class MDHistoWorkspaceTest : public CxxTest::TestSuite
 {
@@ -339,6 +341,25 @@ public:
   }
 
 
+  //---------------------------------------------------------------------------------------------------
+  void test_getSignalAtCoord()
+  {
+    // 2D workspace with signal[i] = i (linear index)
+    MDHistoWorkspace_sptr ws = MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 2, 10);
+    for (size_t i=0; i<100; i++)
+      ws->setSignalAt(i, double(i));
+    IMDWorkspace_sptr iws(ws);
+    TS_ASSERT_DELTA( iws->getSignalAtCoord(VMD(0.5, 0.5)), 0.0, 1e-6);
+    TS_ASSERT_DELTA( iws->getSignalAtCoord(VMD(1.5, 0.5)), 1.0, 1e-6);
+    TS_ASSERT_DELTA( iws->getSignalAtCoord(VMD(1.5, 1.5)), 11.0, 1e-6);
+    TS_ASSERT_DELTA( iws->getSignalAtCoord(VMD(9.5, 9.5)), 99.0, 1e-6);
+    // Out of range = NaN
+    TS_ASSERT( boost::math::isnan(iws->getSignalAtCoord(VMD(-0.01, 2.5)) ) );
+    TS_ASSERT( boost::math::isnan(iws->getSignalAtCoord(VMD(3.5, -0.02)) ) );
+    TS_ASSERT( boost::math::isnan(iws->getSignalAtCoord(VMD(10.01, 2.5)) ) );
+    TS_ASSERT( boost::math::isnan(iws->getSignalAtCoord(VMD(3.5, 10.02)) ) );
+  }
+
 };
 
 
-- 
GitLab