LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
DlVertexingAlgorithm.cc
Go to the documentation of this file.
1 
9 #include <chrono>
10 #include <cmath>
11 
12 #include <torch/script.h>
13 #include <torch/torch.h>
14 
19 
21 
22 using namespace pandora;
23 using namespace lar_content;
24 
25 namespace lar_dl_content
26 {
27 
28 DlVertexingAlgorithm::DlVertexingAlgorithm() :
29  m_trainingMode{false},
31  m_event{-1},
32  m_pass{1},
33  m_nClasses{0},
34  m_height{256},
35  m_width{256},
36  m_driftStep{0.5f},
37  m_visualise{false},
38  m_writeTree{false},
39  m_rng(static_cast<std::mt19937::result_type>(std::chrono::high_resolution_clock::now().time_since_epoch().count())),
40  m_volumeType{"dune_fd_hd"}
41 {
42 }
43 
45 {
46  if (m_writeTree)
47  {
48  try
49  {
50  PANDORA_MONITORING_API(SaveTree(this->GetPandora(), m_rootTreeName, m_rootFileName, "RECREATE"));
51  }
52  catch (StatusCodeException e)
53  {
54  std::cout << "VertexAssessmentAlgorithm: Unable to write to ROOT tree" << std::endl;
55  }
56  }
57 }
58 
59 //-----------------------------------------------------------------------------------------------------------------------------------------
60 
62 {
63  if (m_trainingMode)
64  return this->PrepareTrainingSample();
65  else
66  return this->Infer();
67 
68  return STATUS_CODE_SUCCESS;
69 }
70 
72 {
74  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->GetMCToHitsMap(mcToHitsMap));
75  MCParticleList hierarchy;
76  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->CompleteMCHierarchy(mcToHitsMap, hierarchy));
77 
78  // Get boundaries for hits and make x dimension common
79  std::map<HitType, float> wireMin, wireMax;
80  float driftMin{std::numeric_limits<float>::max()}, driftMax{-std::numeric_limits<float>::max()};
81  for (const std::string &listname : m_caloHitListNames)
82  {
83  const CaloHitList *pCaloHitList{nullptr};
84  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, listname, pCaloHitList));
85  if (pCaloHitList->empty())
86  continue;
87 
88  HitType view{pCaloHitList->front()->GetHitType()};
89  float viewDriftMin{driftMin}, viewDriftMax{driftMax};
90  this->GetHitRegion(*pCaloHitList, viewDriftMin, viewDriftMax, wireMin[view], wireMax[view]);
91  driftMin = std::min(viewDriftMin, driftMin);
92  driftMax = std::max(viewDriftMax, driftMax);
93  }
94  for (const std::string &listname : m_caloHitListNames)
95  {
96  const CaloHitList *pCaloHitList(nullptr);
97  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, listname, pCaloHitList));
98  if (pCaloHitList->empty())
99  continue;
100 
101  HitType view{pCaloHitList->front()->GetHitType()};
102  const bool isU{view == TPC_VIEW_U}, isV{view == TPC_VIEW_V}, isW{view == TPC_VIEW_W};
103  if (!(isU || isV || isW))
104  return STATUS_CODE_NOT_ALLOWED;
105 
106  CartesianPointVector vertices;
107  for (const MCParticle *mc : hierarchy)
108  {
109  if (LArMCParticleHelper::IsNeutrino(mc))
110  vertices.push_back(mc->GetVertex());
111  }
112  if (vertices.empty())
113  continue;
114  const CartesianVector &vertex{vertices.front()};
115  const std::string trainingFilename{m_trainingOutputFile + "_" + listname + ".csv"};
116  const unsigned long nVertices{1};
117  unsigned long nHits{0};
118  const unsigned int nuance{LArMCParticleHelper::GetNuanceCode(hierarchy.front())};
119 
120  // Vertices
121  const LArTransformationPlugin *transform{this->GetPandora().GetPlugins()->GetLArTransformationPlugin()};
122  const double xVtx{vertex.GetX()};
123  double zVtx{0.};
124  if (isW)
125  zVtx = transform->YZtoW(vertex.GetY(), vertex.GetZ());
126  else if (isV)
127  zVtx = transform->YZtoV(vertex.GetY(), vertex.GetZ());
128  else
129  zVtx = transform->YZtoU(vertex.GetY(), vertex.GetZ());
130 
131  // Calo hits
132  double xMin{driftMin}, xMax{driftMax}, zMin{wireMin[view]}, zMax{wireMax[view]};
133 
134  // Only train on events where the vertex resides within the image - with a small tolerance
135  if (!(xVtx > (xMin - 1.f) && xVtx < (xMax + 1.f) && zVtx > (zMin - 1.f) && zVtx < (zMax + 1.f)))
136  continue;
137 
138  LArMvaHelper::MvaFeatureVector featureVector;
139  featureVector.emplace_back(static_cast<double>(nuance));
140  featureVector.emplace_back(static_cast<double>(nVertices));
141  featureVector.emplace_back(xVtx);
142  featureVector.emplace_back(zVtx);
143  // Retain the hit region
144  featureVector.emplace_back(xMin);
145  featureVector.emplace_back(xMax);
146  featureVector.emplace_back(zMin);
147  featureVector.emplace_back(zMax);
148 
149  for (const CaloHit *pCaloHit : *pCaloHitList)
150  {
151  const float x{pCaloHit->GetPositionVector().GetX()}, z{pCaloHit->GetPositionVector().GetZ()}, adc{pCaloHit->GetMipEquivalentEnergy()};
152  // If on a refinement pass, drop hits outside the region of interest
153  if (m_pass > 1 && (x < xMin || x > xMax || z < zMin || z > zMax))
154  continue;
155  featureVector.emplace_back(static_cast<double>(x));
156  featureVector.emplace_back(static_cast<double>(z));
157  featureVector.emplace_back(static_cast<double>(adc));
158  ++nHits;
159  }
160  featureVector.insert(featureVector.begin() + 8, static_cast<double>(nHits));
161  // Only write out the feature vector if there were enough hits in the region of interest
162  if (nHits > 10)
163  LArMvaHelper::ProduceTrainingExample(trainingFilename, true, featureVector);
164  }
165 
166  return STATUS_CODE_SUCCESS;
167 }
168 
169 //-----------------------------------------------------------------------------------------------------------------------------------------
170 
172 {
173  if (m_pass == 1)
174  ++m_event;
175 
176  std::map<HitType, float> wireMin, wireMax;
177  float driftMin{std::numeric_limits<float>::max()}, driftMax{-std::numeric_limits<float>::max()};
178  for (const std::string &listname : m_caloHitListNames)
179  {
180  const CaloHitList *pCaloHitList{nullptr};
181  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, listname, pCaloHitList));
182  if (pCaloHitList->empty())
183  continue;
184 
185  HitType view{pCaloHitList->front()->GetHitType()};
186  float viewDriftMin{driftMin}, viewDriftMax{driftMax};
187  this->GetHitRegion(*pCaloHitList, viewDriftMin, viewDriftMax, wireMin[view], wireMax[view]);
188  driftMin = std::min(viewDriftMin, driftMin);
189  driftMax = std::max(viewDriftMax, driftMax);
190  }
191 
192  CartesianPointVector vertexCandidatesU, vertexCandidatesV, vertexCandidatesW;
193  for (const std::string &listName : m_caloHitListNames)
194  {
195  const CaloHitList *pCaloHitList{nullptr};
196  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, listName, pCaloHitList));
197 
198  HitType view{pCaloHitList->front()->GetHitType()};
199  const bool isU{view == TPC_VIEW_U}, isV{view == TPC_VIEW_V}, isW{view == TPC_VIEW_W};
200  if (!isU && !isV && !isW)
201  return STATUS_CODE_NOT_ALLOWED;
202 
204  PixelVector pixelVector;
205  this->MakeNetworkInputFromHits(*pCaloHitList, view, driftMin, driftMax, wireMin[view], wireMax[view], input, pixelVector);
206 
207  // Run the input through the trained model
209  inputs.push_back(input);
211  if (isU)
212  LArDLHelper::Forward(m_modelU, inputs, output);
213  else if (isV)
214  LArDLHelper::Forward(m_modelV, inputs, output);
215  else
216  LArDLHelper::Forward(m_modelW, inputs, output);
217 
218  int colOffset{0}, rowOffset{0}, canvasWidth{m_width}, canvasHeight{m_height};
219  this->GetCanvasParameters(output, pixelVector, colOffset, rowOffset, canvasWidth, canvasHeight);
220 
221  float **canvas{new float *[canvasHeight]};
222  for (int row = 0; row < canvasHeight; ++row)
223  canvas[row] = new float[canvasWidth]{};
224 
225  // we want the maximum value in the num_classes dimension (1) for every pixel
226  auto classes{torch::argmax(output, 1)};
227  // the argmax result is a 1 x height x width tensor where each element is a class id
228  auto classesAccessor{classes.accessor<long, 3>()};
229  const double scaleFactor{std::sqrt(m_height * m_height + m_width * m_width)};
230  std::map<int, bool> haveSeenMap;
231  for (const auto &[row, col] : pixelVector)
232  {
233  const auto cls{classesAccessor[0][row][col]};
234  if (cls > 0 && cls < m_nClasses)
235  {
236  const int inner{static_cast<int>(std::round(std::ceil(scaleFactor * m_thresholds[cls - 1])))};
237  const int outer{static_cast<int>(std::round(std::ceil(scaleFactor * m_thresholds[cls])))};
238  this->DrawRing(canvas, row + rowOffset, col + colOffset, inner, outer, 1.f / (outer * outer - inner * inner));
239  }
240  }
241 
242  CartesianPointVector positionVector;
244  canvas, canvasWidth, canvasHeight, colOffset, rowOffset, view, driftMin, driftMax, wireMin[view], wireMax[view], positionVector);
245  if (isU)
246  vertexCandidatesU.emplace_back(positionVector.front());
247  else if (isV)
248  vertexCandidatesV.emplace_back(positionVector.front());
249  else
250  vertexCandidatesW.emplace_back(positionVector.front());
251 
252 #ifdef MONITORING
253  if (m_visualise)
254  {
255  PANDORA_MONITORING_API(SetEveDisplayParameters(this->GetPandora(), true, DETECTOR_VIEW_XZ, -1.f, 1.f, 1.f));
256  try
257  {
258  float x{0.f}, u{0.f}, v{0.f}, w{0.f};
259  this->GetTrueVertexPosition(x, u, v, w);
260  if (isU)
261  {
262  const CartesianVector trueVertex(x, 0.f, u);
263  PANDORA_MONITORING_API(AddMarkerToVisualization(this->GetPandora(), &trueVertex, "U(true)", BLUE, 3));
264  }
265  else if (isV)
266  {
267  const CartesianVector trueVertex(x, 0.f, v);
268  PANDORA_MONITORING_API(AddMarkerToVisualization(this->GetPandora(), &trueVertex, "V(true)", BLUE, 3));
269  }
270  else if (isW)
271  {
272  const CartesianVector trueVertex(x, 0.f, w);
273  PANDORA_MONITORING_API(AddMarkerToVisualization(this->GetPandora(), &trueVertex, "W(true)", BLUE, 3));
274  }
275  }
276  catch (StatusCodeException &e)
277  {
278  std::cerr << "DlVertexingAlgorithm: Warning. Couldn't find true vertex." << std::endl;
279  }
280  for (const auto &pos : positionVector)
281  {
282  std::string label{isU ? "U" : isV ? "V" : "W"};
283  PANDORA_MONITORING_API(AddMarkerToVisualization(this->GetPandora(), &pos, label, RED, 3));
284  }
285  PANDORA_MONITORING_API(ViewEvent(this->GetPandora()));
286  }
287 #endif
288 
289  for (int row = 0; row < canvasHeight; ++row)
290  delete[] canvas[row];
291  delete[] canvas;
292  }
293 
294  int nEmptyLists{0};
295  if (vertexCandidatesU.empty())
296  ++nEmptyLists;
297  if (vertexCandidatesV.empty())
298  ++nEmptyLists;
299  if (vertexCandidatesW.empty())
300  ++nEmptyLists;
301  std::vector<VertexTuple> vertexTuples;
302  CartesianPointVector candidates3D;
303  if (nEmptyLists == 0)
304  {
305  vertexTuples.emplace_back(VertexTuple(this->GetPandora(), vertexCandidatesU.front(), vertexCandidatesV.front(), vertexCandidatesW.front()));
306  }
307  else if (nEmptyLists == 1)
308  {
309  if (vertexCandidatesU.empty())
310  { // V and W available
311  vertexTuples.emplace_back(VertexTuple(this->GetPandora(), vertexCandidatesV.front(), vertexCandidatesW.front(), TPC_VIEW_V, TPC_VIEW_W));
312  }
313  else if (vertexCandidatesV.empty())
314  { // U and W available
315  vertexTuples.emplace_back(VertexTuple(this->GetPandora(), vertexCandidatesU.front(), vertexCandidatesW.front(), TPC_VIEW_U, TPC_VIEW_W));
316  }
317  else
318  { // U and V available
319  vertexTuples.emplace_back(VertexTuple(this->GetPandora(), vertexCandidatesU.front(), vertexCandidatesV.front(), TPC_VIEW_U, TPC_VIEW_V));
320  }
321  }
322  else
323  { // Not enough views to reconstruct a 3D vertex
324  std::cout << "Insufficient 2D vertices to reconstruct a 3D vertex" << std::endl;
325  return STATUS_CODE_NOT_FOUND;
326  }
327 
328  if (m_visualise)
329  {
330  PANDORA_MONITORING_API(AddMarkerToVisualization(this->GetPandora(), &vertexTuples.front().GetPosition(), "candidate", GREEN, 1));
331  }
332 
333  if (!vertexTuples.empty())
334  {
335  const CartesianVector &vertex{vertexTuples.front().GetPosition()};
336  CartesianPointVector vertexCandidates;
337  vertexCandidates.emplace_back(vertex);
338  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->MakeCandidateVertexList(vertexCandidates));
339  }
340  else
341  {
342  std::cout << "Insufficient 2D vertices to reconstruct a 3D vertex" << std::endl;
343  return STATUS_CODE_NOT_FOUND;
344  }
345 
346  if (m_visualise)
347  {
348  PANDORA_MONITORING_API(ViewEvent(this->GetPandora()));
349  }
350 
351  return STATUS_CODE_SUCCESS;
352 }
353 
354 //-----------------------------------------------------------------------------------------------------------------------------------------
355 
356 StatusCode DlVertexingAlgorithm::MakeNetworkInputFromHits(const CaloHitList &caloHits, const HitType view, const float xMin,
357  const float xMax, const float zMin, const float zMax, LArDLHelper::TorchInput &networkInput, PixelVector &pixelVector) const
358 {
359  // ATTN If wire w pitches vary between TPCs, exception will be raised in initialisation of lar pseudolayer plugin
360  const LArTPC *const pTPC(this->GetPandora().GetGeometry()->GetLArTPCMap().begin()->second);
361  const float pitch(view == TPC_VIEW_U ? pTPC->GetWirePitchU() : view == TPC_VIEW_V ? pTPC->GetWirePitchV() : pTPC->GetWirePitchW());
362 
363  // Determine the bin edges
364  std::vector<double> xBinEdges(m_width + 1);
365  std::vector<double> zBinEdges(m_height + 1);
366  xBinEdges[0] = xMin - 0.5f * m_driftStep;
367  const double dx = ((xMax + 0.5f * m_driftStep) - xBinEdges[0]) / m_width;
368  for (int i = 1; i < m_width + 1; ++i)
369  xBinEdges[i] = xBinEdges[i - 1] + dx;
370  zBinEdges[0] = zMin - 0.5f * pitch;
371  const double dz = ((zMax + 0.5f * pitch) - zBinEdges[0]) / m_height;
372  for (int i = 1; i < m_height + 1; ++i)
373  zBinEdges[i] = zBinEdges[i - 1] + dz;
374 
375  LArDLHelper::InitialiseInput({1, 1, m_height, m_width}, networkInput);
376  auto accessor = networkInput.accessor<float, 4>();
377 
378  for (const CaloHit *pCaloHit : caloHits)
379  {
380  const float x{pCaloHit->GetPositionVector().GetX()};
381  const float z{pCaloHit->GetPositionVector().GetZ()};
382  if (m_pass > 1)
383  {
384  if (x < xMin || x > xMax || z < zMin || z > zMax)
385  continue;
386  }
387  const float adc{pCaloHit->GetMipEquivalentEnergy()};
388  const int pixelX{static_cast<int>(std::floor((x - xBinEdges[0]) / dx))};
389  const int pixelZ{static_cast<int>(std::floor((z - zBinEdges[0]) / dz))};
390  accessor[0][0][pixelZ][pixelX] += adc;
391  }
392  for (int row = 0; row < m_height; ++row)
393  {
394  for (int col = 0; col < m_width; ++col)
395  {
396  const float value{accessor[0][0][row][col]};
397  if (value > 0)
398  pixelVector.emplace_back(std::make_pair(row, col));
399  }
400  }
401 
402  return STATUS_CODE_SUCCESS;
403 }
404 
405 //-----------------------------------------------------------------------------------------------------------------------------------------
406 
407 StatusCode DlVertexingAlgorithm::MakeWirePlaneCoordinatesFromCanvas(float **canvas, const int canvasWidth, const int canvasHeight,
408  const int columnOffset, const int rowOffset, const HitType view, const float xMin, const float xMax, const float zMin, const float zMax,
409  CartesianPointVector &positionVector) const
410 {
411  // ATTN If wire w pitches vary between TPCs, exception will be raised in initialisation of lar pseudolayer plugin
412  const LArTPC *const pTPC(this->GetPandora().GetGeometry()->GetLArTPCMap().begin()->second);
413  const float pitch(view == TPC_VIEW_U ? pTPC->GetWirePitchU() : view == TPC_VIEW_V ? pTPC->GetWirePitchV() : pTPC->GetWirePitchW());
414 
415  const double dx = ((xMax + 0.5f * m_driftStep) - (xMin - 0.5f * m_driftStep)) / m_width;
416  const double dz = ((zMax + 0.5f * pitch) - (zMin - 0.5f * pitch)) / m_height;
417 
418  float best{-1.f};
419  int rowBest{0}, colBest{0};
420  for (int row = 0; row < canvasHeight; ++row)
421  for (int col = 0; col < canvasWidth; ++col)
422  if (canvas[row][col] > 0 && canvas[row][col] > best)
423  {
424  best = canvas[row][col];
425  rowBest = row;
426  colBest = col;
427  }
428 
429  const float x{static_cast<float>((colBest - columnOffset) * dx + xMin)};
430  const float z{static_cast<float>((rowBest - rowOffset) * dz + zMin)};
431 
432  CartesianVector pt(x, 0.f, z);
433  positionVector.emplace_back(pt);
434 
435  return STATUS_CODE_SUCCESS;
436 }
437 
438 //-----------------------------------------------------------------------------------------------------------------------------------------
439 
441  int &colOffset, int &rowOffset, int &width, int &height) const
442 {
443  const double scaleFactor{std::sqrt(m_height * m_height + m_width * m_width)};
444  // output is a 1 x num_classes x height x width tensor
445  // we want the maximum value in the num_classes dimension (1) for every pixel
446  auto classes{torch::argmax(networkOutput, 1)};
447  // the argmax result is a 1 x height x width tensor where each element is a class id
448  auto classesAccessor{classes.accessor<long, 3>()};
449  int colOffsetMin{0}, colOffsetMax{0}, rowOffsetMin{0}, rowOffsetMax{0};
450  for (const auto &[row, col] : pixelVector)
451  {
452  const auto cls{classesAccessor[0][row][col]};
453  const double threshold{m_thresholds[cls]};
454  if (threshold > 0. && threshold < 1.)
455  {
456  const int distance = static_cast<int>(std::round(std::ceil(scaleFactor * threshold)));
457  if ((row - distance) < rowOffsetMin)
458  rowOffsetMin = row - distance;
459  if ((row + distance) > rowOffsetMax)
460  rowOffsetMax = row + distance;
461  if ((col - distance) < colOffsetMin)
462  colOffsetMin = col - distance;
463  if ((col + distance) > colOffsetMax)
464  colOffsetMax = col + distance;
465  }
466  }
467  colOffset = colOffsetMin < 0 ? -colOffsetMin : 0;
468  rowOffset = rowOffsetMin < 0 ? -rowOffsetMin : 0;
469  width = std::max(colOffsetMax + colOffset + 1, m_width);
470  height = std::max(rowOffsetMax + rowOffset + 1, m_height);
471 }
472 
473 //-----------------------------------------------------------------------------------------------------------------------------------------
474 
475 void DlVertexingAlgorithm::DrawRing(float **canvas, const int row, const int col, const int inner, const int outer, const float weight) const
476 {
477  // Set the starting position for each circle bounding the ring
478  int c1{inner}, r1{0}, c2{outer}, r2{0};
479  int inner2{inner * inner}, outer2{outer * outer};
480  while (c2 >= r2)
481  {
482  // Set the output pixel location
483  int rp2{r2}, cp2{c2};
484  // We're still within the octant for the inner ring, so use the inner pixel location (see Update comment below)
485  // Note also that the inner row is always the same as the outer row, so no need to define rp1
486  int cp1{c1};
487  if (c1 <= r1)
488  { // We've completed the arc of the inner ring already, so just move radially out from here (see Update comment below)
489  cp1 = r2;
490  }
491  // Fill the pixels from inner to outer in the current row and their mirror pixels in the other octants
492  for (int c = cp1; c <= cp2; ++c)
493  {
494  canvas[row + rp2][col + c] += weight;
495  if (rp2 != c)
496  canvas[row + c][col + rp2] += weight;
497  if (rp2 != 0 && cp2 != 0)
498  {
499  canvas[row - rp2][col - c] += weight;
500  if (rp2 != c)
501  canvas[row - c][col - rp2] += weight;
502  }
503  if (rp2 != 0)
504  {
505  canvas[row - rp2][col + c] += weight;
506  if (rp2 != c)
507  canvas[row + c][col - rp2] += weight;
508  }
509  if (cp2 != 0)
510  {
511  canvas[row + rp2][col - c] += weight;
512  if (rp2 != c)
513  canvas[row - c][col + rp2] += weight;
514  }
515  }
516  // Only update the inner location while it remains in the octant (outer ring also remains in the octant of course, but the logic of
517  // the update means that the inner ring can leave its octant before the outer ring is complete, so we need to stop that)
518  if (c1 > r1)
519  this->Update(inner2, c1, r1);
520  // Update the outer location - increase the row position with every step, decrease the column position if conditions are met
521  this->Update(outer2, c2, r2);
522  }
523 }
524 
525 //-----------------------------------------------------------------------------------------------------------------------------------------
526 
527 void DlVertexingAlgorithm::Update(const int radius2, int &col, int &row) const
528 {
529  // Bresenham midpoint circle algorithm to determine if we should update the column position
530  // This obscure looking block of code uses bit shifts and integer arithmetic to perform this check as efficiently as possible
531  const int a{1 - (col << 2)};
532  const int b{col * col + row * row - radius2 + (row << 2) + 1};
533  const int c{(a << 2) * b + a * a};
534  if (c < 0)
535  {
536  --col;
537  ++row;
538  }
539  else
540  ++row;
541 }
542 
543 //-----------------------------------------------------------------------------------------------------------------------------------------
544 
546 {
547  const CaloHitList *pCaloHitList2D(nullptr);
548  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, "CaloHitList2D", pCaloHitList2D));
549  const MCParticleList *pMCParticleList(nullptr);
550  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*this, pMCParticleList));
551 
553  parameters.m_maxPhotonPropagation = std::numeric_limits<float>::max();
554  LArMCParticleHelper::SelectReconstructableMCParticles(
555  pMCParticleList, pCaloHitList2D, parameters, LArMCParticleHelper::IsBeamNeutrinoFinalState, mcToHitsMap);
556 
557  return STATUS_CODE_SUCCESS;
558 }
559 
560 //-----------------------------------------------------------------------------------------------------------------------------------------
561 
562 StatusCode DlVertexingAlgorithm::CompleteMCHierarchy(const LArMCParticleHelper::MCContributionMap &mcToHitsMap, MCParticleList &mcHierarchy) const
563 {
564  try
565  {
566  for (const auto &[mc, hits] : mcToHitsMap)
567  {
568  (void)hits;
569  mcHierarchy.push_back(mc);
570  LArMCParticleHelper::GetAllAncestorMCParticles(mc, mcHierarchy);
571  }
572  }
573  catch (const StatusCodeException &e)
574  {
575  return e.GetStatusCode();
576  }
577 
578  // Move the neutrino to the front of the list
579  auto pivot =
580  std::find_if(mcHierarchy.begin(), mcHierarchy.end(), [](const MCParticle *mc) -> bool { return LArMCParticleHelper::IsNeutrino(mc); });
581  (void)pivot;
582  if (pivot != mcHierarchy.end())
583  std::rotate(mcHierarchy.begin(), pivot, std::next(pivot));
584  else
585  return STATUS_CODE_NOT_FOUND;
586 
587  return STATUS_CODE_SUCCESS;
588 }
589 
590 //-----------------------------------------------------------------------------------------------------------------------------------------
591 
592 void DlVertexingAlgorithm::GetHitRegion(const CaloHitList &caloHitList, float &xMin, float &xMax, float &zMin, float &zMax) const
593 {
594  xMin = std::numeric_limits<float>::max();
595  xMax = -std::numeric_limits<float>::max();
596  zMin = std::numeric_limits<float>::max();
597  zMax = -std::numeric_limits<float>::max();
598  // Find the range of x and z values in the view
599  for (const CaloHit *pCaloHit : caloHitList)
600  {
601  const float x{pCaloHit->GetPositionVector().GetX()};
602  const float z{pCaloHit->GetPositionVector().GetZ()};
603  xMin = std::min(x, xMin);
604  xMax = std::max(x, xMax);
605  zMin = std::min(z, zMin);
606  zMax = std::max(z, zMax);
607  }
608 
609  if (caloHitList.empty())
610  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
611 
612  const HitType view{caloHitList.front()->GetHitType()};
613  const bool isU{view == TPC_VIEW_U}, isV{view == TPC_VIEW_V}, isW{view == TPC_VIEW_W};
614  if (!(isU || isV || isW))
615  throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
616 
617  // ATTN If wire w pitches vary between TPCs, exception will be raised in initialisation of lar pseudolayer plugin
618  const LArTPC *const pTPC(this->GetPandora().GetGeometry()->GetLArTPCMap().begin()->second);
619  const float pitch(view == TPC_VIEW_U ? pTPC->GetWirePitchU() : view == TPC_VIEW_V ? pTPC->GetWirePitchV() : pTPC->GetWirePitchW());
620 
621  if (m_pass > 1)
622  {
623  const VertexList *pVertexList(nullptr);
624  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, m_inputVertexListName, pVertexList));
625  if (pVertexList->empty())
626  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
627  const CartesianVector &vertex{pVertexList->front()->GetPosition()};
628 
629  // Get hit distribution left/right asymmetry
630  int nHitsLeft{0}, nHitsRight{0};
631  const double xVtx{vertex.GetX()};
632  for (const std::string &listname : m_caloHitListNames)
633  {
634  const CaloHitList *pCaloHitList(nullptr);
635  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, listname, pCaloHitList));
636  if (pCaloHitList->empty())
637  continue;
638  for (const CaloHit *const pCaloHit : *pCaloHitList)
639  {
640  const CartesianVector &pos{pCaloHit->GetPositionVector()};
641  if (pos.GetX() <= xVtx)
642  ++nHitsLeft;
643  else
644  ++nHitsRight;
645  }
646  }
647  const int nHitsTotal{nHitsLeft + nHitsRight};
648  if (nHitsTotal == 0)
649  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
650  const float xAsymmetry{nHitsLeft / static_cast<float>(nHitsTotal)};
651 
652  // Vertices
653  const LArTransformationPlugin *transform{this->GetPandora().GetPlugins()->GetLArTransformationPlugin()};
654  double zVtx{0.};
655  if (isW)
656  zVtx += transform->YZtoW(vertex.GetY(), vertex.GetZ());
657  else if (isV)
658  zVtx += transform->YZtoV(vertex.GetY(), vertex.GetZ());
659  else
660  zVtx = transform->YZtoU(vertex.GetY(), vertex.GetZ());
661 
662  // Get hit distribution upstream/downstream asymmetry
663  int nHitsUpstream{0}, nHitsDownstream{0};
664  for (const CaloHit *const pCaloHit : caloHitList)
665  {
666  const CartesianVector &pos{pCaloHit->GetPositionVector()};
667  if (pos.GetZ() <= zVtx)
668  ++nHitsUpstream;
669  else
670  ++nHitsDownstream;
671  }
672  const int nHitsViewTotal{nHitsUpstream + nHitsDownstream};
673  if (nHitsViewTotal == 0)
674  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
675  const float zAsymmetry{nHitsUpstream / static_cast<float>(nHitsViewTotal)};
676 
677  const float xSpan{m_driftStep * (m_width - 1)};
678  xMin = xVtx - xAsymmetry * xSpan;
679  xMax = xMin + (m_driftStep * (m_width - 1));
680  const float zSpan{pitch * (m_height - 1)};
681  zMin = zVtx - zAsymmetry * zSpan;
682  zMax = zMin + zSpan;
683  }
684 
685  // Avoid unreasonable rescaling of very small hit regions, pixels are assumed to be 0.5cm in x and wire pitch in z
686  // ATTN: Rescaling is to a size 1 pixel smaller than the intended image to ensure all hits fit within an imaged binned
687  // to be one pixel wider than this
688  const float xRange{xMax - xMin}, zRange{zMax - zMin};
689  const float minXSpan{m_driftStep * (m_width - 1)};
690  if (xRange < minXSpan)
691  {
692  const float padding{0.5f * (minXSpan - xRange)};
693  xMin -= padding;
694  xMax += padding;
695  }
696  const float minZSpan{pitch * (m_height - 1)};
697  if (zRange < minZSpan)
698  {
699  const float padding{0.5f * (minZSpan - zRange)};
700  zMin -= padding;
701  zMax += padding;
702  }
703 }
704 
705 //-----------------------------------------------------------------------------------------------------------------------------------------
706 
707 StatusCode DlVertexingAlgorithm::MakeCandidateVertexList(const CartesianPointVector &positions)
708 {
709  const VertexList *pVertexList{nullptr};
710  std::string temporaryListName;
711  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*this, pVertexList, temporaryListName));
712 
713  for (const CartesianVector &position : positions)
714  {
715  PandoraContentApi::Vertex::Parameters parameters;
716  parameters.m_position = position;
717  parameters.m_vertexLabel = VERTEX_INTERACTION;
718  parameters.m_vertexType = VERTEX_3D;
719 
720  const Vertex *pVertex(nullptr);
721  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*this, parameters, pVertex));
722  }
723  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Vertex>(*this, m_outputVertexListName));
724  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ReplaceCurrentList<Vertex>(*this, m_outputVertexListName));
725 
726  return STATUS_CODE_SUCCESS;
727 }
728 
729 //-----------------------------------------------------------------------------------------------------------------------------------------
730 
731 void DlVertexingAlgorithm::GetTrueVertexPosition(float &x, float &y, float &z) const
732 {
733  const CartesianVector &trueVertex{this->GetTrueVertex()};
734  x = trueVertex.GetX();
735  y = trueVertex.GetY();
736  z = trueVertex.GetZ();
737 }
738 
739 //-----------------------------------------------------------------------------------------------------------------------------------------
740 
741 void DlVertexingAlgorithm::GetTrueVertexPosition(float &x, float &u, float &v, float &w) const
742 {
743  const CartesianVector &trueVertex{this->GetTrueVertex()};
744  const LArTransformationPlugin *transform{this->GetPandora().GetPlugins()->GetLArTransformationPlugin()};
745  x = trueVertex.GetX();
746  u = static_cast<float>(transform->YZtoU(trueVertex.GetY(), trueVertex.GetZ()));
747  v = static_cast<float>(transform->YZtoV(trueVertex.GetY(), trueVertex.GetZ()));
748  w = static_cast<float>(transform->YZtoW(trueVertex.GetY(), trueVertex.GetZ()));
749 }
750 
751 //-----------------------------------------------------------------------------------------------------------------------------------------
752 
753 const CartesianVector &DlVertexingAlgorithm::GetTrueVertex() const
754 {
755  const MCParticleList *pMCParticleList{nullptr};
756  if (STATUS_CODE_SUCCESS == PandoraContentApi::GetCurrentList(*this, pMCParticleList) && pMCParticleList)
757  {
758  MCParticleVector primaries;
759  LArMCParticleHelper::GetPrimaryMCParticleList(pMCParticleList, primaries);
760  if (!primaries.empty())
761  {
762  const MCParticle *primary{primaries.front()};
763  const MCParticleList &parents{primary->GetParentList()};
764  if (parents.size() == 1)
765  {
766  const MCParticle *trueNeutrino{parents.front()};
767  if (LArMCParticleHelper::IsNeutrino(trueNeutrino))
768  return primaries.front()->GetVertex();
769  }
770  }
771  }
772 
773  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
774 }
775 
776 #ifdef MONITORING
777 void DlVertexingAlgorithm::PopulateRootTree(const std::vector<VertexTuple> &vertexTuples, const pandora::CartesianPointVector &vertexCandidatesU,
778  const pandora::CartesianPointVector &vertexCandidatesV, const pandora::CartesianPointVector &vertexCandidatesW) const
779 {
780  if (m_writeTree)
781  {
782  const MCParticleList *pMCParticleList{nullptr};
783  if (STATUS_CODE_SUCCESS == PandoraContentApi::GetCurrentList(*this, pMCParticleList))
784  {
785  if (pMCParticleList)
786  {
788  MCParticleVector primaries;
789  LArMCParticleHelper::GetPrimaryMCParticleList(pMCParticleList, primaries);
790  if (!primaries.empty())
791  {
792  const MCParticle *primary{primaries.front()};
793  const MCParticleList &parents{primary->GetParentList()};
794  if (parents.size() == 1)
795  {
796  const MCParticle *trueNeutrino{parents.front()};
797  if (LArMCParticleHelper::IsNeutrino(trueNeutrino))
798  {
799  const LArTransformationPlugin *transform{this->GetPandora().GetPlugins()->GetLArTransformationPlugin()};
800  const CartesianVector &trueVertex{primaries.front()->GetVertex()};
801  if (LArVertexHelper::IsInFiducialVolume(this->GetPandora(), trueVertex, m_volumeType))
802  {
803  const CartesianVector &recoVertex{vertexTuples.front().GetPosition()};
804  const float tx{trueVertex.GetX()};
805  const float tu{static_cast<float>(transform->YZtoU(trueVertex.GetY(), trueVertex.GetZ()))};
806  const float tv{static_cast<float>(transform->YZtoV(trueVertex.GetY(), trueVertex.GetZ()))};
807  const float tw{static_cast<float>(transform->YZtoW(trueVertex.GetY(), trueVertex.GetZ()))};
808  const float rx_u{vertexCandidatesU.front().GetX()};
809  const float ru{vertexCandidatesU.front().GetZ()};
810  const float rx_v{vertexCandidatesV.front().GetX()};
811  const float rv{vertexCandidatesV.front().GetZ()};
812  const float rx_w{vertexCandidatesW.front().GetX()};
813  const float rw{vertexCandidatesW.front().GetZ()};
814  const float dr_u{std::sqrt((rx_u - tx) * (rx_u - tx) + (ru - tu) * (ru - tu))};
815  const float dr_v{std::sqrt((rx_v - tx) * (rx_v - tx) + (rv - tv) * (rv - tv))};
816  const float dr_w{std::sqrt((rx_w - tx) * (rx_w - tx) + (rw - tw) * (rw - tw))};
817  const CartesianVector &dv{recoVertex - trueVertex};
818  const float dr{dv.GetMagnitude()};
819  const float dx{dv.GetX()}, dy{dv.GetY()}, dz{dv.GetZ()};
820  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_rootTreeName, "event", m_event));
821  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_rootTreeName, "pass", m_pass));
822  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_rootTreeName, "dr_u", dr_u));
823  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_rootTreeName, "dr_v", dr_v));
824  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_rootTreeName, "dr_w", dr_w));
825  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_rootTreeName, "dr", dr));
826  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_rootTreeName, "dx", dx));
827  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_rootTreeName, "dy", dy));
828  PANDORA_MONITORING_API(SetTreeVariable(this->GetPandora(), m_rootTreeName, "dz", dz));
829  PANDORA_MONITORING_API(FillTree(this->GetPandora(), m_rootTreeName));
830  }
831  }
832  }
833  }
834  }
835  }
836  }
837 }
838 #endif
839 
840 //-----------------------------------------------------------------------------------------------------------------------------------------
841 
842 StatusCode DlVertexingAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
843 {
844  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "TrainingMode", m_trainingMode));
845  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "Visualise", m_visualise));
846  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "Pass", m_pass));
847  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ImageHeight", m_height));
848  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ImageWidth", m_width));
849  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "DriftStep", m_driftStep));
850  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "DistanceThresholds", m_thresholds));
851  m_nClasses = m_thresholds.size() - 1;
852  if (m_pass > 1)
853  {
854  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "InputVertexListName", m_inputVertexListName));
855  }
856 
857  if (m_trainingMode)
858  {
859  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "TrainingOutputFileName", m_trainingOutputFile));
860  }
861  else
862  {
863  std::string modelName;
864  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "ModelFileNameU", modelName));
865  modelName = LArFileHelper::FindFileInPath(modelName, "FW_SEARCH_PATH");
866  LArDLHelper::LoadModel(modelName, m_modelU);
867  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "ModelFileNameV", modelName));
868  modelName = LArFileHelper::FindFileInPath(modelName, "FW_SEARCH_PATH");
869  LArDLHelper::LoadModel(modelName, m_modelV);
870  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "ModelFileNameW", modelName));
871  modelName = LArFileHelper::FindFileInPath(modelName, "FW_SEARCH_PATH");
872  LArDLHelper::LoadModel(modelName, m_modelW);
873  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "WriteTree", m_writeTree));
874  if (m_writeTree)
875  {
876  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "RootTreeName", m_rootTreeName));
877  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "RootFileName", m_rootFileName));
878  }
879  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "OutputVertexListName", m_outputVertexListName));
880  }
881 
882  PANDORA_RETURN_RESULT_IF_AND_IF(
883  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "CaloHitListNames", m_caloHitListNames));
884  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "VolumeType", m_volumeType));
885 
886  return STATUS_CODE_SUCCESS;
887 }
888 
889 //-----------------------------------------------------------------------------------------------------------------------------------------
890 //-----------------------------------------------------------------------------------------------------------------------------------------
891 
893  const Pandora &pandora, const CartesianVector &vertexU, const CartesianVector &vertexV, const CartesianVector &vertexW) :
894  m_pos{0.f, 0.f, 0.f},
895  m_chi2{0.f}
896 {
897  LArGeometryHelper::MergeThreePositions3D(pandora, TPC_VIEW_U, TPC_VIEW_V, TPC_VIEW_W, vertexU, vertexV, vertexW, m_pos, m_chi2);
898  if (m_chi2 > 1.f)
899  {
900  CartesianVector vertexUV(0.f, 0.f, 0.f);
901  float chi2UV{0.f};
902  LArGeometryHelper::MergeTwoPositions3D(pandora, TPC_VIEW_U, TPC_VIEW_V, vertexU, vertexV, vertexUV, chi2UV);
903 
904  CartesianVector vertexUW(0.f, 0.f, 0.f);
905  float chi2UW{0.f};
906  LArGeometryHelper::MergeTwoPositions3D(pandora, TPC_VIEW_U, TPC_VIEW_W, vertexU, vertexW, vertexUW, chi2UW);
907 
908  CartesianVector vertexVW(0.f, 0.f, 0.f);
909  float chi2VW{0.f};
910  LArGeometryHelper::MergeTwoPositions3D(pandora, TPC_VIEW_V, TPC_VIEW_W, vertexV, vertexW, vertexVW, chi2VW);
911 
912  if (chi2UV < m_chi2)
913  {
914  m_pos = vertexUV;
915  m_chi2 = chi2UV;
916  }
917  if (chi2UW < m_chi2)
918  {
919  m_pos = vertexUW;
920  m_chi2 = chi2UW;
921  }
922  if (chi2VW < m_chi2)
923  {
924  m_pos = vertexVW;
925  m_chi2 = chi2VW;
926  }
927  }
928  // std::cout << "Merging 3, position (" << m_pos.GetX() << ", " << m_pos.GetY() << ", " << m_pos.GetZ() << ") with chi2 " << m_chi2 <<
929  // std::endl;
930 }
931 
932 //-----------------------------------------------------------------------------------------------------------------------------------------
933 
935  const Pandora &pandora, const CartesianVector &vertex1, const CartesianVector &vertex2, const HitType view1, const HitType view2) :
936  m_pos{0.f, 0.f, 0.f},
937  m_chi2{0.f}
938 {
939  LArGeometryHelper::MergeTwoPositions3D(pandora, view1, view2, vertex1, vertex2, m_pos, m_chi2);
940  std::cout << "Merging 2, position (" << m_pos.GetX() << ", " << m_pos.GetY() << ", " << m_pos.GetZ() << ") with chi2 " << m_chi2 << std::endl;
941 }
942 
943 //-----------------------------------------------------------------------------------------------------------------------------------------
944 
946 {
947  return m_pos;
948 }
949 
950 //-----------------------------------------------------------------------------------------------------------------------------------------
951 
953 {
954  return m_chi2;
955 }
956 
957 //-----------------------------------------------------------------------------------------------------------------------------------------
958 
960 {
961  const float x{m_pos.GetX()}, y{m_pos.GetY()}, z{m_pos.GetZ()};
962  return "3D pos: (" + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + ") X2 = " + std::to_string(m_chi2);
963 }
964 
965 } // namespace lar_dl_content
Float_t x
Definition: compare.C:6
LArDLHelper::TorchModel m_modelU
The model for the U view.
const pandora::CartesianVector & GetTrueVertex() const
Retrieve the true neutrino vertex.
void GetHitRegion(const pandora::CaloHitList &caloHitList, float &xMin, float &xMax, float &zMin, float &zMax) const
std::vector< double > m_thresholds
Distance class thresholds.
std::unordered_map< const pandora::MCParticle *, pandora::CaloHitList > MCContributionMap
MvaTypes::MvaFeatureVector MvaFeatureVector
Definition: LArMvaHelper.h:75
void Update(const int radius, int &col, int &row) const
Update the coordinates along the loci of a circle. When drawing the ring we need an efficient means t...
pandora::StatusCode GetMCToHitsMap(LArMCParticleHelper::MCContributionMap &mcToHitsMap) const
Float_t y
Definition: compare.C:6
Double_t z
Definition: plot.C:276
bool m_visualise
Whether or not to visualise the candidate vertices.
int m_event
The current event number.
pandora::StringVector m_caloHitListNames
Names of input calo hit lists.
LArDLHelper::TorchModel m_modelV
The model for the V view.
float m_maxPhotonPropagation
the maximum photon propagation length
pandora::StatusCode CompleteMCHierarchy(const LArMCParticleHelper::MCContributionMap &mcToHitsMap, pandora::MCParticleList &mcHierarchy) const
std::string m_outputVertexListName
Output vertex list name.
TFile f
Definition: plotHisto.C:6
void GetCanvasParameters(const LArDLHelper::TorchOutput &networkOutput, const PixelVector &pixelVector, int &columnOffset, int &rowOffset, int &width, int &height) const
Determines the parameters of the canvas for extracting the vertex location. The network predicts the ...
Header file for the geometry helper class.
std::mt19937 m_rng
The random number generator.
void hits()
Definition: readHits.C:15
int m_nClasses
The number of distance classes.
TCanvas * c1
Definition: plotHisto.C:7
TCanvas * c2
Definition: plot_hist.C:75
std::string m_rootTreeName
The ROOT tree name.
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
Int_t col[ntarg]
Definition: Style.C:29
bool m_writeTree
Whether or not to write validation details to a ROOT tree.
int m_height
The height of the images.
TMarker * pt
Definition: egs.C:25
std::vector< art::Ptr< simb::MCParticle > > MCParticleVector
const pandora::CartesianVector & GetPosition() const
int m_pass
The pass of the train/infer step.
Header file for the file helper class.
static void Forward(TorchModel &model, const TorchInputVector &input, TorchOutput &output)
Run a deep learning model.
Definition: LArDLHelper.cc:41
double value
Definition: spectrum.C:18
void GetTrueVertexPosition(float &x, float &y, float &z) const
Retrieve the true neutrino vertex position.
std::string m_inputVertexListName
Input vertex list name if 2nd pass.
Header file for the vertex helper class.
pandora::StatusCode MakeWirePlaneCoordinatesFromCanvas(float **canvas, const int canvasWidth, const int canvasHeight, const int columnOffset, const int rowOffset, const pandora::HitType view, const float xMin, const float xMax, const float zMin, const float zMax, pandora::CartesianPointVector &positionVector) const
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
double weight
Definition: plottest35.C:25
LArDLHelper::TorchModel m_modelW
The model for the W view.
pandora::StatusCode MakeNetworkInputFromHits(const pandora::CaloHitList &caloHits, const pandora::HitType view, const float xMin, const float xMax, const float zMin, const float zMax, LArDLHelper::TorchInput &networkInput, PixelVector &pixelVector) const
std::string m_trainingOutputFile
Output file name for training examples.
static pandora::StatusCode LoadModel(const std::string &filename, TorchModel &model)
Loads a deep learning model.
Definition: LArDLHelper.cc:16
std::string m_rootFileName
The ROOT file name.
HitType
Definition: HitType.h:12
pandora::StatusCode MakeCandidateVertexList(const pandora::CartesianPointVector &positions)
Create a vertex list from the candidate vertices.
boost::graph_traits< ModuleGraph >::vertex_descriptor Vertex
Definition: ModuleGraph.h:25
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
float m_driftStep
The size of a pixel in the drift direction in cm (most relevant in pass 2)
Float_t e
Definition: plot.C:35
second_as<> second
Type of time stored in seconds, in double precision.
Definition: spacetime.h:82
int m_width
The width of the images.
static void InitialiseInput(const at::IntArrayRef dimensions, TorchInput &tensor)
Create a torch input tensor.
Definition: LArDLHelper.cc:34
Float_t w
Definition: plot.C:20
std::list< Vertex > VertexList
Definition: DCEL.h:169
std::vector< torch::jit::IValue > TorchInputVector
Definition: LArDLHelper.h:27
VertexTuple(const pandora::Pandora &pandora, const pandora::CartesianVector &vertexU, const pandora::CartesianVector &vertexV, const pandora::CartesianVector &vertexW)
void DrawRing(float **canvas, const int row, const int col, const int inner, const int outer, const float weight) const
Add a filled ring to the specified canvas. The ring has an inner radius based on the minimum predicte...
std::string m_volumeType
The name of the fiducial volume type for the monitoring output.
vertex reconstruction