CHistogrammer

Name

CHistogrammer -- SpecTcl histogramming core

Synopsis


class CHistogrammer : public CEventSink {

  typedef std::list<CGateObserver*>   GateObserverList;
  typedef std::list<CGatingObserver*> GatingObserverList;

  ParameterDictionary m_ParameterDictionary;
  SpectrumDictionary  m_SpectrumDictionary;
  CGateDictionary     m_GateDictionary; 
  GateObserverList    m_gateObservers;  
  GatingObserverList  m_gatingObservers;


  CFlattenedGateList*   m_pGateList;
  CSpectrumByParameter* m_pSpectrumLists;


 public:

  const ParameterDictionary& getParameterDictionary() const ;

  const SpectrumDictionary& getSpectrumDictionary() const ;

 protected:

  void setParameterDictionary(const ParameterDictionary& am_ParameterDictionary);

  void setSpectrumDictionary(const SpectrumDictionary& am_SpectrumDictionary) ;

 public:

  virtual void operator() (const CEvent&     rEvent);
  virtual void operator() (CEventList& rEventList);


  CParameter* AddParameter (const std::string& sName,
			    UInt_t nId,
			    const char* pUnits);
  CParameter* AddParameter (const std::string& sName,
			    UInt_t nId,
			    UInt_t  nScale);
  CParameter* AddParameter (const std::string& sName,
			    UInt_t nId, UInt_t nScale,
			    Float_t nLow, Float_t nHi,
			    const std::string& sUnits);
  CParameter* RemoveParameter (const std::string& sName);
  CParameter* FindParameter (const std::string& rName);
  CParameter* FindParameter (UInt_t nPar);
  ParameterDictionaryIterator ParameterBegin();
  ParameterDictionaryIterator ParameterEnd();
  UInt_t ParameterCount();


  void AddSpectrum(CSpectrum& rSpectrum);
  CSpectrum* RemoveSpectrum(const std::string sName);
  void ClearSpectrum(const std::string& rsName);
  void ClearAllSpectra();
  CSpectrum* FindSpectrum(const std::string& rName);
  CSpectrum* FindSpectrum(UInt_t id);
  SpectrumDictionaryIterator SpectrumBegin();
  SpectrumDictionaryIterator SpectrumEnd();
  UInt_t SpectrumCount();
  void addSpectrumDictionaryObserver(SpectrumDictionaryObserver* observer);
  void removeSpectrumDictionaryObserver(SpectrumDictionaryObserver* observer);

  void UnGate(const std::string& rSpectrum); 

  void AddGate(const std::string& rName, UInt_t nId, CGate& rGate);
  void DeleteGate(const std::string& rGateName);
  void ReplaceGate(const std::string& rGateName, CGate& rGate);
  void ApplyGate(const std::string& rGateName,  const std::string& rSpectrum);
  CGateContainer* FindGate(const std::string& rGate);
  CGateContainer* FindGate(UInt_t nId);
  CGateDictionaryIterator GateBegin();
  CGateDictionaryIterator GateEnd();
  UInt_t GateCount();

  void addGateObserver(CGateObserver* observer);
  void removeGateObserver(CGateObserver* observer);

  void addGatingObserver(CGatingObserver* observer);
  void removeGatingObserver(CGatingObserver* observer);

};
        

DESCRIPTION

Histogramming core of SpecTcl. In addition to performing the actual histogramming, this class encapsulates SpecTcl's dictionaries.

METHODS

The first set of methods get and set attributes. The getter methods are public while the setters are all protected.

const const ParameterDictionary& getParameterDictionary();

Returns a reference to the SpecTcl parameter dictionary. This is a dictionary that contains all of the parameter definitions known to SpecTcl. Note that the SpecTcl API class provides the access to this dictionary that most applications need and should be used instead rather than directly accessing the dictionary.

const const SpectrumDictionary& getSpectrumDictionary();

Returns a reference to the Spectrum dictionary. This contains all of the objects that define the spectra the histogrammer increments. Note that the SpecTcl API class provides the access to this dictionary that most applications need and should be used instead rather than directly accessing the dictionary.

protected: void setParameterDictionary(const ParameterDictionary& am_ParameterDictionary);

Allows derived classes to replace the parameter dictionary. This is only useful in the unlikely event you've derived a new dictionary class from the ParameterDictionary class.

This method should be called early in the lifetime of the derived class to ensure you don't lose existing definitions when replacing the object. The constructor would be a good place to do this.

protected void setSpectrumDictionary(const SpectrumDictionary& am_SpectrumDictionary);

Provides a replacement for a spectrum dictionary. Most of the comments associated with setParameterDictionary apply here.

The next set of methods are invoked externally to perform histogramming. Normally the analyzer object invokes these after building an event list from the results of the analysis pipeline.

virtual void operator()(const CEvent& rEvent);

Resets all of the gates and histograms the rEvent, a single event. Note that the histograms check the gates needed to be incremented so there's no separate pass taken to check all gates. Furthermore, gates cache their results so the actual gate computation is not only performed only on the gates needed but at most once per gate.

virtual void operator() ( CEventList& rEventList);

Iterates over each event in rEventlist invoking the previous overloaded operator() for each element in that list. This is the method invoked by the analyzer object to process events from the event processing pipeline.

The next set of methods mainpulate the parameter dictionary. Note that the SpecTcl API provides methods to accomplish everything these methods accomplish. I recommend using the API singleton to do parameter manipulation or, even simpler, use CTreeParameter objects instead of directly working with SpecTcl low level parameters.

CParameter* AddParameter(const std::string& sName, UInt_t nId, const char* pUnits); , CParameter* AddParameter(const std::string& sName, UInt_t nId, UInt_t nScale); , CParameter* AddParameter (const std::string& sName, UInt_t nId, UInt_t nScale, Float_t nLow, Float_t nHi, const std::string& sUnits);

These methods create a new parameter and add it to the parameter dictionary.

sName is the name of the new parameter. If a parameter with that name already exists, a CDictionaryException is thrown. nId is the parameter's id which is the slot in the CEvent array like object in which parameter values are put. A CDictionaryException is also thrown if a parameter with that Id already exists.

nScale determines the resolution of the parameter in bits. When creating a spetrum on a parameter, consider being informed by this value when determining the binning for axes involving this parameter.

nLow and nHigh are soft limits on the values stored in the parameter. Spectra created with axes defined on this parameter should use these values to inform decisions about the limits on those axes.

sUnits is the units of measure for the parameter. Spectra can label axes with that as a unix of meausre appropriately.

On successful return, a pointer to the new CParameter object is returned.

CParameter* RemoveParameter (const std::string& sName);

Removes the parameter identified by sName from the parameter dictionary. The parameter object is copy constructed into a dynamically allocated CParameter object whose pointer is returned. The return value must therefore be deleted in order to prevent memory leaks.

CParameter* FindParameter(const std::string& rName); , CParameter* FindParameter ( UInt_t nPar);

Returns a pointer to a CParameter object in the parameter dictionary. The parameter returned either has a name equal to rName or a parameter id equal to nPar depending on which actual method is called.

If there is no matching parameter a null pointer is returned.

ParameterDictionaryIterator ParameterBegin();

Returns an iterator to the first element of the parameter dictionary. Parameter dictionary Iterators act like pointers that point to an std::pair<std::string, CParameter>. The first element of this pair is the name of the parameter while the second is the parameter itself.

Incrementing an iterator points to the next element of the container. Incrementing an iterator that points to the last container element returns the same value as returned by ParameterEnd

ParameterDictionaryIterator ParameterEnd();

Returns an value that is no longer in the container. Typical iteration over the parameter dictionary follows this pattern:


CHistogrammer* pH;                     // Assume this points to the histogrammer.
for (auto p = pH->ParameterBegin(); p != pH->ParameteEnd(); p++) {
        // do something with p->first and p->second.
        ...
}

                    
UInt_t ParameterCount();

Returns the number of elements in the parameter dictionary.

The next methods manipulate the spectrum dictionary. The SpecTcl API singleton class provides these services as well and we recommend you use it rather than relyingo n these methods.

void AddSpectrum( CSpectrum& rSpectrum);

Adds a new spectrum object to the spectrum dictionary. The Spectrum's name is used as the dictionary key. The spectrum's id is used as the spectrum number.

If a spectrum matches either the name or the id, a CDictionaryException is thrown.

CSpectrum* RemoveSpectrum(const std::string sName);

Removes a spectrum with the name sName from the spectrum dictionary. A pointer to the removed spectrum is returned to the caller. If there is no matching spectrum, a null pointer is returned.

void ClearSpectrum(const std::string& rsName);

Locates the spectrum in the spectrum dictionary that is named rsName. That spectrum's clear method is called. Normally that method sets all of the channels of the spectrum to 0.

If there is no matching spectrum, a CDictionaryException is thrown.

void ClearAllSpectra();

Iterates through the spectrum dictionary invoking each CSpectrum object's clear method. This sets all channels for all spectra to zero (assuming that's what the clear method does for all subclasses of CSpectrum).

CSpectrum* FindSpectrum(const std::string& rName); , CSpectrum* FindSpectrum( UInt_t id);

The return value of FindSpectrum is a pointer to the CSpectrum object in the spectrum dictionary that matches the search criterion passed in as an argument. rName is the name of the spectrum that must match exactly. id is the spectrum id.

If there is no matching spectrum in the dictionary, a null pointer is returned. Note that the dictionary management methods ensure that there can be at most one match.

SpectrumDictionaryIterator SpectrumBegin(); , SpectrumDictionaryIterator SpectrumEnd();

These methods can be used to iterate over all of the entries in the spectrum dictionary. Both methods return a SpectrumDictionaryIterator. This object acts like a pointer to a std::pair<std:;string, CSpectrum*> object. The first element of the pair is the name of an entry in the dictinoary (spectrum name), the second a pointer to the spectrum with that name.

SpectrumBegin provides an iterator that points to information about the first entry in the dictionary. Incrementing an iterator via its operator++ points it to the next entry in the dictionary. Incremeting the iterator when it points to the last entry of the container makes it equal to the value returned from SpectrumEnd.

Typical spectrum dictionary iteration can use the STL algorithm std::for_each if you have a functor it can call, or can express your operation as a C++ lambda or, without being fancy looks something like (pHisto is a pointer to the histogrammer object).


    for (auto p = pHisto->SpectrumBegin(); p != pHisto->SpectrumEnd(); p++) {
        std::string name = p->first;
        CSpectrum*   pSpec= p->second;
        
        // Do something with the spectrum or name or both.
    }
                    
UInt_t SpectrumCount();

Returns the number of spectra in the spectrum dictionary.

void addSpectrumDictionaryObserver( SpectrumDictionaryObserver* observer); , void removeSpectrumDictionaryObserver( SpectrumDictionaryObserver* observer);

These methods control observers of the spectrum dictionary. For information about the observer programming pattern see: https://en.wikipedia.org/wiki/Observer_pattern. For information about the SpectrumDictionaryObserver abstract base class, see DATA TYPES below.

addSpectrumDictionaryObserver adds an observer whose methods will be called when changes are made to the spectrum dictionary (adding or removing spectra). removeSpectrumObserver removes an existing observer (observer). If the specified observer has not been established, removeSpectrumObserver does nothing.

It is possible to register a single observer object more than once. This is considered a pathology but no effort is made to stop you from doing that. If an observer has been multiply registered, removeSpectrumObserver will remove all instances of that observer object.

The Next group of methods are used to mainpulate gates. In addition to adding and replacing gates in the gate dictionary, this set of methods can apply gates to a spectrum as well as remove any gate application from a spectrum (called ungating).

A couple of words about why gates can't actually be removed/deleted from the gate dictionary. Many gate types are compound gates. Compound gates are formed from logical combinations of othe gates. For example an and gate is true if all of its constituent gates (some of which might also be compound) are true.

It's very hard, therefore to get a good definition of the effect on a compound gate when a gate it depends on (directly or indirectly) is destroyed. Therefore SpecTcl's commands, normally "deletes" a gate not by destroying it but by replacing it with a False gate. This has a consistent well defined behavior with respect not only to gates that directly depend on the 'deleted' gate but also indirectly dependent gates.

void AddGate( const std::string& rName, UInt_t nId, CGate& rGate);

Adds a new gate to the gate dictionary. rName is the name that is given to the gate. It must be unique or else a CDictionaryException will be thrown.

nId is a gate id number. It's value is not actually important to SpecTcl's processing but it too must be unique, or else a CDictionaryException will be thrown

rGate is a reference to the gate that will be added. The object is cloned so that a dynamically created copy is actually stored.

void ReplaceGate( const std::string& rGateName, , CGate& rGate); , void DeleteGate(const std::string& rGateName);

These methods both actually replace the definition of an existing gate. ReplaceGate replaces the defintion of the gate named rGateName with the gate rGate. The previous gate definition object is deleted (recall that addGate makes a dynamic clone).

DeleteGate simply calls ReplaceGate with a false gate. SpecTcl's commands understand that such gates are actually deleted when listing gates.

If no gate named rGateName is defined in the gate dictionary, a CDictionaryException is thrown.

CGateContainer* FindGate( const std::string& rGate); , CGateContainer* FindGate( UInt_t nId);

Locates a gate either by its name (rGate) or integer gate id (nId). If no matching gate is found in the gate dictionary; a nul pointer is returned.

The return value is a pointer to a CGateContainer. For all purposes, you can treat a CGateContainer as a pointer to the gate itself. The gate container is what dependent gates actually use as this allows gate definitions to be modified transparently.

Note that for any specific matched gate, SpecTcl gaurantees that a subsequent search for the same gate (by name or id) will return the same CGateContainer. Furthermore a search for the same gate either by id or by name will, when matched both return the same gate container pointer.

CGateDictionaryIterator GateBegin(); , CGateDictionaryIterator GateEnd();

These methods iteration over thee gate dictionary. A CGateDictionaryIterator is like a pointer to a std::pair<std::string, CGateContainer*>. The first element of the pair is a gate name. The second a gate container that points to the gate that's currently bound to that name.

GateBegin returns an iterator that points to the first element in the gate dictionary. Incrementing this iterator points to the next element of the dictionary. Incrementing the iterator when it points to the last element of the dictionary results in the value returned by GetEnd.

UInt_t GateCount();

Returns the number of entries in the gate dictionary.

void addGateObserver( CGateObserver* observer); , void removeGateObserver( CGateObserver* observer);

These methods manage observers on the gate dictionary. For information about the observer programming pattern see: https://en.wikipedia.org/wiki/Observer_pattern. For information about the CGateObserver abstract base class, see DATA TYPES below.

addGateObserver adds a new observer to the end of the list of observers of the gate dictionary. removeGateObserver removes the observer from the set of observers established on the gate dictionary.

While establishing the same observer more than once is pathalogical, nothing is done to prevent that. If removeGateObserver is passed an observer that has been added more than once, all instances of that observer are removed.

void ApplyGate( const std::string& rGateName, const std::string& rSpectrum);

Applies the gate named rGateName to the spectrum named rSpectrum. If either the gate or the spectrum are not in their respective dictionaries, a CDictionaryException is thrown.

Any previously applied gate remains defined but no longer affects when the spectrum is incremented. If successful, the spectrum can only be incremented if the gate named by rGateName evaluates to true for the event.

void UnGate(const std::string& rSpectrum);

This is like doing a call to ApplyGate to the spectrum named rSpectrum passing a gate that is a true gate.

If rSpectrum does not name a spectrum that is defined in the spectrum dictionary a CDictionaryException is thrown. If successful, rSpectrum is incremented whenever all of the parameters required are present and inside the spectrum's axis bounds.

void addGatingObserver( CGatingObserver* observer); , void removeGatingObserver( CGatingObserver* observer);

Manage the gating observers. Gating observers observe the application of gates to spectra as well as the ungating of spectra. For infoirmation about the observer pattern see https://en.wikipedia.org/wiki/Observer_pattern. For information about CGatingObserver* objects see DATA TYPES below.

addGatingObserver adds a new observer to the end of the list of observers that will be invoked when gate applications/removals are done. removeGatingObserver removes the observer observer from the list of gating observers.

While it is pathalogical to add the same observer more than once, no steps are taken to block this. Furthermore, if removeGatingObserver is asked to remove a gating observer that has been multiply added, all instances of it in the observer list are removed.

DATA TYPES

The CHistogrammer methods use a number of data types. These will be documented in full later in this part of the manual. A brief overview of some of them is given here.

Let's start with dictionaries. The Dictionary.h is a templated class that wraps an std::map object that is indexed by a string. The actual object contained by the map is templated. The functionality added by Dictionaries is support for observation.

Observation, or the observer pattern, is an object oriented programming pattern that allows external objects (observers) to be notified of state changes in another objecdt (the observed objecdt). Dictionary objects maintain a list of observers.

Each observer is an object from class that is derived from DictionaryObserver. This is, inn turn a templated class, templated by the type of object contained by the Dictionary it observers.

The observer base class provides an interface that looks like:


template <class T>
class DictionaryObserver 
{
public:
  virtual void onAdd(std::string   name,   T& item) {}
  virtual void onRemove( std::string name,    T& item) {}

};            
        

Provided a do nothing implementation for each observer method allows useful observers to only implement the methods they care about.

onAdd is called whenever item is added to the dictionary with the name name. This observer method is called after item has been successfullly added to the dictionary.

onRemove is invoked whenever the item associated with name is removed from the dictionary. It is called just prior to item's erasure from the map.

All observers form an ordered list and are called in the order in which they were registered.

While we are talking about Dictionary observers, let's look as well at GatingObserver objects. These allow code to observer the application of gates to spectra and the ungating of a spectrum. As such they don't actually fit well into the dictionary observers described.

Here's the interface presented by a GatingOBserver:


class CGatingObserver
{
public:
    virtual void onApply(const CGateContainer& rGate, CSpectrum& rSpectrum,
                         CHistogrammer& rSorter) = 0;
    virtual void onRemove(const CGateContainer& rGate, CSpectrum& rSpectrum,
                          CHistogrammer& rSorter) = 0;

};

        

As you can guess, onApply is invoked when rGate is applied to rSpectrum. Similarly, onRemove is applied when rSpectrum is un-gated. In that case, rGate is the gate that used to be applied to that spectrum. Note that in all cases, rSorter is a reference to the histogrammer object itself.

Next let's look at the type of dictinoaries CHistogrammer maintains. Each dictionary represents a name indexed store of one of the fundamental classes SpecTcl defines:

ParameterDictionary

The objects contained by this dictionary are CParameter objects. Note that this class is a final class; no subclasses are defined. The class supports copy construction allowing ParameterDictionary to contains CParameter objects rather than pointers or references.

Once created a CParameter object is considered immutable. See the CParameter reference page for more information about that object. Normal code, however should strongly consider using CTreeParameter and CTreeParameterArray objects as front ends to the CParameter objects SpecTcl's guts use.

SpectrumDictionary

This dictionary contains pointers to CSpectrum objects. The CSpectrum class is an abstract base class for concrete classes that implement the rich variety of spectra SpecTcl supports.

Therefore, spectrum objects must be created and then added to the dictionary in a separate step.

In parallel with the spectrum dictionary, SpecTcl maintains data structures that facilitate parameter driven histogramming. Those structures are maintained using the dictionary observer mechanism. Their purpose is to restrict the number of histograms that must be asked to increment themselves for each event to those that depend on at least one parameter present in that event. For sparse events, this results in significant performance improvements.

CGateDictionary

Contains pointers to CGateContainer objects. CGateContainer objects are wrappers for pointers to CGate objects. When they were developed the various pointer like objects in the standard C++ library had not yet been defined and implemented.

A CGateContainer object is a fixed object that can be handed to a user of a gate that is invariant, although the gate it points to may vary with time. If, for example, spectra contained a pointer to their gate, each time the definition of that gate changed, the value of that pointer would need to change too. You can think of a CGateContainer as a hidden pointer the gate pointer with methods that allow it to look like the gate pointer itself.

By handing gated spectra a pointer to their gate's CGateContainer object the underlying gate pointer can be transparently modified with respect to the gate clients.

CGate objects, which are what CGateContainers appear to point at, implement SpecTcl Gates. CGate is an abstract base class for the class hierarchy that represents the rich set of gates SpecTcl defines.

See reference information on gate classes and the gate container for more information.