Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix histograms for Gaudi v39 and add a configurable histogram #239

Merged
merged 6 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions k4FWCore/scripts/k4run
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,9 @@ def add_arguments(parser, app_mgr):
# skip public tools and the applicationmgr itself
if "ToolSvc" in conf.name() or "ApplicationMgr" in conf.name():
continue
props = (
conf.getPropertiesWithDescription()
) # dict propertyname: (propertyvalue, propertydescription)
# dict propertyname: (propertyvalue, propertydescription)
props = conf.getPropertiesWithDescription()
for prop in props:
# only add arguments for relevant properties
if (
prop in FILTER_GAUDI_PROPS
or "Audit" in prop
Expand Down Expand Up @@ -208,7 +206,15 @@ def main():
opts_dict = vars(opts)
for optionName, propTuple in option_db.items():
logger.info("Option name: %s %s %s", propTuple[1], optionName, opts_dict[optionName])
propTuple[0].setProp(propTuple[1].rsplit(".", 1)[1], opts_dict[optionName])
# After Gaudi v39 the new configurable histograms have properties that are tuples
# and by default one of the member is an empty tuple that Gaudi seems not to like
# when used in setProp - it will try to parse it as a string and fail
if "_Axis" in optionName:
propTuple[0].setProp(
propTuple[1].rsplit(".", 1)[1], tuple(x for x in opts_dict[optionName] if x != ())
)
else:
propTuple[0].setProp(propTuple[1].rsplit(".", 1)[1], opts_dict[optionName])

if opts.verbose:
from Gaudi.Configuration import VERBOSE
Expand Down
8 changes: 8 additions & 0 deletions test/k4FWCoreTest/options/ExampleFunctionalTransformerHist.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@
root_hist_svc = RootHistoSink("RootHistoSink")
root_hist_svc.FileName = "functional_transformer_hist.root"

try:
transformer1.CustomHistogram_Title = "Custom Title"
# Bins can be defined here
transformer1.CustomHistogram_Axis0 = (10, -5.0, 10.0, "X")
# Before Gaudi v39 there isn't a way to set the bins from python
except Exception:
pass


app = ApplicationMgr(
TopAlg=[producer1, producer2, transformer1, transformer2],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,24 @@

#include <string>

#include "GAUDI_VERSION.h"

#if GAUDI_MAJOR_VERSION < 39
namespace Gaudi::Accumulators {
template <unsigned int ND, atomicity Atomicity = atomicity::full, typename Arithmetic = double>
using StaticRootHistogram =
Gaudi::Accumulators::RootHistogramingCounterBase<ND, Atomicity, Arithmetic, naming::histogramString>;
}
#endif

struct ExampleFunctionalTransformerHist final
: k4FWCore::Transformer<edm4hep::MCParticleCollection(const edm4hep::MCParticleCollection& input)> {
StatusCode initialize() override {
#if GAUDI_MAJOR_VERSION >= 39
m_customHistogram.createHistogram(*this);
#endif
return StatusCode::SUCCESS;
}
// The pairs in KeyValues can be changed from python and they correspond
// to the name of the input and output collections respectively
ExampleFunctionalTransformerHist(const std::string& name, ISvcLocator* svcLoc)
Expand All @@ -36,14 +52,26 @@ struct ExampleFunctionalTransformerHist final
// This is the function that will be called to produce the data
edm4hep::MCParticleCollection operator()(const edm4hep::MCParticleCollection& input) const override {
// Fill the histogram with the energy of one particle
++m_histograms[input[0 + !m_firstParticle.value()].getEnergy()];
++m_histogram[input[0 + !m_firstParticle.value()].getEnergy()];
#if GAUDI_MAJOR_VERSION >= 39
++m_customHistogram[input[0 + !m_firstParticle.value()].getEnergy()];
#endif
// Return an empty collection since we don't care about the collection
return {};
}

private:
// This is the histogram that will be filled, 1 is the number of dimensions of the histogram (1D)
mutable Gaudi::Accumulators::RootHistogram<1> m_histograms{this, "Histogram Name", "Histogram Title", {100, 0, 10.}};
mutable Gaudi::Accumulators::StaticRootHistogram<1> m_histogram{
this, "Histogram Name", "Histogram Title", {100, 0, 10.}};

public:
#if GAUDI_MAJOR_VERSION >= 39
// This is a histogram with title, name and bins that can be set from python
// The callback function is only needed for these histograms with configurable properties
void registerCallBack(Gaudi::StateMachine::Transition, std::function<void()>) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this is necessary for any algorithm that has histograms? In that case we need to document it.

Copy link
Contributor Author

@jmcarcell jmcarcell Sep 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is necessary for histograms with configurable properties, I added a comment about that (so the ones that are not Static...).

mutable Gaudi::Accumulators::RootHistogram<1> m_customHistogram{this, "CustomHistogram"};
#endif

Gaudi::Property<bool> m_firstParticle{this, "FirstParticle", true};
};
Expand Down
Loading