Skip to content
Snippets Groups Projects
Commit 50a08bfe authored by Charles Burton's avatar Charles Burton Committed by Walter Lampl
Browse files

Arrays of Histograms

parent 696bb5b9
No related branches found
No related tags found
No related merge requests found
...@@ -209,6 +209,7 @@ public: ...@@ -209,6 +209,7 @@ public:
*/ */
ToolHandle<GenericMonitoringTool> getGroup( const std::string& name ) const; ToolHandle<GenericMonitoringTool> getGroup( const std::string& name ) const;
/** /**
* Get the trigger decision tool member. * Get the trigger decision tool member.
* *
...@@ -219,7 +220,6 @@ public: ...@@ -219,7 +220,6 @@ public:
*/ */
const ToolHandle<Trig::ITrigDecisionTool>& getTrigDecisionTool() const; const ToolHandle<Trig::ITrigDecisionTool>& getTrigDecisionTool() const;
/** /**
* Check whether triggers are passed * Check whether triggers are passed
* *
...@@ -238,7 +238,7 @@ public: ...@@ -238,7 +238,7 @@ public:
* @param ctx EventContext for the event * @param ctx EventContext for the event
* @return a SG::ReadHandle<xAOD::EventInfo> * @return a SG::ReadHandle<xAOD::EventInfo>
*/ */
SG::ReadHandle<xAOD::EventInfo> GetEventInfo(const EventContext&) const; SG::ReadHandle<xAOD::EventInfo> GetEventInfo( const EventContext& ) const;
/** @defgroup lumi Luminosity Functions /** @defgroup lumi Luminosity Functions
* A group of functions which all deal with calculating luminosity. * A group of functions which all deal with calculating luminosity.
...@@ -248,42 +248,42 @@ public: ...@@ -248,42 +248,42 @@ public:
/** /**
* Calculate the average mu, i.e. <mu>. * Calculate the average mu, i.e. <mu>.
*/ */
virtual float lbAverageInteractionsPerCrossing (const EventContext& ctx = Gaudi::Hive::currentContext()) const; virtual float lbAverageInteractionsPerCrossing( const EventContext& ctx = Gaudi::Hive::currentContext() ) const;
/** /**
* Calculate instantaneous number of interactions, i.e. mu. * Calculate instantaneous number of interactions, i.e. mu.
*/ */
virtual float lbInteractionsPerCrossing (const EventContext& ctx = Gaudi::Hive::currentContext()) const; virtual float lbInteractionsPerCrossing( const EventContext& ctx = Gaudi::Hive::currentContext() ) const;
/** /**
* Calculate average luminosity (in ub-1 s-1 => 10^30 cm-2 s-1). * Calculate average luminosity (in ub-1 s-1 => 10^30 cm-2 s-1).
*/ */
virtual float lbAverageLuminosity (const EventContext& ctx = Gaudi::Hive::currentContext()) const; virtual float lbAverageLuminosity( const EventContext& ctx = Gaudi::Hive::currentContext() ) const;
/** /**
* Calculate the instantaneous luminosity per bunch crossing. * Calculate the instantaneous luminosity per bunch crossing.
*/ */
virtual float lbLuminosityPerBCID (const EventContext& ctx = Gaudi::Hive::currentContext()) const; virtual float lbLuminosityPerBCID( const EventContext& ctx = Gaudi::Hive::currentContext() ) const;
/** /**
* Calculate the duration of the luminosity block (in seconds) * Calculate the duration of the luminosity block (in seconds)
*/ */
virtual double lbDuration (const EventContext& ctx = Gaudi::Hive::currentContext()) const; virtual double lbDuration( const EventContext& ctx = Gaudi::Hive::currentContext() ) const;
/** /**
* Calculate the average luminosity livefraction * Calculate the average luminosity livefraction
*/ */
virtual float lbAverageLivefraction (const EventContext& ctx = Gaudi::Hive::currentContext()) const; virtual float lbAverageLivefraction( const EventContext& ctx = Gaudi::Hive::currentContext() ) const;
/** /**
* Calculate the live fraction per bunch crossing ID. * Calculate the live fraction per bunch crossing ID.
*/ */
virtual float livefractionPerBCID (const EventContext& ctx = Gaudi::Hive::currentContext()) const; virtual float livefractionPerBCID( const EventContext& ctx = Gaudi::Hive::currentContext() ) const;
/** /**
* Calculate the average integrated luminosity multiplied by the live fraction. * Calculate the average integrated luminosity multiplied by the live fraction.
*/ */
virtual double lbLumiWeight (const EventContext& ctx = Gaudi::Hive::currentContext()) const; virtual double lbLumiWeight( const EventContext& ctx = Gaudi::Hive::currentContext() ) const;
/** @} */ // end of lumi group /** @} */ // end of lumi group
...@@ -341,6 +341,7 @@ protected: ...@@ -341,6 +341,7 @@ protected:
Gaudi::Property<int> m_detailLevel {this,"DetailLevel",0}; ///< Sets the level of detail used in the monitoring Gaudi::Property<int> m_detailLevel {this,"DetailLevel",0}; ///< Sets the level of detail used in the monitoring
SG::ReadHandleKey<xAOD::EventInfo> m_EventInfoKey {this,"EventInfoKey","EventInfo"}; ///< Key for retrieving EventInfo from StoreGate SG::ReadHandleKey<xAOD::EventInfo> m_EventInfoKey {this,"EventInfoKey","EventInfo"}; ///< Key for retrieving EventInfo from StoreGate
private: private:
typedef std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>> MonVarVec_t; typedef std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>> MonVarVec_t;
std::string m_name; std::string m_name;
......
...@@ -17,6 +17,10 @@ public: ...@@ -17,6 +17,10 @@ public:
virtual StatusCode initialize() override; virtual StatusCode initialize() override;
virtual StatusCode fillHistograms( const EventContext& ctx ) const override; virtual StatusCode fillHistograms( const EventContext& ctx ) const override;
private: private:
Gaudi::Property<bool> m_doRandom {this,"RandomHist",false}; Gaudi::Property<bool> m_doRandom {this,"RandomHist",false};
std::vector<int> m_abGroups1;
std::vector<std::vector<int>> m_abGroups2;
std::map<std::string,int> m_cGroups1;
std::map<std::string,std::map<std::string,int>> m_cGroups2;
}; };
#endif #endif
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <functional> #include <functional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <stdexcept>
#include "GaudiKernel/ToolHandle.h" #include "GaudiKernel/ToolHandle.h"
...@@ -108,6 +109,63 @@ namespace Monitored { ...@@ -108,6 +109,63 @@ namespace Monitored {
} }
} }
} }
// Sub-namespace for internal-use functions
namespace detail {
/** Finds the index of an element in a tool handle array by its string name */
template <typename T = int>
int findToolIndex( const ToolHandleArray<GenericMonitoringTool>& toolArray, const std::string& name ) {
auto it = std::find_if(toolArray.begin(),toolArray.end(),[&](const auto& r) {return r.name()==name;});
return it!=toolArray.end()
? std::distance(toolArray.begin(),it)
: throw std::runtime_error("The tool "+name+" could not be found in the tool array.");
}
}
/** Builds an array of indices (base case) */
template<typename V,typename std::enable_if_t<std::is_integral_v<V>>* =nullptr>
std::vector<V> buildToolMap(ToolHandleArray<GenericMonitoringTool> tools, const std::string& baseName, int nHist) {
std::vector<int> indexArray;
for ( int iHist=0; iHist<nHist; iHist++ ) {
std::string groupName = baseName + "_" + std::to_string(iHist);
indexArray.push_back(detail::findToolIndex(tools,groupName));
}
return indexArray;
}
/** Builds an N-dimensional array of indices (recursive) */
template<typename V,typename std::enable_if_t<!std::is_integral_v<V>>* =nullptr,typename...T>
std::vector<V> buildToolMap(ToolHandleArray<GenericMonitoringTool> tools, const std::string& baseName, int nHist, T... dimensions) {
std::vector<V> indexArray;
for ( int iHist=0; iHist<nHist; iHist++ ) {
std::string groupName = baseName + "_" + std::to_string(iHist);
indexArray.push_back(buildToolMap<typename V::value_type>(tools,groupName,dimensions...));
}
return indexArray;
}
/** Builds a map of indices (base case) */
template<typename V,typename std::enable_if_t<std::is_integral_v<V>>* =nullptr>
std::map<std::string,int> buildToolMap(ToolHandleArray<GenericMonitoringTool> tools, const std::string& baseName, std::vector<std::string> labels) {
std::map<std::string,int> indexMap;
for ( auto label : labels ) {
std::string groupName = baseName + "_" + label;
indexMap[label] = detail::findToolIndex(tools,groupName);
}
return indexMap;
}
/** Builds an N-dimensional map of indices (recursive) */
template<typename V,typename std::enable_if_t<!std::is_integral_v<V>>* =nullptr,typename...T>
std::map<std::string,V> buildToolMap(ToolHandleArray<GenericMonitoringTool> tools, const std::string& baseName, std::vector<std::string> labels, T... dimensions) {
std::map<std::string,V> indexMap;
for ( auto label : labels ) {
std::string groupName = baseName + "_" + label;
indexMap[label] = buildToolMap<typename V::mapped_type>(tools,groupName,dimensions...);
}
return indexMap;
}
} // namespace Monitored } // namespace Monitored
#endif /* AthenaMonitoring_MonitoredGroup_h */ #endif /* AthenaMonitoring_MonitoredGroup_h */
...@@ -57,7 +57,7 @@ class AthMonitorCfgHelper(object): ...@@ -57,7 +57,7 @@ class AthMonitorCfgHelper(object):
algObj = algClassOrObj(name, *args, **kwargs) algObj = algClassOrObj(name, *args, **kwargs)
else: else:
algObj = algClassOrObj algObj = algClassOrObj
# configure these properties; users really should have no reason to override them # configure these properties; users really should have no reason to override them
algObj.Environment = self.inputFlags.DQ.Environment algObj.Environment = self.inputFlags.DQ.Environment
algObj.DataType = self.inputFlags.DQ.DataType algObj.DataType = self.inputFlags.DQ.DataType
...@@ -80,40 +80,64 @@ class AthMonitorCfgHelper(object): ...@@ -80,40 +80,64 @@ class AthMonitorCfgHelper(object):
return algObj return algObj
def addGroup(self, alg, name, topPath='', defaultDuration='run'): def addGroup(self, alg, name, topPath='', defaultDuration='run'):
''' '''Add a group to an algorithm
Add a "group" (technically, a GenericMonitoringTool instance) to an algorithm. The name given
here can be used to retrieve the group from within the algorithm when calling the fill() Technically, adding a GenericMonitoringTool instance. The name given here can be
function. (Note this is *not* the same thing as the Monitored::Group class.) used to retrieve the group from within the algorithm when calling the fill()
function. Note this is *not* the same thing as the Monitored::Group class. To
avoid replication of code, this calls the more general case, getArray with an 1D
array of length 1.
Arguments: Arguments:
alg -- algorithm Configurable object (e.g. one returned from addAlgorithm) alg -- algorithm Configurable object (e.g. one returned from addAlgorithm)
name -- name of the group name -- name of the group
topPath -- directory name in the output ROOT file under which histograms will be produced topPath -- directory name in the output ROOT file under which histograms will be
defaultDuration -- default duration of histograms produced under this group; can be overridden for each specific histogram produced
defaultDuration -- default time between histogram reset for all histograms in
group; can be overridden for each specific histogram
Returns: Returns:
tool -- a GenericMonitoringTool Configurable object. This can be used to define histograms tool -- a GenericMonitoringTool Configurable object. This can be used to define
associated with that group (using defineHistogram). histograms associated with that group (using defineHistogram).
''' '''
from AthenaMonitoring.GenericMonitoringTool import GenericMonitoringTool array = self.addArray([1],alg,name,topPath=topPath,defaultDuration=defaultDuration)
tool = GenericMonitoringTool(name) return array[0]
def addArray(self, dimensions, alg, baseName, topPath='', defaultDuration='run'):
'''Add many groups to an algorithm
Arguments:
alg -- algorithm Configurable object
baseName -- base name of the group. postfixes are added by GMT Array initialize
topPath -- directory name in the output ROOT file under which histograms will be
produced
duration -- default time between histogram reset for all histograms in group
Returns:
tool -- a GenericMonitoringToolArray object. This is used to define histograms
associated with each group in the array.
'''
from AthenaMonitoring.GenericMonitoringTool import GenericMonitoringArray
array = GenericMonitoringArray(baseName,dimensions)
if self.inputFlags.DQ.isReallyOldStyle: if self.inputFlags.DQ.isReallyOldStyle:
from AthenaCommon.AppMgr import ServiceMgr from AthenaCommon.AppMgr import ServiceMgr
tool.THistSvc = ServiceMgr.THistSvc array.broadcast('THistSvc',ServiceMgr.THistSvc)
else: else:
acc = getDQTHistSvc(self.inputFlags) acc = getDQTHistSvc(self.inputFlags)
self.resobj.merge(acc) self.resobj.merge(acc)
tool.HistPath = self.inputFlags.DQ.FileKey + ('/%s' % topPath if topPath else '') pathToSet = self.inputFlags.DQ.FileKey+('/%s' % topPath if topPath else '')
array.broadcast('HistPath',pathToSet)
# in the future, autodetect if we are online or not # in the future, autodetect if we are online or not
tool.convention = 'OFFLINE' array.broadcast('convention','OFFLINE')
tool.defaultDuration = defaultDuration array.broadcast('defaultDuration',defaultDuration)
alg.GMTools += [tool] alg.GMTools += array.toolList()
return tool return array
def result(self): def result(self):
''' '''
This function should be called to finalize the creation of the set of monitoring algorithms. Finalize the creation of the set of monitoring algorithms.
Returns: Returns:
(resobj, monSeq) -- a tuple with a ComponentAccumulator and an AthSequencer (resobj, monSeq) -- a tuple with a ComponentAccumulator and an AthSequencer
......
...@@ -79,6 +79,7 @@ def ExampleMonitoringConfig(inputFlags): ...@@ -79,6 +79,7 @@ def ExampleMonitoringConfig(inputFlags):
# Add a GMT for the other example monitor algorithm # Add a GMT for the other example monitor algorithm
anotherGroup = helper.addGroup(anotherExampleMonAlg,'ExampleMonitor') anotherGroup = helper.addGroup(anotherExampleMonAlg,'ExampleMonitor')
### STEP 5 ### ### STEP 5 ###
# Configure histograms # Configure histograms
myGroup.defineHistogram('lumiPerBCID',title='Luminosity,WithCommaInTitle;L/BCID;Events', myGroup.defineHistogram('lumiPerBCID',title='Luminosity,WithCommaInTitle;L/BCID;Events',
...@@ -91,14 +92,39 @@ def ExampleMonitoringConfig(inputFlags): ...@@ -91,14 +92,39 @@ def ExampleMonitoringConfig(inputFlags):
xbins=[0,.1,.2,.4,.8,1.6]) xbins=[0,.1,.2,.4,.8,1.6])
myGroup.defineHistogram('random,pT', type='TH2F', title='title;x;y',path='ToBringThemAll', myGroup.defineHistogram('random,pT', type='TH2F', title='title;x;y',path='ToBringThemAll',
xbins=[0,.1,.2,.4,.8,1.6],ybins=[0,10,30,40,60,70,90]) xbins=[0,.1,.2,.4,.8,1.6],ybins=[0,10,30,40,60,70,90])
myGroup.defineHistogram('pT_passed,pT',type='TEfficiency',title='Test TEfficiency;x;Eff', # myGroup.defineHistogram('pT_passed,pT',type='TEfficiency',title='Test TEfficiency;x;Eff',
path='AndInTheDarkness',xbins=100,xmin=0.0,xmax=50.0) # path='AndInTheDarkness',xbins=100,xmin=0.0,xmax=50.0)
anotherGroup.defineHistogram('lbWithFilter',title='Lumi;lb;Events', anotherGroup.defineHistogram('lbWithFilter',title='Lumi;lb;Events',
path='top',xbins=1000,xmin=-0.5,xmax=999.5) path='top',xbins=1000,xmin=-0.5,xmax=999.5)
anotherGroup.defineHistogram('run',title='Run Number;run;Events', anotherGroup.defineHistogram('run',title='Run Number;run;Events',
path='top',xbins=1000000,xmin=-0.5,xmax=999999.5) path='top',xbins=1000000,xmin=-0.5,xmax=999999.5)
# Example defining an array of histograms. This is useful if one seeks to create a
# number of histograms in an organized manner. (For instance, one plot for each ASIC
# in the subdetector, and these components are mapped in eta, phi, and layer.) Thus,
# one might have an array of TH1's such as quantity[etaIndex][phiIndex][layerIndex].
for alg in [exampleMonAlg,anotherExampleMonAlg]:
# Using an array of groups
array = helper.addArray([2],alg,'ExampleMonitor')
array.defineHistogram('a,b',title='AB',type='TH2F',path='Eta',
xbins=10,xmin=0.0,xmax=10.0,
ybins=10,ymin=0.0,ymax=10.0)
array.defineHistogram('c',title='C',path='Eta',
xbins=10,xmin=0.0,xmax=10.0)
array = helper.addArray([4,2],alg,'ExampleMonitor')
array.defineHistogram('a',title='A',path='EtaPhi',
xbins=10,xmin=0.0,xmax=10.0)
# Using a map of groups
layerList = ['layer1','layer2']
clusterList = ['clusterX','clusterB']
array = helper.addArray([layerList],alg,'ExampleMonitor')
array.defineHistogram('c',title='C',path='Layer',
xbins=10,xmin=0,xmax=10.0)
array = helper.addArray([layerList,clusterList],alg,'ExampleMonitor')
array.defineHistogram('c',title='C',path='LayerCluster',
xbins=10,xmin=0,xmax=10.0)
### STEP 6 ### ### STEP 6 ###
# Finalize. The return value should be a tuple of the ComponentAccumulator # Finalize. The return value should be a tuple of the ComponentAccumulator
# and the sequence containing the created algorithms. If we haven't called # and the sequence containing the created algorithms. If we haven't called
...@@ -141,7 +167,7 @@ if __name__=='__main__': ...@@ -141,7 +167,7 @@ if __name__=='__main__':
cfg.merge(exampleMonitorAcc) cfg.merge(exampleMonitorAcc)
# If you want to turn on more detailed messages ... # If you want to turn on more detailed messages ...
#exampleMonitorAcc.getEventAlgo('ExampleMonAlg').OutputLevel = 2 # DEBUG # exampleMonitorAcc.getEventAlgo('ExampleMonAlg').OutputLevel = 2 # DEBUG
cfg.printConfig(withDetails=False) # set True for exhaustive info cfg.printConfig(withDetails=False) # set True for exhaustive info
cfg.run() #use cfg.run(20) to only run on first 20 events cfg.run() #use cfg.run(20) to only run on first 20 events
...@@ -27,6 +27,62 @@ class GenericMonitoringTool(_GenericMonitoringTool): ...@@ -27,6 +27,62 @@ class GenericMonitoringTool(_GenericMonitoringTool):
kwargs['convention'] = self.convention + ':' + self.defaultDuration kwargs['convention'] = self.convention + ':' + self.defaultDuration
self.Histograms.append(defineHistogram(*args, **kwargs)) self.Histograms.append(defineHistogram(*args, **kwargs))
class GenericMonitoringArray:
'''Array of configurables of GenericMonitoringTool objects'''
def __init__(self, name, dimensions, **kwargs):
self.Tools = {}
for postfix in GenericMonitoringArray._postfixes(dimensions):
self.Tools[postfix] = GenericMonitoringTool(name+postfix,**kwargs)
def __getitem__(self,index):
'''Forward operator[] on class to the list of tools'''
return self.toolList()[index]
def toolList(self):
return list(self.Tools.values())
def broadcast(self, member, value):
'''Allows one to set attributes of every tool simultaneously
Arguments:
member -- string which contains the name of the attribute to be set
value -- value of the attribute to be set
'''
for tool in self.toolList():
setattr(tool,member,value)
def defineHistogram(self, varname, **kwargs):
'''Propogate defineHistogram to each tool, adding a unique tag.'''
unAliased = varname.split(';')[0]
aliasBase = varname.split(';')[1] if ';' in varname else varname.replace(',','')
for postfix,tool in self.Tools.items():
aliased = unAliased+';'+aliasBase+postfix
tool.defineHistogram(aliased,**kwargs)
@staticmethod
def _postfixes(dimensions, previous=''):
'''Generates a list of subscripts to add to the name of each tool.
Arguments:
dimensions -- List containing the lengths of each side of the array off tools
previous -- Strings appended from the other dimensions of the array
'''
assert isinstance(dimensions,list) and len(dimensions)>0
if dimensions==[1]:
return ['']
postList = []
first = dimensions[0]
if isinstance(first,list):
iterable = first
elif isinstance(first,int):
iterable = range(first)
for i in iterable:
if len(dimensions)==1:
postList.append(previous+'_'+str(i))
else:
postList.extend(GenericMonitoringArray._postfixes(dimensions[1:],previous+'_'+str(i)))
return postList
## Generate histogram definition string for the `GenericMonitoringTool.Histograms` property ## Generate histogram definition string for the `GenericMonitoringTool.Histograms` property
# #
# For full details see the GenericMonitoringTool documentation. # For full details see the GenericMonitoringTool documentation.
......
...@@ -14,6 +14,14 @@ ExampleMonitorAlgorithm::~ExampleMonitorAlgorithm() {} ...@@ -14,6 +14,14 @@ ExampleMonitorAlgorithm::~ExampleMonitorAlgorithm() {}
StatusCode ExampleMonitorAlgorithm::initialize() { StatusCode ExampleMonitorAlgorithm::initialize() {
using namespace Monitored;
m_abGroups1 = buildToolMap<int>(m_tools,"ExampleMonitor",2);
m_abGroups2 = buildToolMap<std::vector<int>>(m_tools,"ExampleMonitor",4,2);
std::vector<std::string> layers = {"layer1","layer2"};
std::vector<std::string> clusters = {"clusterX","clusterB"};
m_cGroups1 = buildToolMap<int>(m_tools,"ExampleMonitor",layers);
m_cGroups2 = buildToolMap<std::map<std::string,int>>(m_tools,"ExampleMonitor",layers,clusters);
return AthMonitorAlgorithm::initialize(); return AthMonitorAlgorithm::initialize();
} }
...@@ -33,7 +41,7 @@ StatusCode ExampleMonitorAlgorithm::fillHistograms( const EventContext& ctx ) co ...@@ -33,7 +41,7 @@ StatusCode ExampleMonitorAlgorithm::fillHistograms( const EventContext& ctx ) co
auto pT_passed = Monitored::Scalar<bool>("pT_passed",false); auto pT_passed = Monitored::Scalar<bool>("pT_passed",false);
// Set the values of the monitored variables for the event // Set the values of the monitored variables for the event
lumiPerBCID = lbAverageInteractionsPerCrossing (ctx); lumiPerBCID = lbAverageInteractionsPerCrossing(ctx);
lb = GetEventInfo(ctx)->lumiBlock(); lb = GetEventInfo(ctx)->lumiBlock();
run = GetEventInfo(ctx)->runNumber(); run = GetEventInfo(ctx)->runNumber();
testweight = 2.0; testweight = 2.0;
...@@ -59,6 +67,30 @@ StatusCode ExampleMonitorAlgorithm::fillHistograms( const EventContext& ctx ) co ...@@ -59,6 +67,30 @@ StatusCode ExampleMonitorAlgorithm::fillHistograms( const EventContext& ctx ) co
std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>> varVec = {lumiPerBCID,pT}; std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>> varVec = {lumiPerBCID,pT};
fill("ExampleMonitor",varVec); fill("ExampleMonitor",varVec);
fill(tool,varVec); fill(tool,varVec);
// Filling using a pre-defined array of groups.
auto a = Scalar<float>("a",0.0);
auto b = Scalar<float>("b",1.0);
auto c = Scalar<float>("c",2.0);
for ( auto iEta : {0,1} ) {
// 1) Valid but inefficient fill
fill("ExampleMonitor_"+std::to_string(iEta),a,b,c);
// 2) Faster way to fill a vector of histograms
fill(m_tools[m_abGroups1[iEta]],a,b,c);
for ( auto iPhi : {0,1} ) {
// Same efficient method for 2D array
fill(m_tools[m_abGroups2[iEta][iPhi]],a,b);
}
}
// Filling using a pre-defined map of groups.
for ( auto& layer : std::vector<std::string>({"layer1","layer2"}) ) {
fill(m_tools[m_cGroups1.at(layer)],c);
for ( auto& cluster : std::vector<std::string>({"clusterX","clusterB"}) ) {
// Same efficient method for 2D map
fill(m_tools[m_cGroups2.at(layer).at(cluster)],c);
}
}
return StatusCode::SUCCESS; return StatusCode::SUCCESS;
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment