Skip to content

Commit

Permalink
refactor: Define interface for generators (#919)
Browse files Browse the repository at this point in the history
This is driven by the python binding implementation. std::function has
the downside of making pybind11 do a round trip through python. This
interface is equivalent, but slightly more complex. I think it's still
acceptable.
  • Loading branch information
paulgessinger committed Aug 27, 2021
1 parent 8b6ae9c commit b87b53c
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ ActsExamples::ProcessCode ActsExamples::EventGenerator::read(
auto& generate = m_cfg.generators[iGenerate];

// generate the primary vertices from this generator
for (size_t n = generate.multiplicity(rng); 0 < n; --n) {
for (size_t n = (*generate.multiplicity)(rng); 0 < n; --n) {
nPrimaryVertices += 1;

// generate primary vertex position
auto vertexPosition = generate.vertex(rng);
auto vertexPosition = (*generate.vertex)(rng);
// generate particles associated to this vertex
auto vertexParticles = generate.particles(rng);
auto vertexParticles = (*generate.particles)(rng);

ACTS_VERBOSE("Generate vertex at " << vertexPosition.transpose());

auto updateParticleInPlace = [&](ActsFatras::Particle& particle) {
// only set the primary vertex, leave everything else as-is
Expand All @@ -65,6 +67,7 @@ ActsExamples::ProcessCode ActsExamples::EventGenerator::read(
.setVertexPrimary(nPrimaryVertices);
// move particle to the vertex
const auto pos4 = (vertexPosition + particle.fourPosition()).eval();
ACTS_VERBOSE(" - particle at " << pos4.transpose());
// `withParticleId` returns a copy because it changes the identity
particle = particle.withParticleId(pid).setPosition4(pos4);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,47 @@ class EventGenerator final : public ActsExamples::IReader {
/// The process generator is responsible for defining all components of the
/// particle barcode except the primary vertex. The primary vertex will be
/// set/overwritten by the event generator.
using MultiplicityGenerator = std::function<size_t(RandomEngine&)>;
using VertexGenerator = std::function<Acts::Vector4(RandomEngine&)>;
using ParticlesGenerator = std::function<SimParticleContainer(RandomEngine&)>;

/// @brief Generator interface for event multiplicity of vertices
struct MultiplicityGenerator {
/// @brief Virtual destructor required
virtual ~MultiplicityGenerator() = default;
/// @brief Generate the multiplicity of vertices
///
/// @param rng Shared random number generator instance
/// @return size_t The multiplicity for the event
virtual size_t operator()(RandomEngine& rng) const = 0;
};

/// @brief Generator interface for a vertex position
struct VertexGenerator {
/// @brief Virtual destructor required
virtual ~VertexGenerator() = default;
/// @brief Generate a vertex position
///
/// @param rng Shared random number generator instance
/// @return Acts::Vector4 The vertex position
virtual Acts::Vector4 operator()(RandomEngine& rng) const = 0;
};

/// @brief Generator interface particles for a vertex
struct ParticlesGenerator {
/// @brief Virtual destructor required
virtual ~ParticlesGenerator() = default;
/// @brief Generate particles for a vertex
/// @note This method cannot be `const` because the Pythia8 generator
/// uses the Pythia8 interfaces, which is non-const
///
/// @param rng Shared random number generator instance
/// @return SimParticleContainer The populated particle container for the vertex
virtual SimParticleContainer operator()(RandomEngine& rng) = 0;
};

/// @brief Combined struct which contains all generator components
struct Generator {
MultiplicityGenerator multiplicity = nullptr;
VertexGenerator vertex = nullptr;
ParticlesGenerator particles = nullptr;
std::shared_ptr<MultiplicityGenerator> multiplicity = nullptr;
std::shared_ptr<VertexGenerator> vertex = nullptr;
std::shared_ptr<ParticlesGenerator> particles = nullptr;
};

struct Config {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,29 @@
#pragma once

#include "ActsExamples/Framework/RandomNumbers.hpp"
#include "ActsExamples/Generators/EventGenerator.hpp"

#include <random>

namespace ActsExamples {

struct FixedMultiplicityGenerator {
struct FixedMultiplicityGenerator
: public EventGenerator::MultiplicityGenerator {
size_t n = 1;

size_t operator()(RandomEngine& /* unused */) const { return n; }
FixedMultiplicityGenerator(size_t _n) : n{_n} {}
FixedMultiplicityGenerator() = default;

size_t operator()(RandomEngine& /* unused */) const override { return n; }
};

struct PoissonMultiplicityGenerator {
struct PoissonMultiplicityGenerator
: public EventGenerator::MultiplicityGenerator {
double mean = 1;
PoissonMultiplicityGenerator(double _mean) : mean{_mean} {}
PoissonMultiplicityGenerator() = default;

size_t operator()(RandomEngine& rng) const {
size_t operator()(RandomEngine& rng) const override {
return (0 < mean) ? std::poisson_distribution<size_t>(mean)(rng) : 0;
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ ActsExamples::ParametricParticleGenerator::ParametricParticleGenerator(
std::numeric_limits<double>::max())) {}

ActsExamples::SimParticleContainer
ActsExamples::ParametricParticleGenerator::operator()(RandomEngine& rng) const {
ActsExamples::ParametricParticleGenerator::operator()(RandomEngine& rng) {
using UniformIndex = std::uniform_int_distribution<unsigned int>;
using UniformReal = std::uniform_real_distribution<double>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "Acts/Utilities/PdgParticle.hpp"
#include "ActsExamples/EventData/SimParticle.hpp"
#include "ActsExamples/Framework/RandomNumbers.hpp"
#include "ActsExamples/Generators/EventGenerator.hpp"

#include <array>
#include <cmath>
Expand All @@ -24,7 +25,7 @@ namespace ActsExamples {
/// direction is drawn from a uniform distribution on the unit sphere (within
/// the given limits). Its absolute momentum is drawn from a uniform
/// distribution. Position and time are always set to zero.
class ParametricParticleGenerator {
class ParametricParticleGenerator : public EventGenerator::ParticlesGenerator {
public:
struct Config {
/// Low, high (exclusive) for the transverse direction angle.
Expand Down Expand Up @@ -52,7 +53,7 @@ class ParametricParticleGenerator {
ParametricParticleGenerator(const Config& cfg);

/// Generate a single primary vertex with the given number of particles.
SimParticleContainer operator()(RandomEngine& rng) const;
SimParticleContainer operator()(RandomEngine& rng) override;

private:
Config m_cfg;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,29 @@

#include "Acts/Definitions/Algebra.hpp"
#include "ActsExamples/Framework/RandomNumbers.hpp"
#include "ActsExamples/Generators/EventGenerator.hpp"

#include <random>

namespace ActsExamples {

struct FixedVertexGenerator {
struct FixedVertexGenerator : public EventGenerator::VertexGenerator {
/// The fixed vertex position and time.
Acts::Vector4 fixed = Acts::Vector4::Zero();

Acts::Vector4 operator()(RandomEngine& /* unused */) const { return fixed; }
Acts::Vector4 operator()(RandomEngine& /* unused */) const override {
return fixed;
}
};

struct GaussianVertexGenerator {
struct GaussianVertexGenerator : public EventGenerator::VertexGenerator {
// standard deviation comes first, since it is more likely to be modified
/// Vertex position and time standard deviation.
Acts::Vector4 stddev = {0.0, 0.0, 0.0, 0.0};
/// Mean vertex position and time.
Acts::Vector4 mean = {0.0, 0.0, 0.0, 0.0};

Acts::Vector4 operator()(RandomEngine& rng) const {
Acts::Vector4 operator()(RandomEngine& rng) const override {
auto normal = std::normal_distribution<double>(0.0, 1.0);
Acts::Vector4 rndNormal = {
normal(rng),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ ActsExamples::Options::readParticleGunOptions(const Variables& vars) {
upper = interval.upper.value() * unit;
};

GaussianVertexGenerator vertexGen;
vertexGen.stddev[Acts::ePos0] = getValue("gen-vertex-xy-std-mm", 1_mm);
vertexGen.stddev[Acts::ePos1] = getValue("gen-vertex-xy-std-mm", 1_mm);
vertexGen.stddev[Acts::ePos2] = getValue("gen-vertex-z-std-mm", 1_mm);
vertexGen.stddev[Acts::eTime] = getValue("gen-vertex-t-std-ns", 1_ns);
auto vertexGen = std::make_shared<GaussianVertexGenerator>();
vertexGen->stddev[Acts::ePos0] = getValue("gen-vertex-xy-std-mm", 1_mm);
vertexGen->stddev[Acts::ePos1] = getValue("gen-vertex-xy-std-mm", 1_mm);
vertexGen->stddev[Acts::ePos2] = getValue("gen-vertex-z-std-mm", 1_mm);
vertexGen->stddev[Acts::eTime] = getValue("gen-vertex-t-std-ns", 1_ns);

ParametricParticleGenerator::Config pgCfg;
getRange("gen-phi-degree", 1_degree, pgCfg.phiMin, pgCfg.phiMax);
Expand All @@ -93,10 +93,13 @@ ActsExamples::Options::readParticleGunOptions(const Variables& vars) {
throw std::runtime_error{"Too many vertices requested for Fatras Barcode"};
}

auto mGen = std::make_shared<FixedMultiplicityGenerator>();
mGen->n = nVertices;

EventGenerator::Config cfg;
cfg.generators = {
{FixedMultiplicityGenerator{nVertices}, std::move(vertexGen),
ParametricParticleGenerator(pgCfg)},
{std::move(mGen), std::move(vertexGen),
std::make_shared<ParametricParticleGenerator>(pgCfg)},
};

return cfg;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@ struct FrameworkRndmEngine : public Pythia8::RndmEngine {
};
} // namespace

std::function<ActsExamples::SimParticleContainer(ActsExamples::RandomEngine&)>
ActsExamples::Pythia8Generator::makeFunction(const Config& cfg,
Acts::Logging::Level lvl) {
auto gen = std::make_shared<Pythia8Generator>(cfg, lvl);
return [=](RandomEngine& rng) { return (*gen)(rng); };
}

ActsExamples::Pythia8Generator::Pythia8Generator(const Config& cfg,
Acts::Logging::Level lvl)
: m_cfg(cfg),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "Acts/Utilities/PdgParticle.hpp"
#include "ActsExamples/EventData/SimParticle.hpp"
#include "ActsExamples/Framework/RandomNumbers.hpp"
#include "ActsExamples/Generators/EventGenerator.hpp"

#include <memory>
#include <mutex>
Expand All @@ -23,7 +24,7 @@ class Pythia;
}
namespace ActsExamples {

class Pythia8Generator {
class Pythia8Generator : public EventGenerator::ParticlesGenerator {
public:
struct Config {
/// PDG particle number of the first incoming beam.
Expand All @@ -36,9 +37,6 @@ class Pythia8Generator {
std::vector<std::string> settings = {{"HardQCD:all = on"}};
};

static std::function<SimParticleContainer(RandomEngine&)> makeFunction(
const Config& cfg, Acts::Logging::Level lvl);

Pythia8Generator(const Config& cfg, Acts::Logging::Level lvl);
~Pythia8Generator();
// try to prevent pythia breakage by forbidding copying
Expand All @@ -48,7 +46,7 @@ class Pythia8Generator {
Pythia8Generator& operator=(const Pythia8Generator&) = delete;
Pythia8Generator& operator=(Pythia8Generator&& other) = delete;

SimParticleContainer operator()(RandomEngine& rng);
SimParticleContainer operator()(RandomEngine& rng) override;

private:
/// Private access to the logging instance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ ActsExamples::EventGenerator::Config ActsExamples::Options::readPythia8Options(
vars["gen-pdg-beam1"].template as<int32_t>());
const auto cmsEnergy = vars["gen-cms-energy-gev"].as<double>() * 1_GeV;

GaussianVertexGenerator vertexGen;
vertexGen.stddev[Acts::ePos0] =
auto vertexGen = std::make_shared<GaussianVertexGenerator>();
vertexGen->stddev[Acts::ePos0] =
vars["gen-vertex-xy-std-mm"].as<double>() * 1_mm;
vertexGen.stddev[Acts::ePos1] =
vertexGen->stddev[Acts::ePos1] =
vars["gen-vertex-xy-std-mm"].as<double>() * 1_mm;
vertexGen.stddev[Acts::ePos2] =
vertexGen->stddev[Acts::ePos2] =
vars["gen-vertex-z-std-mm"].as<double>() * 1_mm;
vertexGen.stddev[Acts::eTime] =
vertexGen->stddev[Acts::eTime] =
vars["gen-vertex-t-std-ns"].as<double>() * 1_ns;

EventGenerator::Config cfg;
Expand All @@ -84,8 +84,9 @@ ActsExamples::EventGenerator::Config ActsExamples::Options::readPythia8Options(
hard.cmsEnergy = cmsEnergy;
hard.settings = vars["gen-hard-process"].as<std::vector<std::string>>();

cfg.generators.push_back({FixedMultiplicityGenerator{nhard}, vertexGen,
Pythia8Generator::makeFunction(hard, lvl)});
cfg.generators.push_back(
{std::make_shared<FixedMultiplicityGenerator>(nhard), vertexGen,
std::make_shared<Pythia8Generator>(hard, lvl)});
}
if (0.0 < npileup) {
Pythia8Generator::Config pileup;
Expand All @@ -94,8 +95,9 @@ ActsExamples::EventGenerator::Config ActsExamples::Options::readPythia8Options(
pileup.cmsEnergy = cmsEnergy;
pileup.settings = vars["gen-pileup-process"].as<std::vector<std::string>>();

cfg.generators.push_back({PoissonMultiplicityGenerator{npileup}, vertexGen,
Pythia8Generator::makeFunction(pileup, lvl)});
cfg.generators.push_back(
{std::make_shared<PoissonMultiplicityGenerator>(npileup), vertexGen,
std::make_shared<Pythia8Generator>(pileup, lvl)});
}

return cfg;
Expand Down

0 comments on commit b87b53c

Please sign in to comment.