classCHistogrammer
: publicCEventSink
{ 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); };
Histogramming core of SpecTcl. In addition to performing the actual histogramming, this class encapsulates SpecTcl's dictionaries.
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.
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.