diff --git a/include/Rivet/Tools/RivetYODA.hh b/include/Rivet/Tools/RivetYODA.hh
--- a/include/Rivet/Tools/RivetYODA.hh
+++ b/include/Rivet/Tools/RivetYODA.hh
@@ -1,354 +1,350 @@
 #ifndef RIVET_RIVETYODA_HH
 #define RIVET_RIVETYODA_HH
 
 /// @author Andy Buckley
 /// @date   2009-01-30
 /// @author David Grellscheid
 /// @date   2011-07-18
 /// @author David Grellscheid
 /// @date   2016-09-27
 
 #include "Rivet/Config/RivetCommon.hh"
 
 #include "YODA/AnalysisObject.h"
 #include "YODA/Counter.h"
 #include "YODA/Histo1D.h"
 #include "YODA/Histo2D.h"
 #include "YODA/Profile1D.h"
 #include "YODA/Profile2D.h"
 #include "YODA/Scatter1D.h"
 #include "YODA/Scatter2D.h"
 #include "YODA/Scatter3D.h"
 
 #include <map>
 
 namespace YODA {
     typedef std::shared_ptr<YODA::AnalysisObject> AnalysisObjectPtr;
     typedef std::shared_ptr<YODA::Histo1D> Histo1DPtr;
     typedef std::shared_ptr<YODA::Histo2D> Histo2DPtr;
     typedef std::shared_ptr<YODA::Profile1D> Profile1DPtr;
     typedef std::shared_ptr<YODA::Profile2D> Profile2DPtr;
     typedef std::shared_ptr<YODA::Scatter1D> Scatter1DPtr;
     typedef std::shared_ptr<YODA::Scatter2D> Scatter2DPtr;
     typedef std::shared_ptr<YODA::Scatter3D> Scatter3DPtr;
     typedef std::shared_ptr<YODA::Counter> CounterPtr;
 }
 
 
 
 namespace Rivet {
 
 
     class AnalysisObjectPtr {
         public:
             virtual ~AnalysisObjectPtr() {}
 
             virtual YODA::AnalysisObject* operator->() = 0;
             virtual YODA::AnalysisObject* operator->() const = 0;
             virtual const YODA::AnalysisObject & operator*() const = 0;
 
             bool operator ==(const AnalysisObjectPtr& p) { return (this == &p); }
 
         protected:
             /// @todo do we need this?
             // virtual void reset() = 0;
     };
 
     /// @todo
     /// implement scatter1dptr and scatter2dptr here
     class Scatter1DPtr : public AnalysisObjectPtr {
         public:
             Scatter1DPtr() :
                 _scatter(YODA::Scatter1DPtr()) { }
 
             Scatter1DPtr(const YODA::Scatter1DPtr& p) :
                 _scatter(p) { }
 
             bool operator!() const { return !_scatter; }
             operator bool() const { return bool(_scatter); }
 
             YODA::Scatter1D* operator->() { return _scatter.get(); }
 
             YODA::Scatter1D* operator->() const { return _scatter.get(); }
 
             YODA::Scatter1D & operator*() { return *_scatter; }
 
             const YODA::Scatter1D & operator*() const { return *_scatter; }
 
         protected:
             YODA::Scatter1DPtr _scatter;
     };
 
     class Scatter2DPtr : public AnalysisObjectPtr {
         public:
             Scatter2DPtr(const YODA::Scatter2DPtr& p) :
                 _scatter(p) { }
 
             Scatter2DPtr() :
                 _scatter(YODA::Scatter2DPtr()) { }
 
             bool operator!() { return !_scatter; }
             operator bool() { return bool(_scatter); }
 
             YODA::Scatter2D* operator->() { return _scatter.get(); }
 
             YODA::Scatter2D* operator->() const { return _scatter.get(); }
 
             YODA::Scatter2D & operator*() { return *_scatter; }
 
             const YODA::Scatter2D & operator*() const { return *_scatter; }
 
         protected:
             YODA::Scatter2DPtr _scatter;
     };
 
     class Scatter3DPtr : public AnalysisObjectPtr {
         public:
             Scatter3DPtr(const YODA::Scatter3DPtr& p) :
                 _scatter(p) { }
 
             Scatter3DPtr() :
                 _scatter(YODA::Scatter3DPtr()) { }
 
             bool operator!() { return !_scatter; }
             operator bool() { return bool(_scatter); }
 
             YODA::Scatter3D* operator->() { return _scatter.get(); }
 
             YODA::Scatter3D* operator->() const { return _scatter.get(); }
 
             YODA::Scatter3D & operator*() { return *_scatter; }
 
             const YODA::Scatter3D & operator*() const { return *_scatter; }
 
         protected:
             YODA::Scatter3DPtr _scatter;
     };
 
 
     class MultiweightAOPtr : public AnalysisObjectPtr {
 
         public:
             virtual void newSubEvent() = 0;
 
             /// @todo 
             /// rename to setActive(Idx)?
             virtual void setActiveWeightIdx(unsigned int iWeight) = 0;
 
             virtual void pushToPersistent(const vector<vector<double> >& weight) = 0;
 
             virtual YODA::AnalysisObjectPtr activeYODAPtr() const = 0;
     };
 
 
 
 template <class T>
     using Fill = pair<typename T::FillType, double>;
 
 template <class T>
     using Fills = multiset<Fill<T>>;
 
 
+// TODO TODO TODO 
+// need to override the old fill method too!
+// otherwise we can't intercept existing fill calls in analysis code
+// 
+// need to 
+// TODO TODO TODO
+
 template <class T>
 class TupleWrapper : public T {
 public:
     typedef shared_ptr<TupleWrapper> Ptr;
 
     TupleWrapper(const T & h) : T(h) {}
 
-    using T::fill;
-
     // todo: do we need to deal with users using fractions directly?
     void fill(typename T::FillType x, double weight=1.0, double fraction=1.0) {
         fills_.insert( {x, weight} );
     }
 
     void reset() {
         fills_.clear();
     }
 
     const Fills<T> & fills() const { return fills_; }
 
 private:
     // x / weight pairs 
     Fills<T> fills_;
 };
 
 
     template <class T>
     class Wrapper : public MultiweightAOPtr {
         public:
 
         /* @todo
          * some things are not really well-defined here
          * for instance: fill() in the finalize() method and integral() in
          * the analyze() method.
          */
 
         Wrapper(size_t len_of_weightvec, const T & p) {
             for (size_t i = 0; i < len_of_weightvec; i++)
                 _persistent.push_back(make_shared<T>(p));
         }
 
         typename T::Ptr active() const { return _active; }
 
         /* @todo this probably need to loop over all? */
         bool operator!() const { return !active(); }
         operator bool() const { return bool(active()); }
 
         T * operator->() {
             return active().get();
         }
 
         T * operator->() const {
             return active().get();
         }
 
         T & operator*() {
             return *active();
         }
 
         const T & operator*() const {
             return *active();
         }
 
         /* @todo
          * these need to be re-thought out.
 
          void reset() { active()->reset(); }
          */
 
         /* @todo
          * these probably need to loop over all?
          * do we even want to provide equality?
          */
         /* @todo
          * how about no.
         friend bool operator==(Wrapper a, Wrapper b){
             if (a._persistent.size() != b._persistent.size())
                 return false;
 
             for (size_t i = 0; i < a._persistent.size(); i++) {
                 if (a._persistent.at(i) != b._persistent.at(i)) {
                     return false;
                 }
             }
 
             return true;
         }
 
         friend bool operator!=(Wrapper a, Wrapper b){
             return !(a == b);
         }
 
 
         friend bool operator<(Wrapper a, Wrapper b){
             if (a._persistent.size() >= b._persistent.size())
                 return false;
 
             for (size_t i = 0; i < a._persistent.size(); i++) {
                 if (*(a._persistent.at(i)) >= *(b._persistent.at(i))) {
                     return false;
                 }
             }
 
             return true;
         }
         */
 
 
         private:
         void setActiveWeightIdx(unsigned int iWeight) {
             _active = _persistent.at(iWeight);
         }
 
         /* this is for dev only---we shouldn't need this in real runs. */
         void unsetActiveWeight() {
             _active.reset();
         }
 
         void newSubEvent() {
             typename TupleWrapper<T>::Ptr tmp
                 = make_shared<TupleWrapper<T>>(_persistent[0]->clone());
             tmp->reset();
             _evgroup.push_back( tmp );
             _active = _evgroup.back();
         }
 
         virtual YODA::AnalysisObjectPtr activeYODAPtr() const {
             return _active;
         }
 
         const vector<typename T::Ptr> & persistent() const {
             return _persistent;
         }
 
         /* to be implemented for each type */
         void pushToPersistent(const vector<vector<double> >& weight);
 
         /* M of these, one for each weight */
         vector<typename T::Ptr> _persistent;
 
         /* N of these, one for each event in evgroup */
         vector<typename TupleWrapper<T>::Ptr> _evgroup;
 
         typename T::Ptr _active;
 
         friend class AnalysisHandler;
     };
 
 
-
-using Histo1DTuple = TupleWrapper<YODA::Histo1D>;
-
-
-
     // every object listed here needs a virtual fill method in YODA,
     // otherwise the Tuple fakery won't work.
 
     using Histo1DPtr = Wrapper<YODA::Histo1D>;
-
-    using Histo2DPtr = Wrapper<YODA::Histo2D>;
-
-    //RIVETAOPTR_COMMON(Histo1D)
-    // RIVETAOPTR_COMMON(Histo2D)
-    // RIVETAOPTR_COMMON(Profile1D)
-    // RIVETAOPTR_COMMON(Profile2D)
-    // RIVETAOPTR_COMMON(Counter)
+    //using Histo2DPtr = Wrapper<YODA::Histo2D>;
+    using Profile1DPtr = Wrapper<YODA::Profile1D>;
+    using Profile2DPtr = Wrapper<YODA::Profile2D>;
+    using CounterPtr = Wrapper<YODA::Counter>;
 
     using YODA::Counter;
     using YODA::Histo1D;
     using YODA::HistoBin1D;
     using YODA::Histo2D;
     using YODA::HistoBin2D;
     using YODA::Profile1D;
     using YODA::ProfileBin1D;
     using YODA::Profile2D;
     using YODA::ProfileBin2D;
     using YODA::Scatter1D;
     using YODA::Point1D;
     using YODA::Scatter2D;
     using YODA::Point2D;
     using YODA::Scatter3D;
     using YODA::Point3D;
 
     /// Function to get a map of all the refdata in a paper with the
     /// given @a papername.
     map<string, YODA::AnalysisObjectPtr> getRefData(const string& papername);
 
     /// @todo Also provide a Scatter3D getRefData() version?
 
     /// Get the file system path to the reference file for this paper.
     string getDatafilePath(const string& papername);
 
     /// Return the integral over the histogram bins
     /// @deprecated Prefer to directly use the histo's integral() method.
     DEPRECATED("Prefer to directly use the histo's integral() method.")
         inline double integral(Histo1DPtr histo) {
             return histo->integral();
         }
 
 
 }
 
 #endif
diff --git a/src/Tools/RivetYODA.cc b/src/Tools/RivetYODA.cc
--- a/src/Tools/RivetYODA.cc
+++ b/src/Tools/RivetYODA.cc
@@ -1,287 +1,300 @@
 #include "Rivet/Config/RivetCommon.hh"
 #include "Rivet/Tools/RivetYODA.hh"
 #include "Rivet/Tools/RivetPaths.hh"
 #include "YODA/ReaderYODA.h"
 #include "YODA/ReaderAIDA.h"
 
 using namespace std;
 
 namespace Rivet {
 
 
   string getDatafilePath(const string& papername) {
     /// Try to find YODA otherwise fall back to try AIDA
     const string path1 = findAnalysisRefFile(papername + ".yoda");
     if (!path1.empty()) return path1;
     const string path2 = findAnalysisRefFile(papername + ".aida");
     if (!path2.empty()) return path2;
     throw Rivet::Error("Couldn't find ref data file '" + papername + ".yoda/aida" +
                        " in $RIVET_REF_PATH, '" + getRivetDataPath() + "', or '.'");
   }
 
 
   map<string, YODA::AnalysisObjectPtr> getRefData(const string& papername) {
     const string datafile = getDatafilePath(papername);
 
     // Make an appropriate data file reader and read the data objects
     /// @todo Remove AIDA support some day...
     YODA::Reader& reader = (datafile.find(".yoda") != string::npos) ?   \
       YODA::ReaderYODA::create() : YODA::ReaderAIDA::create();
     vector<YODA::AnalysisObject *> aovec;
     reader.read(datafile, aovec);
 
     // Return value, to be populated
     map<string, YODA::AnalysisObjectPtr> rtn;
     foreach ( YODA::AnalysisObject* ao, aovec ) {
       YODA::AnalysisObjectPtr refdata(ao);
       if (!refdata) continue;
       const string plotpath = refdata->path();
       // Split path at "/" and only return the last field, i.e. the histogram ID
       const size_t slashpos = plotpath.rfind("/");
       const string plotname = (slashpos+1 < plotpath.size()) ? plotpath.substr(slashpos+1) : "";
       rtn[plotname] = refdata;
     }
     return rtn;
   }
 }
 
 namespace {
 
   using Rivet::Fill;
   using Rivet::Fills;
 
   template <class T>
   void fillAllPersistent(const vector<typename T::Ptr> & persistent, 
                          typename T::FillType x, double w, 
                          const vector<double> & weight) {
     for ( size_t m = 0; m < persistent.size(); ++m ) {
       persistent[m]->fill( x, w * weight[m] );
     }
   }
 
     template <class T>
     double get_window_size(const typename T::Ptr & histo,
                            typename T::BinType x) {
         // the bin index we fall in
         const auto binidx = histo->binIndexAt(x);
         // gaps, overflow, underflow don't contribute
         if ( binidx == -1 ) 
             return 0;
 
 
         const auto & b = histo->bin(binidx);
 
         // if we don't have a valid neighbouring bin,
         // we use infinite width
         typename T::Bin b1(-1.0/0.0, 1.0/0.0);
 
         // points in the top half compare to the upper neighbour
         if ( x > b.xMid() ) {
             int nextidx = binidx + 1;
             if ( nextidx < histo->bins().size() )
                 b1 = histo->bin(nextidx);
         }
         else { // compare to the lower neighbour
             int nextidx = binidx - 1;
             if ( nextidx >= 0 )
                 b1 = histo->bin(nextidx);
         }
         // the factor 2 is arbitrary, could poss. be smaller
         return min( b.width(), b1.width() ) / 2.0;
     }
 
     // template <class T>
     // double getX(T a) {
     //   return a;
     // }
 
     // template <>
     // double getX<tuple<double,double> >(tuple<double,double> a) {
     //   return get<0>(a);
     // }
 
 
 
   template <class T>
   void commit(typename T::Ptr & persistent,
               const vector< vector<Fill<T> > > & tuple,
               const vector<double> weights /* generator weight over subevents */) {
     for ( const auto & x : tuple ) {
       double maxwindow = 0.0;
       for ( const auto & xi : x ) {
         // check for NOFILL here
         double window = get_window_size<T>(persistent, xi.first);
         if ( window > maxwindow )
           maxwindow = window;
       }
       const double wsize = maxwindow;
       // all windows have same size
 
       set<double> edgeset;
       // bin edges need to be in here!
       for ( const auto & xi : x ) {
         edgeset.insert((xi.first) - wsize);
         edgeset.insert((xi.first) + wsize);
       }
 
       vector< std::tuple<double,double,double> > hfill;
       double sumf = 0.0;
       auto edgit = edgeset.begin();
       double ehi = *edgit;
       while ( ++edgit != edgeset.end() ) {
         double elo = ehi;
         ehi = *edgit;
         double sumw = 0.0;
         bool gap = true; // Check for gaps between the sub-windows.
         for ( int i = 0; i < x.size(); ++i  ) {
           // check equals comparisons here!
           if ( (x[i].first) + wsize >= ehi && (x[i].first) - wsize <= elo ) {
             sumw += x[i].second * weights[i];
             gap = false;
           }
         }
         if ( gap ) continue;
         hfill.push_back(make_tuple((ehi + elo)/2.0, sumw, ehi - elo));
         sumf += ehi - elo;
       }
       for ( auto f : hfill )
         persistent->fill( get<0>(f), get<1>(f), get<2>(f)/sumf );
         // Note the scaling to one single fill
     }
   }
 
     template <class T>
     double distance(T a, T b) {
       return abs(a - b);
     }
 
     template <>
     double distance<tuple<double,double> >(tuple<double,double> a, tuple<double,double> b) {
       return Rivet::sqr(get<0>(a) - get<0>(b)) + Rivet::sqr(get<1>(a) - get<1>(b));
     }
 
 
 
 }
 
 
 
 
 /// fills is a vector of sub-event with an ordered set of x-values of
 /// the fills in each sub-event. NOFILL should be an "impossible"
 /// value for this histogram. Returns a vector of sub-events with
 /// an ordered vector of fills (including NOFILLs) for each sub-event.
 template <class T>
 vector< vector<Fill<T> > > 
 match_fills(const vector< Fills<T> > & fills, const Fill<T> & NOFILL) 
 {
   vector< vector<Fill<T> > > matched;
   // First just copy subevents into vectors and find the longest vector.
   unsigned int maxfill = 0; // length of biggest vector
   int imax = 0; // index position of biggest vector
   for ( const auto & subev : fills ) {
     if ( subev.size() > maxfill ) {
       maxfill = subev.size();
       imax = matched.size();
     }
     matched.push_back(vector<Fill<T> >(subev.begin(), subev.end()));
   }
   // Now, go through all subevents with missing fills.
   const vector<Fill<T>> & full = matched[imax]; // the longest one
   for ( auto & subev : matched ) {
     if ( subev.size() == maxfill ) continue;
 
     // Add NOFILLs to the end;
     while ( subev.size() < maxfill ) subev.push_back(NOFILL);
 
     // Iterate from the back and shift all fill values backwards by
     // swapping with NOFILLs so that they better match the full
     // subevent.
     for ( int i = maxfill - 1; i >= 0; --i ) {
       if ( subev[i] == NOFILL ) continue;
       int j = i;
       while ( j + 1 < maxfill && subev[j + 1] == NOFILL &&
               distance(subev[j].first, full[j].first) > distance(subev[j].first, full[j + 1].first) ) 
       {
             swap(subev[j], subev[j + 1]);
             ++j;
       }
     }
   }
   // transpose
   vector<vector<Fill<T>>> result(maxfill,vector<Fill<T>>(matched.size()));
   for (size_t i = 0; i < matched.size(); ++i)
       for (size_t j = 0; j < maxfill; ++j)
           result.at(j).at(i) = matched.at(i).at(j);
   return result;
 }
 
 
 
 
 
 
 namespace Rivet {
 
   template <class T>
   void Wrapper<T>::pushToPersistent(const vector<vector<double> >& weight) {
 
       // have we had subevents at all?
       const bool have_subevents = _evgroup.size() > 1;
       if ( ! have_subevents ) {
         assert( _evgroup.size() == 1 && weight.size() == 1 );
         // simple replay of all tuple entries
         // each recorded fill is inserted into all persistent weightname histos
         for ( const auto & f : _evgroup[0]->fills() ) {
           fillAllPersistent<T>( _persistent, f.first, f.second, weight[0] );
         }
       } else {
         assert( _evgroup.size() == weight.size() );
 
         // All the fills across subevents
         // each item in allFills is a subevent
         vector<Fills<T>> allFills;
         for ( const auto & ev : _evgroup )
           allFills.push_back( ev->fills() );
 
         vector< vector<Fill<T> > > 
           linedUpXs = match_fills<T>(allFills, {typename T::FillType(), 0.0});
 
         for ( size_t m = 0; m < _persistent.size(); ++m ) {
           commit<T>( _persistent[m], linedUpXs, weight[m] );
         }
       }
-
       _evgroup.clear();
       _active.reset();
   }
 
-  static Histo1DPtr foobar1 = Histo1DPtr(13, YODA::Histo1D() );
+  template <>
+  void Wrapper<YODA::Counter>::pushToPersistent(
+              const vector<vector<double> >& weight) {
+    for ( size_t m = 0; m < _persistent.size(); ++m ) {
+      for ( const auto & f : _evgroup[m]->fills() ) {
+          fillAllPersistent<YODA::Counter>( _persistent, f.first, f.second, weight[m] );
+      }
+    }
+  }
+
+  static auto foobar1 = Histo1DPtr(13, YODA::Histo1D() );
+
+  static auto foobar2 = CounterPtr(13, YODA::Counter() );
+
+  //static auto foobar3 = Profile1DPtr(13, YODA::Profile1D() );
 
   // static Histo2DPtr foobar2 = Histo2DPtr(13, YODA::Histo2D() );
 
 
   // void Histo2DPtr::pushToPersistent(const vector<vector<double> >& weight) {
   //     /// @todo
 
   //     return;
   // }
 
   // void Profile1DPtr::pushToPersistent(const vector<vector<double> >& weight) {
   //     /// @todo
 
   //     return;
   // }
 
   // void Profile2DPtr::pushToPersistent(const vector<vector<double> >& weight) {
   //     /// @todo
 
   //     return;
   // }
 
   // void CounterPtr::pushToPersistent(const vector<vector<double> >& weight) {
   //     /// @todo
 
   //     return;
   // }
 }