Skip to content
Snippets Groups Projects
EventList.cpp 67.8 KiB
Newer Older
#include "MantidDataObjects/EventList.h"
#include <math.h>
Nick Draper's avatar
Nick Draper committed
using std::ostream;
using std::runtime_error;
using std::size_t;
using std::vector;

namespace Mantid
{
namespace DataObjects
{
using Kernel::Exception::NotImplementedError;
  //==========================================================================
  /// --------------------- TofEvent Comparators ----------------------------------
  //==========================================================================
  /** Compare two events' TOF, return true if e1 should be before e2.
   * @param e1 first event
   * @param e2 second event
   *  */
  bool compareEventTof(const TofEvent & e1, const TofEvent& e2)
  /** Compare two events' FRAME id, return true if e1 should be before e2.
  * @param e1 first event
  * @param e2 second event
  *  */
  bool compareEventPulseTime(const TofEvent& e1, const TofEvent& e2)
    return (e1.pulseTime() < e2.pulseTime());
//  /** Comparison operator by TOF for TofEvents) */
//  bool operator<(const TofEvent & e1, const TofEvent& e2)
//  {
//    return (e1.tof() < e2.tof());
//  }
//
//  /** Comparison operator by TOF for TofEvents) */
//  bool operator>(const TofEvent & e1, const TofEvent& e2)
//  {
//    return (e1.tof() > e2.tof());
//  }
//
//  /** Comparison operator by TOF for TofEvents) */
//  bool operator<(const WeightedEvent & e1, const WeightedEvent& e2)
//  {
//    return (e1.tof() < e2.tof());
//  }





  //==========================================================================
  /** Unary function for searching the event list.
   * Returns true if the event's TOF is >= a value
   * @param event the event being checked.
   */
  class tofGreaterOrEqual: std::unary_function<TofEvent, double>
  {
    /// Comparison variable
    double m_value;
  public:
    /// Constructor: save the value
    tofGreaterOrEqual(double value): m_value(value)
    {  }
    /// () operator: return true if event.tof >= value
    bool operator()(TofEvent event)
    {
    }
  };

  //==========================================================================
  /** Unary function for searching the event list.
   * Returns true if the event's TOF is > a value
   * @param event the event being checked.
   */
  class tofGreater: std::unary_function<TofEvent, double>
  {
    /// Comparison variable
    double m_value;
  public:
    /// Constructor: save the value
    tofGreater(double value): m_value(value)
    {  }
    /// () operator: return true if event.tof > value
    bool operator()(TofEvent event)
    {
  //==========================================================================
  // ---------------------- EventList stuff ----------------------------------
  //==========================================================================
  // --- Constructors -------------------------------------------------------------------

    has_weights(false), order(UNSORTED), detectorIDs()
  /** Constructor copying from an existing event list
   * @param rhs EventList object to copy*/
  EventList::EventList(const EventList& rhs)
    //Call the copy operator to do the job,
    this->operator=(rhs);
  /** Constructor, taking a vector of events.
   * @param events Vector of TofEvent's */
  EventList::EventList(const std::vector<TofEvent> &events)
  {
    this->events.assign(events.begin(), events.end());
    // Note: These two lines do not seem to have an effect on releasing memory
    //  at least on Linux. (Memory usage seems to increase event after deleting EventWorkspaces.
    //  Therefore, for performance, they are kept commented:

    //this->events.clear();
    //std::vector<TofEvent>().swap(events); //Trick to release the vector memory.
  // --------------------------------------------------------------------------
  // --- Operators -------------------------------------------------------------------

  /** Copy into this event list from another
   * @param rhs We will copy all the events from that into this object.
   * @return reference to this
   * */
  EventList& EventList::operator=(const EventList& rhs)
    //Copy all data from the rhs.
    this->events.assign(rhs.events.begin(), rhs.events.end());
    this->weightedEvents.assign(rhs.weightedEvents.begin(), rhs.weightedEvents.end());
    this->has_weights = rhs.has_weights;
    //Copy the detector ID set
    this->detectorIDs = rhs.detectorIDs;
  // --------------------------------------------------------------------------
   * @param event TofEvent to add at the end of the list.
   * @return reference to this
   * */
  EventList& EventList::operator+=(const TofEvent &event)
    if (has_weights)
      this->weightedEvents.push_back(WeightedEvent(event));
    else
      this->events.push_back(event);

  // --------------------------------------------------------------------------
  /** Append a list of events to the histogram.
   * @param more_events A vector of events to append.
   * @return reference to this
   * */
  EventList& EventList::operator+=(const std::vector<TofEvent> & more_events)
    if (has_weights)
    {
      //Add default weights to all the un-weighted incoming events from the list.
      // and append to the list
      std::vector<TofEvent>::const_iterator it;
      for(it = more_events.begin(); it != more_events.end(); it++)
        this->weightedEvents.push_back( WeightedEvent(*it) );
    }
    else
    {
      //Simply push the events
      this->events.insert(this->events.end(), more_events.begin(), more_events.end());
    }

  // --------------------------------------------------------------------------
  /** Append a WeightedEvent to the histogram.
   * Note: The whole list will switch to weights (a possibly lengthy operation)
   *  if it did not have weights before.
   *
   * @param event WeightedEvent to add at the end of the list.
   * @return reference to this
   * */
  EventList& EventList::operator+=(const WeightedEvent &event)
  {
    if (!has_weights)
      this->switchToWeightedEvents();
    this->weightedEvents.push_back(event);
    this->order = UNSORTED;
    return *this;
  }

  // --------------------------------------------------------------------------
  /** Append a list of events to the histogram.
   * Note: The whole list will switch to weights (a possibly lengthy operation)
   *  if it did not have weights before.
   *
   * @param more_events A vector of events to append.
   * @return reference to this
   * */
  EventList& EventList::operator+=(const std::vector<WeightedEvent> & more_events)
  {
    if (!has_weights)
      this->switchToWeightedEvents();
    //Simply push the events
    this->weightedEvents.insert(weightedEvents.end(), more_events.begin(), more_events.end());
    this->order = UNSORTED;
    return *this;
  }



  // --------------------------------------------------------------------------
  /** Append another EventList to this event list.
   * The event lists are concatenated, and a union of the sets of detector ID's is done.
   * @param more_events Another EventList.
   * @return reference to this
  EventList& EventList::operator+=(const EventList& more_events)
    if (more_events.hasWeights())
    {
      //We're adding something with weights

      //Make sure that THIS has weights too.
      if (!has_weights)
        this->switchToWeightedEvents();

      //At this point, both have weights. Great!
      const vector<WeightedEvent> & rel = more_events.getWeightedEvents();
      this->weightedEvents.insert(this->weightedEvents.end(), rel.begin(), rel.end());
    }

    if (has_weights && !more_events.hasWeights())
    {
      //THIS has weights, but we're adding something that doesn't.
      const vector<TofEvent> & rel = more_events.getEvents();
      this->operator+=(rel);
    }

    else if (!has_weights && !more_events.hasWeights())
    {
      //Neither has weights. Keep the unweighted event lists.
      const vector<TofEvent> & rel = more_events.getEvents();
      this->events.insert(this->events.end(), rel.begin(), rel.end());
    }

    //No guaranteed order
    this->order = UNSORTED;
    //Do a union between the detector IDs of both lists
    std::set<int>::const_iterator it;
    for (it = more_events.detectorIDs.begin(); it != more_events.detectorIDs.end(); it++ )
      this->detectorIDs.insert( *it );


  // --------------------------------------------------------------------------
  /** SUBTRACT another EventList from this event list.
   * The event lists are concatenated, but the weights of the incoming
   *    list are multiplied by -1.0.
   *
   * @param more_events Another EventList.
   * @return reference to this
   * */
  EventList& EventList::operator-=(const EventList& more_events)
  {
    if (more_events.hasWeights())
    {
      //We're adding something with weights
      //Make sure that THIS has weights too.
      this->switchToWeightedEvents();

      //At this point, both have weights. Great!
      const vector<WeightedEvent> & rel = more_events.getWeightedEvents();
      std::vector<WeightedEvent>::const_iterator it;
      for(it = rel.begin(); it != rel.end(); it++)
        this->weightedEvents.push_back( WeightedEvent(it->m_tof, it->m_pulsetime, -it->m_weight, it->m_errorSquared) );
    }

    if (!more_events.hasWeights())
    {
      //We're adding a list without weights.

      //Make sure that THIS has weights too.
      this->switchToWeightedEvents();

      //Loop through the unweighted input, convert them to -1.0 weight, and concatenate.
      const vector<TofEvent> & rel = more_events.getEvents();
      std::vector<TofEvent>::const_iterator it;
      for(it = rel.begin(); it != rel.end(); it++)
        this->weightedEvents.push_back( WeightedEvent(*it, -1.0, 1.0) );
    }

    //No guaranteed order
    this->order = UNSORTED;

    //NOTE: What to do about detector ID's

    return *this;
  }


  // --------------------------------------------------------------------------
  /** Equality operator between EventList's
   * @param rhs :: other EventList to compare
   * @return :: true if equal.
   */
  bool EventList::operator==(const EventList& rhs) const
  {
    if (this->getNumberEvents() != rhs.getNumberEvents())
      return false;
    if (this->has_weights != rhs.has_weights)
      return false;
    if (events != rhs.events)
      return false;
    if (weightedEvents != rhs.weightedEvents)
      return false;
    return true;
  }
  /** Inequality comparator
  * @param rhs :: other EventList to compare
   * @return :: true if not equal.
  */
  bool EventList::operator!=(const EventList& rhs) const
  {
    return (!this->operator==(rhs));
  }
  // --------------------------------------------------------------------------
  /** Append an event to the histogram, without clearing the cache, to make it faster.
   * @param event TofEvent to add at the end of the list.
   * */
  void EventList::addEventQuickly(const TofEvent &event)
  {
    if (has_weights)
      this->weightedEvents.push_back(WeightedEvent(event));
    else
      this->events.push_back(event);
  }

  // --------------------------------------------------------------------------
  /** Append an event to the histogram, without clearing the cache, to make it faster.
   * @param event TofEvent to add at the end of the list.
   * */
  void EventList::addEventQuickly(const WeightedEvent &event)
  {
    this->weightedEvents.push_back(event);
  // --------------------------------------------------------------------------
  /** Add a detector ID to the set of detector IDs
   *
   * @param detID detector ID to insert in set.
   */
  void EventList::addDetectorID(const int detID)
  {
    this->detectorIDs.insert( detID );
  }

  // --------------------------------------------------------------------------
  /** Return true if the given detector ID is in the list for this eventlist */
  bool EventList::hasDetectorID(const int detID) const
  {
    return ( detectorIDs.find(detID) != detectorIDs.end() );
  }

  // --------------------------------------------------------------------------
  /** Get a const reference to the detector IDs set.
   */
  const std::set<int>& EventList::getDetectorIDs() const
  {
    return this->detectorIDs;
  }

  /** Get a mutable reference to the detector IDs set.
   */
  std::set<int>& EventList::getDetectorIDs()
  {
    return this->detectorIDs;
  }

  /** Return true if the event list has weights */
  bool EventList::hasWeights() const
  {
    return has_weights;
  }

  // -----------------------------------------------------------------------------------------------
  /** Switch the EventList to use WeightedEvents instead
   * of TofEvent.
   */
  void EventList::switchToWeightedEvents()
  {
    //Do nothing if already there
    if (has_weights)
      return;
    has_weights = true;
    weightedEvents.clear();

    //Convert and copy all TofEvents to the weightedEvents list.
    std::vector<TofEvent>::const_iterator it;
    for(it = events.begin(); it != events.end(); it++)
      this->weightedEvents.push_back( WeightedEvent(*it) );

    //Get rid of the old events
    events.clear();
  }




  // ==============================================================================================
  // --- Handling the event list -------------------------------------------------------------------
  // ==============================================================================================

  /** Return the const list of TofEvents contained.
   * @return a const reference to the list of non-weighted events
   * */
  const std::vector<TofEvent> & EventList::getEvents() const
    if (has_weights)
      throw std::runtime_error("EventList::getEvents() called for an EventList that has weights. Use getWeightedEvents().");
  /** Return the list of TofEvents contained.
   * @return a reference to the list of non-weighted events
   * */
  std::vector<TofEvent>& EventList::getEvents()
    if (has_weights)
      throw std::runtime_error("EventList::getEvents() called for an EventList that has weights. Use getWeightedEvents().");
  /** Return the list of WeightedEvent contained.
   * @return a reference to the list of weighted events
   * */
  std::vector<WeightedEvent>& EventList::getWeightedEvents()
  {
    if (!has_weights)
      throw std::runtime_error("EventList::getWeightedEvents() called for an EventList that does not have weights. Use getEvents().");
    return this->weightedEvents;
  }

  /** Return the list of WeightedEvent contained.
   * @return a const reference to the list of weighted events
   * */
  const std::vector<WeightedEvent>& EventList::getWeightedEvents() const
  {
    if (!has_weights)
      throw std::runtime_error("EventList::getWeightedEvents() called for an EventList that does not have weights. Use getEvents().");
    return this->weightedEvents;
  }

  /** Clear the list of events and any
   * associated detector ID's.
   * */
  /** Resrve a certain number of entries in the (NOT-WEIGHTED) event list. Do NOT call
   * on weighted events!
   *
   * Calls std::vector<>::reserve() in order to pre-allocate the length of the event list vector.
   *
   * @param num :: number of events that will be in this EventList
   */
  void EventList::reserve(size_t num)
  {
    this->events.reserve(num);
  }


  // ==============================================================================================
  // --- Sorting functions -----------------------------------------------------
  // ==============================================================================================

  // --------------------------------------------------------------------------
  /** Sort events by TOF or Frame
   * @param order Order by which to sort.
   * */
  void EventList::sort(const EventSortType order) const
      return; // don't bother doing anything. Why did you ask to unsort?
    }
    else if (order == TOF_SORT)
    {
      this->sortTof();
    }
    }
    else
    {
      throw runtime_error("Invalid sort type in EventList::sort(EventSortType)");
    }
  }

  // --------------------------------------------------------------------------
  {
    if (this->order == TOF_SORT)
    {
      return; // nothing to do
    }
    if (has_weights)
      std::sort(weightedEvents.begin(), weightedEvents.end(), compareEventTof);
    else
      std::sort(events.begin(), events.end(), compareEventTof);

    //Save the order to avoid unnecessary re-sorting.
    this->order = TOF_SORT;


//  // MergeSort from: http://en.literateprograms.org/Merge_sort_%28C_Plus_Plus%29#chunk%20def:merge
//  template<typename IT, typename VT> void insert(IT begin, IT end, const VT &v)
//  {
//    while(begin+1!=end && *(begin+1)<v) {
//      std::swap(*begin, *(begin+1));
//      ++begin;
//    }
//    *begin=v;
//  }
//
//  template<typename IT> void merge(IT begin, IT begin_right, IT end)
//  {
//    for(;begin<begin_right; ++begin) {
//      if(*begin>*begin_right) {
//        typename std::iterator_traits<IT>::value_type v(*begin);
//        *begin=*begin_right;
//        insert(begin_right, end, v);
//      }
//    }
//  }
//
//  template<typename IT> void mergesort(IT begin, IT end)
//  {
//    size_t size(end-begin);
//    //std::cout << "mergesort called on " << size << "\n";
//    if(size<2) return;
//
//    IT begin_right=begin+size/2;
//
//    mergesort(begin, begin_right);
//    mergesort(begin_right, end);
//    merge(begin, begin_right, end);
//  }


  //----------------------------------------------------------------------------------------------------
  /** Merge two sorted lists into one sorted vector.
   *
   * @tparam T :: the type in the vector.
   * @param begin1 :: iterator at the start of the first list.
   * @param end1 :: iterator at the end of the first list.
   * @param begin2 :: iterator at the start of the second list.
   * @param end2 :: iterator at the end of the second list.
   * @param result_vector :: a vector (by reference) that will be filled with the result.
   * */
  template<typename T>
  void merge(typename std::vector<T>::iterator begin1, typename std::vector<T>::iterator end1,
             typename std::vector<T>::iterator begin2, typename std::vector<T>::iterator end2,
             typename std::vector<T> & result_vector)
  {
    typename std::vector<T>::iterator it1=begin1;
    typename std::vector<T>::iterator it2=begin2;
    while (!((it1 == end1) && (it2 == end2)))
    {
      if (it1 == end1)
      {
        // Only it2 makes sense
        result_vector.push_back(*it2);
        it2++;
      }
      else if (it2 == end2)
      {
        // Only it1 makes sense
        result_vector.push_back(*it1);
        it1++;
      }
      else
      {
        // Both iterators are valid. Which is smaller?
        if (*it1 < *it2)
        {
          result_vector.push_back(*it1);
          it1++;
        }
        else
        {
          result_vector.push_back(*it2);
          it2++;
        }
      }
    }
  }



  //----------------------------------------------------------------------------------------------------
  /** Perform a parallelized sort on a provided vector, using 2 threads.
   * NOTE: Will temporarily use twice the memory used by the incoming vector.
   *
   * @param vec :: a vector, by refe/rence, that will be sorted-in place.
   */
  template<typename T>
  void parallel_sort2(typename std::vector<T> & vec)
  {
    size_t size = vec.size();

    typename std::vector<T>::iterator begin = vec.begin();
    typename std::vector<T>::iterator middle = begin + size/2;
    typename std::vector<T>::iterator end = vec.end();

    PRAGMA_OMP(parallel sections)
    {
      PRAGMA_OMP(section)
      {
        std::sort(begin, middle);
        //std::cout << " ----------- Part 1 --------------\n"; for (typename std::vector<T>::iterator it = begin; it != middle; it++) std::cout << *it << "\n";
      }
      PRAGMA_OMP(section)
      {
        std::sort(middle, end);
        // std::cout << " ----------- Part 2 --------------\n";for (typename std::vector<T>::iterator it = middle; it != end; it++) std::cout << *it << "\n";
      }
    }

    // Now merge back
    typename std::vector<T> temp;
    merge(begin, middle, middle, end, temp);

    //std::cout << " ----------- Part 1+2 --------------\n"; for (typename std::vector<T>::iterator it = temp.begin(); it != temp.end(); it++) std::cout << *it << "\n";
    // Swap storage with the temp vector
    vec.swap(temp);
    // Which we can now clear
    temp.clear();
  }


  //----------------------------------------------------------------------------------------------------
  /** Perform a parallelized sort on a provided vector, using 4 threads.
   * NOTE: Will temporarily use twice the memory used by the incoming vector.
   *
   * @param vec :: a vector, by refe/rence, that will be sorted-in place.
   */
  template<typename T>
  void parallel_sort4(std::vector<T> & vec)
  {
    //int num_cores = PARALLEL_NUMBER_OF_THREADS;
    size_t size = vec.size();

    typename std::vector<T>::iterator begin = vec.begin();
    typename std::vector<T>::iterator middle1 = begin + size/4;
    typename std::vector<T>::iterator middle2 = begin + size/2;
    typename std::vector<T>::iterator middle3 = begin + 3*size/4;
    typename std::vector<T>::iterator end = vec.end();

    PRAGMA_OMP(parallel sections)
    {
      PRAGMA_OMP(section)
      {
        std::sort(begin, middle1);
      }
      PRAGMA_OMP(section)
      {
        std::sort(middle1, middle2);
      }
      PRAGMA_OMP(section)
      {
        std::sort(middle2, middle3);
      }
      PRAGMA_OMP(section)
      {
        std::sort(middle3, end);
      }
    }

    // Now merge back
    typename std::vector<T> temp1, temp2;
    //PRAGMA_OMP(parallel sections)
    {
      //PRAGMA_OMP(section)
      {
        merge(begin, middle1, middle1, middle2, temp1);
      }
      //PRAGMA_OMP(section)
      {
        merge(middle2, middle3, middle3, end, temp2);
      }
    }

    // We can clear the incoming vector to free up memory now,
    //  because it is copied already in temp1, temp2
    vec.clear();

    // Final merge
    typename std::vector<T> temp;
    merge(temp1.begin(), temp1.end(), temp2.begin(), temp2.end(), temp);

    // Swap storage with the temp vector
    vec.swap(temp);
    // Which we can now clear
    temp.clear();
  }


  // --------------------------------------------------------------------------
  /** Sort events by TOF, using two threads.
   *
   * Performance for 5e7 events:
   *  - 40.5 secs with sortTof() (one thread)
   *  - 21.1 secs with sortTof2() (two threads)
   *  - 18.2 secs with sortTof4() (four threads)
   * Performance gain tends to go up with longer event lists.
   * */
  void EventList::sortTof2() const
  {
    if (this->order == TOF_SORT)
    {
      return; // nothing to do
    }
    if (has_weights)
      parallel_sort2(weightedEvents);
    else
      parallel_sort2(events);

    //Save the order to avoid unnecessary re-sorting.
    this->order = TOF_SORT;
  }

  // --------------------------------------------------------------------------
  /** Sort events by TOF, using four threads.
   *
   * Performance for 5e7 events:
   *  - 40.5 secs with sortTof() (one thread)
   *  - 21.1 secs with sortTof2() (two threads)
   *  - 18.2 secs with sortTof4() (four threads)
   * Performance gain tends to go up with longer event lists.
   * */
  void EventList::sortTof4() const
  {
    if (this->order == TOF_SORT)
    {
      return; // nothing to do
    }

    if (has_weights)
      parallel_sort4(weightedEvents);
    else
      parallel_sort4(events);

    //Save the order to avoid unnecessary re-sorting.
    this->order = TOF_SORT;
  }



  // --------------------------------------------------------------------------
    if (has_weights)
      std::sort(weightedEvents.begin(), weightedEvents.end(), compareEventPulseTime);
    else
      std::sort(events.begin(), events.end(), compareEventPulseTime);
    //Save the order to avoid unnecessary re-sorting.
  // --------------------------------------------------------------------------
  /** Return true if the event list is sorted by TOF */
  bool EventList::isSortedByTof() const
  {
    return (this->order == TOF_SORT);
  }

  // --------------------------------------------------------------------------
  /** Reverse the histogram boundaries and the associated events if they are sorted. */
  void EventList::reverse()
  {
    // reverse the histogram bin parameters
    std::reverse(x.begin(), x.end());
    this->refX.access() = x;

    // flip the events if they are tof sorted
    if (this->isSortedByTof())
    {
      if (has_weights)
        std::reverse(this->weightedEvents.begin(), this->weightedEvents.end());
      else
        std::reverse(this->events.begin(), this->events.end());
      //And we are still sorted! :)
    }
  // --------------------------------------------------------------------------
  /** Return the number of events in the list.
   * NOTE: If the events have weights, this returns the NUMBER of WeightedEvent's in the
   * list, and NOT the sum of their weights (which may be two different numbers).
   *
   * @return the number of events in the list.
Nick Draper's avatar
Nick Draper committed
  size_t EventList::getNumberEvents() const
  {
    if (has_weights)
      return this->weightedEvents.size();
    else
      return this->events.size();
Nick Draper's avatar
Nick Draper committed
  }

  // --------------------------------------------------------------------------
  /** @return :: the memory used by the EventList, in bytes.
   * */
  size_t EventList::getMemorySize() const
  {
    if (has_weights)
      return this->weightedEvents.size() * sizeof(WeightedEvent) + sizeof(EventList);
    else
      return this->events.size() * sizeof(TofEvent) + sizeof(EventList);
  }


  // --------------------------------------------------------------------------
  /** Return the size of the histogram data.
   * @return the size of the histogram representation of the data (size of Y) **/
    size_t x_size = refX->size();
    if (x_size > 1)
      return x_size - 1;
    else
      return 0;


  // ==============================================================================================
  // --- Setting the Histrogram X axis, without recalculating the histogram -----------------------
  // ==============================================================================================

  /** Set the x-component for the histogram view. This will NOT cause the histogram to be calculated.
   * @param X :: The vector of doubles to set as the histogram limits.
   */
  void EventList::setX(const MantidVecPtr::ptr_type& X)
  /** Set the x-component for the histogram view. This will NOT cause the histogram to be calculated.
   * @param X :: The vector of doubles to set as the histogram limits.
   */
  void EventList::setX(const MantidVecPtr& X)
  /** Set the x-component for the histogram view. This will NOT cause the histogram to be calculated.
   * @param X :: The vector of doubles to set as the histogram limits.
   */
  void EventList::setX(const MantidVec& X)
  // ==============================================================================================
  // --- Return Data Vectors --------------------------------------------------
  // ==============================================================================================

  // Note: these will only be called from a const class; e.g
  // const EventList el;
  // el.dataX(); <<<<< this works
  // EventList el2;
  // el2.dataX(); <<<<< this throws an error.

  /** Returns the x data.
   * @return a const reference to the X (bin) vector.
   *  */
  const MantidVec& EventList::dataX() const
  /** Returns a reference to the X data
   * @return a cow_ptr to the X (bin) vector.
   * */
  Kernel::cow_ptr<MantidVec> EventList::getRefX() const
  {
    return refX;
  }
  /** Calculates and returns a pointer to the Y histogrammed data.
   * Remember to delete your pointer after use!
    generateCountsHistogram(*this->refX, *Y);
    return Y;
  /** Calculates and returns a pointer to the E histogrammed data.
   * Remember to delete your pointer after use!
    if (has_weights)
    {
      MantidVec Y;
      MantidVec * E = new MantidVec();
      generateHistogramsForWeights(*this->refX, Y, *E);
      //Y is unused.
      return E;
    }
    else
    {
      MantidVec Y;
      generateCountsHistogram(*this->refX, Y);
      MantidVec * E = new MantidVec();
      generateErrorsHistogram(Y, *E);
      return E;
    }
  }