LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
DlSecondaryVertexingAlgorithm.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 
24 
26 
27 using namespace pandora;
28 using namespace lar_content;
29 
30 namespace lar_dl_content
31 {
32 
33 DlSecondaryVertexingAlgorithm::DlSecondaryVertexingAlgorithm() :
34  m_event{-1},
35  m_visualise{false},
36  m_writeTree{false},
37  m_rng(static_cast<std::mt19937::result_type>(std::chrono::high_resolution_clock::now().time_since_epoch().count()))
38 {
39 }
40 
42 {
43  if (m_writeTree)
44  {
45  try
46  {
47  PANDORA_MONITORING_API(SaveTree(this->GetPandora(), m_rootTreeName, m_rootFileName, "RECREATE"));
48  }
49  catch (StatusCodeException e)
50  {
51  std::cout << "VertexAssessmentAlgorithm: Unable to write to ROOT tree" << std::endl;
52  }
53  }
54 }
55 
56 //-----------------------------------------------------------------------------------------------------------------------------------------
57 
59 {
60  ++m_event;
61 
62  if (m_trainingMode)
63  return this->PrepareTrainingSample();
64  else
65  return this->Infer();
66 
67  return STATUS_CODE_SUCCESS;
68 }
69 
71 {
72  const CaloHitList *pCaloHitList2D{nullptr};
73  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, "CaloHitList2D", pCaloHitList2D));
74  LArEventTopology eventTopology(*pCaloHitList2D);
75  eventTopology.ConstructVisibleHierarchy();
76  eventTopology.PruneHierarchy();
77  CartesianPointVector vertices;
78  eventTopology.GetVertices(vertices);
79 
80  // Only train on events where there is a vertex in the fiducial volume
81  bool hasFiducialVertex{false};
82  for (const CartesianVector &vertex : vertices)
83  {
84  if (LArVertexHelper::IsInFiducialVolume(this->GetPandora(), vertex, m_volumeType))
85  {
86  hasFiducialVertex = true;
87  break;
88  }
89  }
90 
91  if (!hasFiducialVertex)
92  return STATUS_CODE_SUCCESS;
93 
94  const MCParticleList *pMCParticleList(nullptr);
95  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*this, pMCParticleList));
97  LArMCParticleHelper::GetMCToHitsMap(pCaloHitList2D, pMCParticleList, mcToHitsMap);
98  MCParticleList hierarchy;
99  LArMCParticleHelper::CompleteMCHierarchy(mcToHitsMap, hierarchy);
100 
101  // Get boundaries for hits and make x dimension common
102  std::map<HitType, float> wireMin, wireMax;
103  float driftMin{std::numeric_limits<float>::max()}, driftMax{-std::numeric_limits<float>::max()};
104  for (const std::string &listname : m_caloHitListNames)
105  {
106  const CaloHitList *pCaloHitList{nullptr};
107  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, listname, pCaloHitList));
108  if (pCaloHitList->empty())
109  continue;
110 
111  HitType view{pCaloHitList->front()->GetHitType()};
112  float viewDriftMin{driftMin}, viewDriftMax{driftMax};
113  this->GetHitRegion(*pCaloHitList, viewDriftMin, viewDriftMax, wireMin[view], wireMax[view]);
114  driftMin = std::min(viewDriftMin, driftMin);
115  driftMax = std::max(viewDriftMax, driftMax);
116  }
117  for (const std::string &listname : m_caloHitListNames)
118  {
119  const CaloHitList *pCaloHitList(nullptr);
120  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, listname, pCaloHitList));
121  if (pCaloHitList->empty())
122  continue;
123 
124  HitType view{pCaloHitList->front()->GetHitType()};
125 
126  const std::string trainingFilename{m_trainingOutputFile + "_" + listname + ".csv"};
127  const unsigned long nVertices{vertices.size()};
128  unsigned long nHits{0};
129 
130  LArMvaHelper::MvaFeatureVector featureVector;
131  featureVector.emplace_back(static_cast<double>(m_event));
132  featureVector.emplace_back(static_cast<double>(nVertices));
133  // Vertices
134  const LArTransformationPlugin *transform{this->GetPandora().GetPlugins()->GetLArTransformationPlugin()};
135  for (const CartesianVector &vertex : vertices)
136  {
137  switch (view)
138  {
139  case TPC_VIEW_U:
140  featureVector.emplace_back(vertex.GetX());
141  featureVector.emplace_back(transform->YZtoU(vertex.GetY(), vertex.GetZ()));
142  break;
143  case TPC_VIEW_V:
144  featureVector.emplace_back(vertex.GetX());
145  featureVector.emplace_back(transform->YZtoV(vertex.GetY(), vertex.GetZ()));
146  break;
147  default:
148  featureVector.emplace_back(vertex.GetX());
149  featureVector.emplace_back(transform->YZtoW(vertex.GetY(), vertex.GetZ()));
150  break;
151  }
152  }
153 
154  // Retain the hit region
155  featureVector.emplace_back(driftMin);
156  featureVector.emplace_back(driftMax);
157  featureVector.emplace_back(wireMin[view]);
158  featureVector.emplace_back(wireMax[view]);
159 
160  for (const CaloHit *pCaloHit : *pCaloHitList)
161  {
162  featureVector.emplace_back(static_cast<double>(pCaloHit->GetPositionVector().GetX()));
163  featureVector.emplace_back(static_cast<double>(pCaloHit->GetPositionVector().GetZ()));
164  featureVector.emplace_back(static_cast<double>(pCaloHit->GetMipEquivalentEnergy()));
165  ++nHits;
166  }
167  featureVector.insert(featureVector.begin() + 2 + 2 * nVertices + 4, static_cast<double>(nHits));
168  // Only write out the feature vector if there were enough hits in the region of interest
169  if (nHits > 10)
170  LArMvaHelper::ProduceTrainingExample(trainingFilename, true, featureVector);
171  }
172 
173  return STATUS_CODE_SUCCESS;
174 }
175 
176 //-----------------------------------------------------------------------------------------------------------------------------------------
177 
179 {
180  // Get boundaries for hits and make x dimension common
181  std::map<HitType, float> wireMin, wireMax;
182  float driftMin{std::numeric_limits<float>::max()}, driftMax{-std::numeric_limits<float>::max()};
183  for (const std::string &listname : m_caloHitListNames)
184  {
185  const CaloHitList *pCaloHitList{nullptr};
186  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, listname, pCaloHitList));
187  if (pCaloHitList->empty())
188  continue;
189 
190  HitType view{pCaloHitList->front()->GetHitType()};
191  float viewDriftMin{driftMin}, viewDriftMax{driftMax};
192  this->GetHitRegion(*pCaloHitList, viewDriftMin, viewDriftMax, wireMin[view], wireMax[view]);
193  driftMin = std::min(viewDriftMin, driftMin);
194  driftMax = std::max(viewDriftMax, driftMax);
195  }
196 
197  CanvasViewMap canvases;
198  canvases[TPC_VIEW_U] = nullptr;
199  canvases[TPC_VIEW_V] = nullptr;
200  canvases[TPC_VIEW_W] = nullptr;
201  CartesianPointVector vertexCandidatesU, vertexCandidatesV, vertexCandidatesW;
202  for (const std::string &listname : m_caloHitListNames)
203  {
204  const CaloHitList *pCaloHitList{nullptr};
205  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetList(*this, listname, pCaloHitList));
206  if (pCaloHitList->empty())
207  continue;
208 
209  HitType view{pCaloHitList->front()->GetHitType()};
211  PixelVector pixelVector;
212  this->MakeNetworkInputFromHits(*pCaloHitList, view, driftMin, driftMax, wireMin[view], wireMax[view], input, pixelVector);
213 
214  // Run the input through the trained model
216  inputs.push_back(input);
218  switch (view)
219  {
220  case TPC_VIEW_U:
221  LArDLHelper::Forward(m_modelU, inputs, output);
222  break;
223  case TPC_VIEW_V:
224  LArDLHelper::Forward(m_modelV, inputs, output);
225  break;
226  default:
227  LArDLHelper::Forward(m_modelW, inputs, output);
228  break;
229  }
230 
231  int colOffset{0}, rowOffset{0}, canvasWidth{m_width}, canvasHeight{m_height};
232  this->GetCanvasParameters(output, pixelVector, colOffset, rowOffset, canvasWidth, canvasHeight);
233  canvases[view] = new Canvas(view, canvasWidth, canvasHeight, colOffset, rowOffset, driftMin, driftMax, wireMin[view], wireMax[view]);
234  // we want the maximum value in the num_classes dimension (1) for every pixel
235  auto classes{torch::argmax(output, 1)};
236  // the argmax result is a 1 x height x width tensor where each element is a class id
237  auto classesAccessor{classes.accessor<long, 3>()};
238  const double scaleFactor{std::sqrt(m_height * m_height + m_width * m_width)};
239  std::map<int, bool> haveSeenMap;
240  for (const auto &[row, col] : pixelVector)
241  {
242  const auto cls{classesAccessor[0][row][col]};
243  if (cls > 0 && cls < m_nClasses)
244  {
245  const int inner{static_cast<int>(std::round(std::ceil(scaleFactor * m_thresholds[cls - 1])))};
246  const int outer{static_cast<int>(std::round(std::ceil(scaleFactor * m_thresholds[cls])))};
248  canvases[view]->m_canvas, row + rowOffset, col + colOffset, inner, outer, 1.f / (outer * outer - inner * inner));
249  }
250  }
251  }
252 
253  CartesianPointVector vertexVector;
254  this->GetNetworkVertices(canvases, vertexVector);
255 
256  if (!vertexVector.empty())
257  {
258  StatusCode status{this->MakeCandidateVertexList(vertexVector)};
259 
260  for (const HitType view : {TPC_VIEW_U, TPC_VIEW_V, TPC_VIEW_W})
261  {
262  if (canvases[view])
263  delete canvases[view];
264  }
265 
266  return status;
267  }
268  else
269  {
270  for (const HitType view : {TPC_VIEW_U, TPC_VIEW_V, TPC_VIEW_W})
271  {
272  if (canvases[view])
273  delete canvases[view];
274  }
275 
276  return STATUS_CODE_SUCCESS;
277  }
278 }
279 
280 //-----------------------------------------------------------------------------------------------------------------------------------------
281 
282 StatusCode DlSecondaryVertexingAlgorithm::MakeNetworkInputFromHits(const CaloHitList &caloHits, const HitType view, const float xMin,
283  const float xMax, const float zMin, const float zMax, LArDLHelper::TorchInput &networkInput, PixelVector &pixelVector) const
284 {
285  // ATTN If wire w pitches vary between TPCs, exception will be raised in initialisation of lar pseudolayer plugin
286  const LArTPC *const pTPC(this->GetPandora().GetGeometry()->GetLArTPCMap().begin()->second);
287  const float pitch(view == TPC_VIEW_U ? pTPC->GetWirePitchU() : view == TPC_VIEW_V ? pTPC->GetWirePitchV() : pTPC->GetWirePitchW());
288  const float driftStep{0.5f};
289 
290  // Determine the bin edges
291  std::vector<double> xBinEdges(m_width + 1);
292  std::vector<double> zBinEdges(m_height + 1);
293  xBinEdges[0] = xMin - 0.5f * driftStep;
294  const double dx = ((xMax + 0.5f * driftStep) - xBinEdges[0]) / m_width;
295  for (int i = 1; i < m_width + 1; ++i)
296  xBinEdges[i] = xBinEdges[i - 1] + dx;
297  zBinEdges[0] = zMin - 0.5f * pitch;
298  const double dz = ((zMax + 0.5f * pitch) - zBinEdges[0]) / m_height;
299  for (int i = 1; i < m_height + 1; ++i)
300  zBinEdges[i] = zBinEdges[i - 1] + dz;
301 
302  LArDLHelper::InitialiseInput({1, 1, m_height, m_width}, networkInput);
303  auto accessor = networkInput.accessor<float, 4>();
304 
305  for (const CaloHit *pCaloHit : caloHits)
306  {
307  const float x{pCaloHit->GetPositionVector().GetX()};
308  const float z{pCaloHit->GetPositionVector().GetZ()};
309  if (m_pass > 1)
310  {
311  if (x < xMin || x > xMax || z < zMin || z > zMax)
312  continue;
313  }
314  const float adc{pCaloHit->GetMipEquivalentEnergy()};
315  const int pixelX{static_cast<int>(std::floor((x - xBinEdges[0]) / dx))};
316  const int pixelZ{static_cast<int>(std::floor((z - zBinEdges[0]) / dz))};
317  accessor[0][0][pixelZ][pixelX] += adc;
318  }
319  for (int row = 0; row < m_height; ++row)
320  {
321  for (int col = 0; col < m_width; ++col)
322  {
323  const float value{accessor[0][0][row][col]};
324  if (value > 0)
325  pixelVector.emplace_back(std::make_pair(row, col));
326  }
327  }
328 
329  return STATUS_CODE_SUCCESS;
330 }
331 
332 //-----------------------------------------------------------------------------------------------------------------------------------------
333 
334 StatusCode DlSecondaryVertexingAlgorithm::GetNetworkVertices(const CanvasViewMap &canvases, CartesianPointVector &positionVector) const
335 {
336  CartesianPointVector verticesU, verticesV, verticesW;
337  this->GetVerticesFromCanvas(*canvases.at(TPC_VIEW_U), verticesU);
338  this->GetVerticesFromCanvas(*canvases.at(TPC_VIEW_V), verticesV);
339  this->GetVerticesFromCanvas(*canvases.at(TPC_VIEW_W), verticesW);
340 
341  std::vector<VertexTuple> vertexTuples;
342  int nEmptyLists{(verticesU.empty() ? 1 : 0) + (verticesV.empty() ? 1 : 0) + (verticesW.empty() ? 1 : 0)};
343 
344  if (nEmptyLists == 0)
345  {
346  for (const CartesianVector &vertexU : verticesU)
347  {
348  for (const CartesianVector &vertexV : verticesV)
349  {
350  for (const CartesianVector &vertexW : verticesW)
351  {
352  const float xMin{std::min({vertexU.GetX(), vertexV.GetX(), vertexW.GetX()})};
353  const float xMax{std::max({vertexU.GetX(), vertexV.GetX(), vertexW.GetX()})};
354  if ((xMax - xMin) < 10.f)
355  {
356  const VertexTuple &tuple{VertexTuple(this->GetPandora(), vertexU, vertexV, vertexW)};
357  if (tuple.GetChi2() < 1)
358  vertexTuples.emplace_back(tuple);
359  }
360  }
361  }
362  }
363  }
364  else if (nEmptyLists == 1)
365  {
366  if (verticesU.empty())
367  {
368  for (const CartesianVector &vertexV : verticesV)
369  {
370  for (const CartesianVector &vertexW : verticesW)
371  {
372  const float xMin{std::min({vertexV.GetX(), vertexW.GetX()})};
373  const float xMax{std::max({vertexV.GetX(), vertexW.GetX()})};
374  if ((xMax - xMin) < 10.f)
375  {
376  const VertexTuple &tuple{VertexTuple(this->GetPandora(), vertexV, vertexW, TPC_VIEW_V, TPC_VIEW_W)};
377  if (tuple.GetChi2() < 1)
378  vertexTuples.emplace_back(tuple);
379  }
380  }
381  }
382  }
383  else if (verticesV.empty())
384  {
385  for (const CartesianVector &vertexU : verticesU)
386  {
387  for (const CartesianVector &vertexW : verticesW)
388  {
389  const float xMin{std::min({vertexU.GetX(), vertexW.GetX()})};
390  const float xMax{std::max({vertexU.GetX(), vertexW.GetX()})};
391  if ((xMax - xMin) < 10.f)
392  {
393  const VertexTuple &tuple{VertexTuple(this->GetPandora(), vertexU, vertexW, TPC_VIEW_U, TPC_VIEW_W)};
394  if (tuple.GetChi2() < 1)
395  vertexTuples.emplace_back(tuple);
396  }
397  }
398  }
399  }
400  else
401  {
402  for (const CartesianVector &vertexU : verticesU)
403  {
404  for (const CartesianVector &vertexV : verticesV)
405  {
406  const float xMin{std::min({vertexU.GetX(), vertexV.GetX()})};
407  const float xMax{std::max({vertexU.GetX(), vertexV.GetX()})};
408  if ((xMax - xMin) < 10.f)
409  {
410  const VertexTuple &tuple{VertexTuple(this->GetPandora(), vertexU, vertexV, TPC_VIEW_U, TPC_VIEW_V)};
411  if (tuple.GetChi2() < 1)
412  vertexTuples.emplace_back(tuple);
413  }
414  }
415  }
416  }
417  }
418  else
419  {
420  std::cout << "Insufficient 2D vertices to reconstruct a 3D vertex" << std::endl;
421  return STATUS_CODE_NOT_FOUND;
422  }
423 
424  // Sort the vertex tuples here and pick the unique ones that look sound
425  std::sort(vertexTuples.begin(), vertexTuples.end(),
426  [](const VertexTuple &tuple1, const VertexTuple &tuple2)
427  {
428  const CartesianPointVector &components1{tuple1.GetComponents()};
429  const CartesianPointVector &components2{tuple2.GetComponents()};
430  if (components1.size() == components2.size())
431  return tuple1.GetChi2() < tuple2.GetChi2();
432  else
433  return components1.size() > components2.size();
434  });
435 
436  CartesianPointVector used;
437  for (const VertexTuple &tuple : vertexTuples)
438  {
439  const CartesianPointVector &components{tuple.GetComponents()};
440  bool isAvailable{true};
441  for (const CartesianVector &component : components)
442  {
443  if (std::find(used.begin(), used.end(), component) != used.end())
444  {
445  isAvailable = false;
446  break;
447  }
448  }
449  if (!isAvailable || (components.size() < 3 && tuple.GetChi2() > 0.1))
450  continue;
451 
452  positionVector.emplace_back(tuple.GetPosition());
453  for (const CartesianVector &component : components)
454  used.emplace_back(component);
455  }
456 
457  return STATUS_CODE_SUCCESS;
458 }
459 
460 //-----------------------------------------------------------------------------------------------------------------------------------------
461 
462 StatusCode DlSecondaryVertexingAlgorithm::GetVerticesFromCanvas(const Canvas &canvas, CartesianPointVector &vertices) const
463 {
464  // ATTN If wire w pitches vary between TPCs, exception will be raised in initialisation of lar pseudolayer plugin
465  const LArTPC *const pTPC(this->GetPandora().GetGeometry()->GetLArTPCMap().begin()->second);
466 
467  HitType view{canvas.m_view};
468  const float pitch(view == TPC_VIEW_U ? pTPC->GetWirePitchU() : view == TPC_VIEW_V ? pTPC->GetWirePitchV() : pTPC->GetWirePitchW());
469  const float driftStep{0.5f};
470 
471  const double dx{((canvas.m_xMax + 0.5f * driftStep) - (canvas.m_xMin - 0.5f * driftStep)) / m_width};
472  const double dz{((canvas.m_zMax + 0.5f * pitch) - (canvas.m_zMin - 0.5f * pitch)) / m_height};
473 
474  float maxIntensity{0.f};
475  for (int xp = 0; xp < m_width; ++xp)
476  {
477  int xpp{xp + canvas.m_colOffset};
478  if (xpp >= canvas.m_width)
479  continue;
480 
481  for (int zp = 0; zp < m_height; ++zp)
482  {
483  int zpp{zp + canvas.m_rowOffset};
484  if (zpp >= canvas.m_height)
485  continue;
486 
487  const float localIntensity{canvas.m_canvas[zpp][xpp]};
488  if (localIntensity > maxIntensity)
489  maxIntensity = localIntensity;
490  }
491  }
492  const float threshold{maxIntensity * 0.3f};
493 
494  std::vector<std::vector<std::pair<int, int>>> peaks;
495  for (int xp = 0; xp < m_width; ++xp)
496  {
497  int xpp{xp + canvas.m_colOffset};
498  if (xpp >= canvas.m_width)
499  continue;
500 
501  for (int zp = 0; zp < m_height; ++zp)
502  {
503  int zpp{zp + canvas.m_rowOffset};
504  if (zpp >= canvas.m_height)
505  continue;
506  const float localIntensity{canvas.m_canvas[zpp][xpp]};
507 
508  std::vector<std::pair<int, int>> peak;
509  bool hasLowNeighbour{false};
510  for (int dr = -1; dr <= 1; ++dr)
511  {
512  for (int dc = -1; dc <= 1; ++dc)
513  {
514  if (dr == 0 && dc == 0)
515  continue;
516  const int r{zpp + dr}, c{xpp + dc};
517  if (r < 0 || r >= canvas.m_height || c < 0 || c >= canvas.m_width)
518  continue;
519 
520  const float neighborIntensity{canvas.m_canvas[r][c]};
521  if (localIntensity > neighborIntensity)
522  {
523  hasLowNeighbour = true;
524  }
525  else if (localIntensity < neighborIntensity)
526  {
527  hasLowNeighbour = false;
528  break;
529  }
530  }
531  }
532  if (hasLowNeighbour && localIntensity > threshold)
533  this->GrowPeak(canvas, xpp, zpp, localIntensity, peak);
534  if (!peak.empty())
535  peaks.emplace_back(peak);
536  }
537  }
538 
539  for (const auto &peak : peaks)
540  {
541  float row{0}, col{0};
542  for (const auto &pixel : peak)
543  {
544  row += pixel.second - canvas.m_rowOffset;
545  col += pixel.first - canvas.m_colOffset;
546  }
547  row /= peak.size();
548  col /= peak.size();
549 
550  const float x{static_cast<float>(col * dx + canvas.m_xMin)};
551  const float z{static_cast<float>(row * dz + canvas.m_zMin)};
552  CartesianVector pt(x, 0, z);
553  vertices.emplace_back(pt);
554  }
555 
556  return STATUS_CODE_SUCCESS;
557 }
558 
559 //-----------------------------------------------------------------------------------------------------------------------------------------
560 
561 bool DlSecondaryVertexingAlgorithm::GrowPeak(const Canvas &canvas, int col, int row, float intensity, std::vector<std::pair<int, int>> &peak) const
562 {
563  // if (col >= 0 && col < canvas.m_width && row >= 0 && row < canvas.m_height)
564  // {
565  // std::cout << "Visited: " << canvas.m_visited[row][col] << " " <<
566  // }
567  if (col < 0 || col >= canvas.m_width || row < 0 || row >= canvas.m_height || canvas.m_visited[row][col] || canvas.m_canvas[row][col] < intensity)
568  return false;
569 
570  // Check that no adjacent pixel is larger than this one
571  for (int dc = -1; dc <= 1; ++dc)
572  {
573  const int c{col + dc};
574  if (c < 0 || c >= canvas.m_width)
575  continue;
576 
577  for (int dr = -1; dr <= 1; ++dr)
578  {
579  const int r{row + dr};
580  if (r < 0 || r >= canvas.m_height)
581  continue;
582 
583  if (dr == 0 && dc == 0)
584  continue;
585 
586  const float neighborIntensity{canvas.m_canvas[r][c]};
587  if (neighborIntensity > intensity)
588  return false;
589  }
590  }
591 
592  // Need to check we aren't growing into a higher peak, if we are restart from the current pixel
593  float localIntensity{canvas.m_canvas[row][col]};
594  if (localIntensity > intensity)
595  {
596  intensity = localIntensity;
597  for (const auto &pixel : peak)
598  canvas.m_visited[pixel.second][pixel.first] = false;
599  peak.clear();
600  //std::cout << ". New size " << peak.size() << " new intensity " << intensity << std::endl;
601  this->GrowPeak(canvas, col, row, intensity, peak);
602  return true;
603  }
604 
605  // Add pixel to the peak
606  canvas.m_visited[row][col] = true;
607  peak.emplace_back(std::make_pair(col, row));
608  //std::cout << " Added" << std::endl;
609 
610  for (int dc = -1; dc <= 1; ++dc)
611  {
612  for (int dr = -1; dr <= 1; ++dr)
613  {
614  if (dr == 0 && dc == 0)
615  continue;
616  //std::cout << " Adjacent (" << (row + i) << "," << (col + j) << ")" << std::endl;
617  bool reset{this->GrowPeak(canvas, col + dc, row + dr, intensity, peak)};
618  // If we started growing a non-peak region, stop looking relative to the previous peak
619  if (reset)
620  return reset;
621  }
622  }
623 
624  return false;
625 }
626 
627 //-----------------------------------------------------------------------------------------------------------------------------------------
628 
629 StatusCode DlSecondaryVertexingAlgorithm::MakeCandidateVertexList(const CartesianPointVector &positions)
630 {
631  const VertexList *pVertexList{nullptr};
632  std::string temporaryListName;
633  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::CreateTemporaryListAndSetCurrent(*this, pVertexList, temporaryListName));
634 
635  for (const CartesianVector &position : positions)
636  {
637  PandoraContentApi::Vertex::Parameters parameters;
638  parameters.m_position = position;
639  parameters.m_vertexLabel = VERTEX_INTERACTION;
640  parameters.m_vertexType = VERTEX_3D;
641 
642  const Vertex *pVertex(nullptr);
643  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Vertex::Create(*this, parameters, pVertex));
644  }
645  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList<Vertex>(*this, m_outputVertexListName));
646 
647  return STATUS_CODE_SUCCESS;
648 }
649 
650 //-----------------------------------------------------------------------------------------------------------------------------------------
651 
652 StatusCode DlSecondaryVertexingAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
653 {
654  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, DlVertexingBaseAlgorithm::ReadSettings(xmlHandle));
655 
656  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "Visualise", m_visualise));
657 
658  if (!m_trainingMode)
659  {
660  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "WriteTree", m_writeTree));
661  if (m_writeTree)
662  {
663  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "RootTreeName", m_rootTreeName));
664  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "RootFileName", m_rootFileName));
665  }
666  }
667 
668  return STATUS_CODE_SUCCESS;
669 }
670 
671 //-----------------------------------------------------------------------------------------------------------------------------------------
672 //-----------------------------------------------------------------------------------------------------------------------------------------
673 
674 DlSecondaryVertexingAlgorithm::Canvas::Canvas(const HitType view, const int width, const int height, const int colOffset,
675  const int rowOffset, const float xMin, const float xMax, const float zMin, const float zMax) :
676  m_view{view},
677  m_width{width},
678  m_height{height},
679  m_colOffset{colOffset},
680  m_rowOffset{rowOffset},
681  m_xMin{xMin},
682  m_xMax{xMax},
683  m_zMin{zMin},
684  m_zMax{zMax}
685 {
686  m_canvas = new float *[m_height];
687  m_visited = new bool *[m_height];
688  for (int r = 0; r < m_height; ++r)
689  {
690  m_canvas[r] = new float[m_width]{};
691  m_visited[r] = new bool[m_width]{false};
692  }
693 }
694 
695 //-----------------------------------------------------------------------------------------------------------------------------------------
696 
698 {
699  for (int r = 0; r < m_height; ++r)
700  {
701  delete[] m_canvas[r];
702  delete[] m_visited[r];
703  }
704  delete[] m_canvas;
705  delete[] m_visited;
706 }
707 
708 } // namespace lar_dl_content
Float_t x
Definition: compare.C:6
TRandom r
Definition: spectrum.C:23
int m_pass
The pass of the train/infer step.
std::unordered_map< const pandora::MCParticle *, pandora::CaloHitList > MCContributionMap
Header file for the lar deep learning helper helper class.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
MvaTypes::MvaFeatureVector MvaFeatureVector
Definition: LArMvaHelper.h:75
LArEventTopology class.
Header file for the vertex tuple object.
pandora::StatusCode GetNetworkVertices(const CanvasViewMap &canvases, pandora::CartesianPointVector &positionVector) const
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
LArDLHelper::TorchModel m_modelU
The model for the U view.
const pandora::CartesianPointVector & GetComponents() const
Definition: VertexTuple.cc:91
Double_t z
Definition: plot.C:276
void GetVertices(pandora::CartesianPointVector &vertices) const
Extract the clear topological vertices from the event.
pandora::StatusCode GetVerticesFromCanvas(const Canvas &canvas, pandora::CartesianPointVector &vertices) const
std::vector< double > m_thresholds
Distance class thresholds.
void ConstructVisibleHierarchy()
Construct a particle hierarchy based on the key topological features in an event. ...
Canvas(const pandora::HitType view, const int width, const int height, const int colOffset, const int rowOffset, const float xMin, const float xMax, const float zMin, const float zMax)
Default constructor.
Header file for lar event topology.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
std::string m_trainingOutputFile
Output file name for training examples.
TFile f
Definition: plotHisto.C:6
std::string m_outputVertexListName
Output vertex list name.
Header file for the geometry helper class.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
static void DrawRing(float **canvas, const int row, const int col, const int inner, const int outer, const float weight)
Add a filled ring to the specified canvas. The ring has an inner radius based on the minimum predicte...
std::mt19937 m_rng
The random number generator.
Int_t col[ntarg]
Definition: Style.C:29
TMarker * pt
Definition: egs.C:25
pandora::StringVector m_caloHitListNames
Names of input calo hit lists.
bool m_visualise
Whether or not to visualise the candidate vertices.
Header file for the file helper class.
void GetHitRegion(const pandora::CaloHitList &caloHitList, float &xMin, float &xMax, float &zMin, float &zMax) const
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 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 vertex helper class.
VertexTuple class.
Definition: VertexTuple.h:18
pandora::StatusCode MakeCandidateVertexList(const pandora::CartesianPointVector &positions)
Create a vertex list from the candidate vertices.
LArDLHelper::TorchModel m_modelW
The model for the W view.
bool m_writeTree
Whether or not to write validation details to a ROOT tree.
HitType
Definition: HitType.h:12
std::map< pandora::HitType, Canvas * > CanvasViewMap
void PruneHierarchy()
Fold or remove particles that aren&#39;t substantive parts of the hierarchy.
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
int m_nClasses
The number of distance classes.
Float_t e
Definition: plot.C:35
second_as<> second
Type of time stored in seconds, in double precision.
Definition: spacetime.h:82
bool GrowPeak(const Canvas &canvas, int col, int row, float intensity, std::vector< std::pair< int, int >> &peak) const
Determine if the pixel under consideration is part of a peak and grow that peak to include all connec...
static void InitialiseInput(const at::IntArrayRef dimensions, TorchInput &tensor)
Create a torch input tensor.
Definition: LArDLHelper.cc:34
std::list< Vertex > VertexList
Definition: DCEL.h:169
std::string m_volumeType
The name of the fiducial volume type for the monitoring output.
LArDLHelper::TorchModel m_modelV
The model for the V view.
std::vector< torch::jit::IValue > TorchInputVector
Definition: LArDLHelper.h:27
vertex reconstruction