ActiveVolumeVertexSampler.cxx
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////
2 /// \file ActiveVolumeVertexSampler.cxx
3 /// \brief Algorithm that samples vertex locations uniformly within the
4 /// active volume of a detector. It is fully experiment-agnostic and multi-TPC
5 /// aware.
6 ///
7 /// \author Steven Gardiner <sjgardiner@ucdavis.edu>
8 //////////////////////////////////////////////////////////////////////////////
9 
13 #include "nurandom/RandomUtils/NuRandomService.h"
14 
16 
17 namespace {
18  constexpr int MAX_BOX_ITERATIONS = 10000;
19 }
20 
21 //------------------------------------------------------------------------------
24  rndm::NuRandomService& rand_service, const geo::Geometry& geom,
25  const std::string& generator_name)
26  : fVertexType(vertex_type_t::kSampled), fGeneratorName(generator_name),
27  fTPCDist(nullptr)
28 {
29  // Configure the algorithm using the FHiCL parameters
30  this->reconfigure(conf, geom);
31 
32  // Register the TPC sampling engine with the seed service. If you need the
33  // seed later, get it from the seed service using the value of the variable
34  // generator_name as the instance name.
35  rndm::NuRandomService::seed_t tpc_seed = rand_service.registerEngine(
36  [this](rndm::NuRandomService::EngineId const& /* unused */,
37  rndm::NuRandomService::seed_t lar_seed) -> void
38  {
39  auto seed = static_cast<uint_fast64_t>(lar_seed);
40  // Use the obtained seed to prepare the random number engine. This is
41  // an attempt to do a decent job, but optimally accomplishing this can
42  // be tricky (see, for example,
43  // http://www.pcg-random.org/posts/cpp-seeding-surprises.html)
44  std::seed_seq seed_sequence{seed};
45  fTPCEngine.seed(seed_sequence);
46  },
47  fGeneratorName, conf.get_PSet(), { "seed" }
48  );
49 
50  // TODO: resolve the other workaround mentioned in the MARLEYHelper
51  // class, then fix this as well
52  uint_fast64_t tpc_cast_seed = static_cast<uint_fast64_t>(tpc_seed);
53  std::seed_seq tpc_seed_sequence{tpc_cast_seed};
54  fTPCEngine.seed(tpc_seed_sequence);
55 }
56 
57 //------------------------------------------------------------------------------
59  const geo::Geometry& geom)
60 {
61  // sample a new position if needed
63 
64  // Sample a TPC index using the active masses as weights
65  size_t tpc_index = fTPCDist->operator()(fTPCEngine);
66 
67  // Get the dimensions of the chosen TPC's active volume
68  const auto& tpc = geom.TPC(tpc_index);
69  double minX = tpc.MinX();
70  double maxX = tpc.MaxX();
71  double minY = tpc.MinY();
72  double maxY = tpc.MaxY();
73  double minZ = tpc.MinZ();
74  double maxZ = tpc.MaxZ();
75  std::uniform_real_distribution<double>::param_type x_range(minX, maxX);
76  std::uniform_real_distribution<double>::param_type y_range(minY, maxY);
77  std::uniform_real_distribution<double>::param_type z_range(minZ, maxZ);
78 
79  // Sample a location uniformly over this volume
80  std::uniform_real_distribution<double> uniform_dist;
81  double x = uniform_dist(fTPCEngine, x_range);
82  double y = uniform_dist(fTPCEngine, y_range);
83  double z = uniform_dist(fTPCEngine, z_range);
84  MF_LOG_INFO("ActiveVolumeVertexSampler " + fGeneratorName)
85  << "Sampled primary vertex in TPC #" << tpc_index << ", x = " << x
86  << ", y = " << y << ", z = " << z;
87 
88  // Update the vertex position 4-vector
89  fVertexPosition.SetXYZT(x, y, z, 0.); // TODO: add time sampling
90  }
91  else if (fVertexType == vertex_type_t::kBox) {
92  bool ok = false;
93  int num_iterations = 0;
94 
95  // TODO: reduce code duplication here
96  // Get the range of coordinates covered by the box
97  std::uniform_real_distribution<double>::param_type x_range(fXmin, fXmax);
98  std::uniform_real_distribution<double>::param_type y_range(fYmin, fYmax);
99  std::uniform_real_distribution<double>::param_type z_range(fZmin, fZmax);
100 
101  // Sample a location uniformly over this volume
102  std::uniform_real_distribution<double> uniform_dist;
103 
104  double x = 0.;
105  double y = 0.;
106  double z = 0.;
107  while ( !ok && num_iterations < MAX_BOX_ITERATIONS ) {
108  x = uniform_dist(fTPCEngine, x_range);
109  y = uniform_dist(fTPCEngine, y_range);
110  z = uniform_dist(fTPCEngine, z_range);
111 
112  // If we've been asked to check whether the vertex is within the
113  // active volume of a TPC, verify that. Otherwise just accept the
114  // first vertex position that was sampled unconditionally.
115  if ( fCheckActive ) {
116  size_t num_tpcs = geom.NTPC();
117  for (size_t iTPC = 0; iTPC < num_tpcs; ++iTPC) {
118  const auto& tpc = geom.TPC(iTPC);
119  double minX = tpc.MinX();
120  double maxX = tpc.MaxX();
121  double minY = tpc.MinY();
122  double maxY = tpc.MaxY();
123  double minZ = tpc.MinZ();
124  double maxZ = tpc.MaxZ();
125  if ( x >= minX && x <= maxX && y >= minY && y <= maxY && z >= minZ && z <= maxZ ) {
126  ok = true;
127  break;
128  }
129  }
130  }
131  else ok = true;
132  }
133 
134  if ( !ok ) throw cet::exception("ActiveVolumeVertexSampler " + fGeneratorName)
135  << "Failed to sample a vertex within a TPC active volume after " << MAX_BOX_ITERATIONS
136  << " iterations";
137 
138  MF_LOG_INFO("ActiveVolumeVertexSampler " + fGeneratorName)
139  << "Sampled primary vertex at x = " << x << ", y = " << y
140  << ", z = " << z;
141 
142  // Update the vertex position 4-vector
143  fVertexPosition.SetXYZT(x, y, z, 0.); // TODO: add time sampling
144  }
145 
146  // if we're using a fixed vertex position, we don't need to do any sampling
147  return fVertexPosition;
148 }
149 
150 //------------------------------------------------------------------------------
153  const geo::Geometry& geom)
154 {
155  auto type = conf().type_();
156  if (type == "sampled") {
157 
159 
160  // Get the active masses of each of the TPCs in the current geometry. Use
161  // them as weights for sampling a TPC to use for the primary vertex.
162  std::vector<double> tpc_masses;
163  size_t num_tpcs = geom.NTPC();
164  for (size_t iTPC = 0; iTPC < num_tpcs; ++iTPC) {
165  // For each TPC, use its active mass (returned in kg) as its sampling
166  // weight
167  tpc_masses.push_back(geom.TPC(iTPC).ActiveMass());
168  }
169 
170  // Load the discrete distribution used to sample TPCs with the up-to-date
171  // set of weights
172  fTPCDist.reset(new std::discrete_distribution<size_t>(tpc_masses.begin(),
173  tpc_masses.end()));
174  }
175  else if (type == "fixed") {
176 
178 
179  auto vertex_pos = conf().position_();
180  double Vx = vertex_pos.at(0);
181  double Vy = vertex_pos.at(1);
182  double Vz = vertex_pos.at(2);
183 
184  fVertexPosition.SetXYZT(Vx, Vy, Vz, 0.); // TODO: add time setting
185  }
186  else if (type == "box") {
187 
189  auto min_pos = conf().min_position_();
190  auto max_pos = conf().max_position_();
191 
192  fXmin = min_pos.at(0);
193  fYmin = min_pos.at(1);
194  fZmin = min_pos.at(2);
195 
196  fXmax = max_pos.at(0);
197  fYmax = max_pos.at(1);
198  fZmax = max_pos.at(2);
199 
200  // By default, don't check whether each point is in a TPC active volume
201  fCheckActive = false;
202  // If the user specified this optional parameter, use that instead
203  conf().check_active_( fCheckActive );
204  }
205 
206  else throw cet::exception("ActiveVolumeVertexSampler " + fGeneratorName)
207  << "Invalid vertex type '" << type << "' requested. Allowed values are"
208  << " 'sampled' and 'fixed'";
209 }
std::string string
Definition: nybbler.cc:12
double MinX() const
Returns the world x coordinate of the start of the box.
Definition: BoxBoundedGeo.h:88
ParameterSet const & get_PSet() const
Definition: Table.h:68
Definition: conf.py:1
TLorentzVector sample_vertex_pos(const geo::Geometry &geom)
double ActiveMass() const
Definition: TPCGeo.h:118
ActiveVolumeVertexSampler(const fhicl::Table< Config > &conf, rndm::NuRandomService &rand_service, const geo::Geometry &geom, const std::string &generator_name)
art framework interface to geometry description
Algorithm that samples vertex locations uniformly within the active volume of a detector. It is fully experiment-agnostic and multi-TPC aware.
The geometry of one entire detector, as served by art.
Definition: Geometry.h:196
#define MF_LOG_INFO(category)
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
void reconfigure(const fhicl::Table< Config > &conf, const geo::Geometry &geom)
std::unique_ptr< std::discrete_distribution< size_t > > fTPCDist
list x
Definition: train.py:276
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
Encapsulate the construction of a single detector plane.