Pandora
Pandora source code navigator
Loading...
Searching...
No Matches
ShowerStartFinderTool.cc
Go to the documentation of this file.
1
11
14
18
20
21using namespace pandora;
22
23namespace lar_content
24{
25
27 m_spineSlidingFitWindow(10),
28 m_longitudinalCoordinateBinSize(1.f),
29 m_nInitialEnergyBins(5),
30 m_minSigmaDeviation(1.f),
31 m_maxEdgeGap(3.f),
32 m_longitudinalShowerFraction(0.85f),
33 m_minShowerOpeningAngle(2.f),
34 m_molliereRadius(4.5f),
35 m_showerSlidingFitWindow(1000),
36 m_maxLayerSeparation(5)
37{
38}
39
40//------------------------------------------------------------------------------------------------------------------------------------------
41
42StatusCode ShowerStartFinderTool::Run(const ParticleFlowObject *const pShowerPfo, const CartesianVector &peakDirection,
43 const HitType hitType, const CaloHitList &showerSpineHitList, CartesianVector &showerStartPosition, CartesianVector &showerStartDirection)
44{
45 try
46 {
47 // Fit the shower spine
48 CartesianPointVector hitPositions;
49 for (const CaloHit *const pCaloHit : showerSpineHitList)
50 hitPositions.push_back(pCaloHit->GetPositionVector());
51
52 const TwoDSlidingFitResult spineTwoDSlidingFit(
54
55 // First obtain the longitudinal position of spine hits
56 LongitudinalPositionMap longitudinalPositionMap;
57 this->ObtainLongitudinalDecomposition(spineTwoDSlidingFit, showerSpineHitList, longitudinalPositionMap);
58
59 // Obtain spine energy profile
60 EnergySpectrumMap energySpectrumMap;
61 this->GetEnergyDistribution(showerSpineHitList, longitudinalPositionMap, energySpectrumMap);
62
63 // Now find the shower start position/direction
64 const bool isEndDownstream(peakDirection.GetZ() > 0.f);
65
66 this->FindShowerStartAndDirection(pShowerPfo, hitType, spineTwoDSlidingFit, energySpectrumMap, showerSpineHitList, isEndDownstream,
67 showerStartPosition, showerStartDirection);
68 }
69 catch (...)
70 {
71 return STATUS_CODE_FAILURE;
72 }
73
74 return STATUS_CODE_SUCCESS;
75}
76
77//------------------------------------------------------------------------------------------------------------------------------------------
78
80 const CaloHitList &showerSpineHitList, LongitudinalPositionMap &longitudinalPositionMap) const
81{
82 // Find hits in each layer
83 LayerToHitMap layerToHitMap;
84
85 for (const CaloHit *const pCaloHit : showerSpineHitList)
86 {
87 float hitL(0.f), hitT(0.f);
88 const CartesianVector hitPosition(pCaloHit->GetPositionVector());
89
90 spineTwoDSlidingFit.GetLocalPosition(hitPosition, hitL, hitT);
91 layerToHitMap[spineTwoDSlidingFit.GetLayer(hitL)].push_back(pCaloHit);
92 }
93
94 // Walk through layers and store the longitudinal distance of each hit
95 // IMPORTANT: layer positions correspond to the middle of the layer
96 // IMPORTANT: the longitudinal distance is measured relative to the first layer position (where l = 0)
97 // IMPORTANT: at any point, the running distance is that at the lowest neighbour central position
98 float runningDistance(0);
99 const LayerFitResultMap &layerFitResultMap(spineTwoDSlidingFit.GetLayerFitResultMap());
100
101 for (auto iter = layerToHitMap.begin(); iter != layerToHitMap.end(); ++iter)
102 {
103 const int layer(iter->first);
104 const float layerL(layerFitResultMap.at(layer).GetL());
105
106 // Get global positions of layer and its neighbours
107 const int higherLayer(std::next(iter) == layerToHitMap.end() ? layer : std::next(iter)->first);
108 const int middleLayer(layer);
109 const int lowerLayer(iter == layerToHitMap.begin() ? layer : std::prev(iter)->first);
110 CartesianVector lowerLayerPosition(0.f, 0.f, 0.f), middleLayerPosition(0.f, 0.f, 0.f), higherLayerPosition(0.f, 0.f, 0.f);
111
112 spineTwoDSlidingFit.GetGlobalPosition(layerFitResultMap.at(lowerLayer).GetL(), layerFitResultMap.at(lowerLayer).GetFitT(), lowerLayerPosition);
113 spineTwoDSlidingFit.GetGlobalPosition(layerFitResultMap.at(middleLayer).GetL(), layerFitResultMap.at(middleLayer).GetFitT(), middleLayerPosition);
114 spineTwoDSlidingFit.GetGlobalPosition(layerFitResultMap.at(higherLayer).GetL(), layerFitResultMap.at(higherLayer).GetFitT(), higherLayerPosition);
115
116 const float layerLength = std::next(iter) == layerToHitMap.end()
117 ? 0.f
118 : iter == layerToHitMap.begin() ? 0.f : (middleLayerPosition - lowerLayerPosition).GetMagnitude();
119
120 for (const CaloHit *const pCaloHit : iter->second)
121 {
122 const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
123
124 float hitL(0.f), hitT(0.f);
125 spineTwoDSlidingFit.GetLocalPosition(hitPosition, hitL, hitT);
126
127 // Is the hit below or above the middle of the layer?
128 // Therefore, determine which layer positions the hit is between
129 CartesianVector localLowerLayerPosition(0.f, 0.f, 0.f), localHigherLayerPosition(0.f, 0.f, 0.f);
130
131 if (hitL < layerL)
132 {
133 localLowerLayerPosition = lowerLayerPosition;
134 localHigherLayerPosition = iter == layerToHitMap.begin() ? higherLayerPosition : middleLayerPosition;
135 }
136 else
137 {
138 localLowerLayerPosition = std::next(iter) == layerToHitMap.end() ? lowerLayerPosition : middleLayerPosition;
139 localHigherLayerPosition = higherLayerPosition;
140 }
141
142 // Determine the axis to project onto
143 // Calculate the distance of axis between its two nearest neighbours
144 const CartesianVector displacement((higherLayerPosition - lowerLayerPosition).GetUnitVector());
145 float longitudinalDisplacement = (displacement.GetDotProduct(hitPosition - lowerLayerPosition) + runningDistance);
146
147 // If we've passed the central position, we need to add on the layer length
148 longitudinalDisplacement += (hitL > layerL ? layerLength : 0.f);
149
150 longitudinalPositionMap[pCaloHit] = longitudinalDisplacement;
151 }
152
153 runningDistance += layerLength;
154 }
155}
156
157//------------------------------------------------------------------------------------------------------------------------------------------
158
160 const LongitudinalPositionMap &longitudinalPositionMap, EnergySpectrumMap &energySpectrumMap) const
161{
162 float e0(0.f);
163
164 for (const CaloHit *pCaloHit : showerSpineHitList)
165 e0 += pCaloHit->GetElectromagneticEnergy();
166
167 for (const CaloHit *pCaloHit : showerSpineHitList)
168 {
169 const float fractionalEnergy(pCaloHit->GetElectromagneticEnergy() / e0);
170 const float projection(longitudinalPositionMap.at(pCaloHit));
171 const int longitudinalIndex = std::floor(projection / m_longitudinalCoordinateBinSize);
172
173 if (energySpectrumMap.find(longitudinalIndex) == energySpectrumMap.end())
174 energySpectrumMap[longitudinalIndex] = fractionalEnergy;
175 else
176 energySpectrumMap[longitudinalIndex] += fractionalEnergy;
177 }
178}
179
180//------------------------------------------------------------------------------------------------------------------------------------------
181
183 const TwoDSlidingFitResult &spineTwoDSlidingFit, const EnergySpectrumMap &energySpectrumMap, const CaloHitList &showerSpineHitList,
184 const bool isEndDownstream, CartesianVector &showerStartPosition, CartesianVector &showerStartDirection) const
185{
186 // Search for shower start at significant energy deviations
187 int longitudinalStartBin(0);
188
189 if (isEndDownstream)
190 {
191 longitudinalStartBin = this->FindShowerStartLongitudinalCoordinate(pShowerPfo, hitType, spineTwoDSlidingFit, energySpectrumMap,
192 showerSpineHitList, isEndDownstream, energySpectrumMap.begin(), std::prev(energySpectrumMap.end()));
193 }
194 else
195 {
196 longitudinalStartBin = this->FindShowerStartLongitudinalCoordinate(pShowerPfo, hitType, spineTwoDSlidingFit, energySpectrumMap,
197 showerSpineHitList, isEndDownstream, energySpectrumMap.rbegin(), std::prev(energySpectrumMap.rend()));
198 }
199
200 const float longitudinalStartCoordinate(longitudinalStartBin * m_longitudinalCoordinateBinSize);
201
202 this->ConvertLongitudinalProjectionToGlobal(spineTwoDSlidingFit, longitudinalStartCoordinate, showerStartPosition, showerStartDirection);
203
204 showerStartDirection = isEndDownstream ? showerStartDirection : showerStartDirection * (-1.f);
205}
206
207//------------------------------------------------------------------------------------------------------------------------------------------
208
209template <typename T>
211 const TwoDSlidingFitResult &spineTwoDSlidingFit, const EnergySpectrumMap &energySpectrumMap, const CaloHitList &showerSpineHitList,
212 const bool isEndDownstream, const T startIter, const T endIter) const
213{
214 // Characterise initial energy
215 float meanEnergy(0.f), energySigma(0.f);
216
217 if (energySpectrumMap.size() > m_nInitialEnergyBins)
218 this->CharacteriseInitialEnergy(energySpectrumMap, isEndDownstream, meanEnergy, energySigma);
219
220 // Now loop through energySpectrumMap
221 T iter(startIter);
222
223 std::advance(iter, (energySpectrumMap.size() > m_nInitialEnergyBins) ? m_nInitialEnergyBins : (energySpectrumMap.size() - 1));
224
225 for (; iter != endIter; iter++)
226 {
227 const float longitudinalCoordinate(iter->first * m_longitudinalCoordinateBinSize);
228 const float energyDeviation((iter->second - meanEnergy) / energySigma);
229
230 // Use energy and local topology to assess whether we are at the shower start
231 if ((energyDeviation > m_minSigmaDeviation) &&
232 this->IsShowerTopology(pShowerPfo, hitType, spineTwoDSlidingFit, longitudinalCoordinate, showerSpineHitList, isEndDownstream))
233 {
234 break;
235 }
236 }
237
238 return iter->first;
239}
240
241//------------------------------------------------------------------------------------------------------------------------------------------
242
244 const EnergySpectrumMap &energySpectrumMap, const bool isEndDownstream, float &meanEnergy, float &energySigma) const
245{
246 auto energySpectrumIter(isEndDownstream ? energySpectrumMap.begin() : std::prev(energySpectrumMap.end()));
247
248 for (unsigned int i = 0; i < m_nInitialEnergyBins; ++i)
249 {
250 meanEnergy += energySpectrumIter->second;
251 isEndDownstream ? ++energySpectrumIter : --energySpectrumIter;
252 }
253
254 meanEnergy /= static_cast<float>(m_nInitialEnergyBins);
255
256 energySpectrumIter = isEndDownstream ? energySpectrumMap.begin() : std::prev(energySpectrumMap.end());
257
258 for (unsigned int i = 0; i < m_nInitialEnergyBins; ++i)
259 {
260 energySigma += std::pow(energySpectrumIter->second - meanEnergy, 2);
261 isEndDownstream ? ++energySpectrumIter : --energySpectrumIter;
262 }
263
264 energySigma = std::sqrt(energySigma / m_nInitialEnergyBins);
265}
266
267//------------------------------------------------------------------------------------------------------------------------------------------
268
269bool ShowerStartFinderTool::IsShowerTopology(const ParticleFlowObject *const pShowerPfo, const HitType hitType, const TwoDSlidingFitResult &spineTwoDSlidingFit,
270 const float longitudinalDistance, const CaloHitList &showerSpineHitList, const bool isEndDownstream) const
271{
272 CartesianVector showerStartPosition(0.f, 0.f, 0.f), showerStartDirection(0.f, 0.f, 0.f);
273 this->ConvertLongitudinalProjectionToGlobal(spineTwoDSlidingFit, longitudinalDistance, showerStartPosition, showerStartDirection);
274
275 // Build shower
276 CartesianPointVector showerRegionPositionVector;
277 if (this->BuildShowerRegion(pShowerPfo, hitType, showerSpineHitList, showerStartPosition, showerStartDirection, isEndDownstream,
278 showerRegionPositionVector) != STATUS_CODE_SUCCESS)
279 {
280 return false;
281 }
282
283 // Characterise the shower
284 bool isBetween(false);
285 CartesianVector positiveEdgeStart(0.f, 0.f, 0.f), positiveEdgeEnd(0.f, 0.f, 0.f), positiveEdgeDirection(0.f, 0.f, 0.f);
286 CartesianVector negativeEdgeStart(0.f, 0.f, 0.f), negativeEdgeEnd(0.f, 0.f, 0.f), negativeEdgeDirection(0.f, 0.f, 0.f);
287
288 if (this->CharacteriseShowerTopology(showerRegionPositionVector, showerStartPosition, hitType, isEndDownstream, showerStartDirection,
289 positiveEdgeStart, positiveEdgeEnd, negativeEdgeStart, negativeEdgeEnd, isBetween) != STATUS_CODE_SUCCESS)
290 {
291 return false;
292 }
293
294 if (!isBetween)
295 return false;
296
297 positiveEdgeStart = showerStartPosition;
298 negativeEdgeStart = showerStartPosition;
299 positiveEdgeDirection = positiveEdgeEnd - positiveEdgeStart;
300 negativeEdgeDirection = negativeEdgeEnd - negativeEdgeStart;
301
302 const float showerOpeningAngle(positiveEdgeDirection.GetOpeningAngle(negativeEdgeDirection) * 180.f / 3.14);
303
304 if (showerOpeningAngle < m_minShowerOpeningAngle)
305 return false;
306
307 return true;
308}
309
310//------------------------------------------------------------------------------------------------------------------------------------------
311
313 const float longitudinalDistance, CartesianVector &globalPosition, CartesianVector &globalDirection) const
314{
315 const LayerFitResultMap &layerFitResultMap(spineTwoDSlidingFit.GetLayerFitResultMap());
316
317 float runningDistance(0.f);
318 int showerStartLayer(0);
319 CartesianVector previousLayerPosition(0.f, 0.f, 0.f);
320 spineTwoDSlidingFit.GetGlobalPosition(layerFitResultMap.begin()->second.GetL(), layerFitResultMap.begin()->second.GetFitT(), previousLayerPosition);
321
322 for (auto iter = std::next(layerFitResultMap.begin()); iter != layerFitResultMap.end(); ++iter)
323 {
324 const int layer(iter->first);
325 showerStartLayer = layer;
326
327 CartesianVector layerPosition(0.f, 0.f, 0.f);
328 spineTwoDSlidingFit.GetGlobalPosition(layerFitResultMap.at(layer).GetL(), layerFitResultMap.at(layer).GetFitT(), layerPosition);
329
330 runningDistance += (layerPosition - previousLayerPosition).GetMagnitude();
331
332 if (runningDistance > longitudinalDistance)
333 break;
334
335 previousLayerPosition = layerPosition;
336 }
337
338 const float lCoordinate(layerFitResultMap.at(showerStartLayer).GetL()), tCoordinate(layerFitResultMap.at(showerStartLayer).GetFitT());
339 const float localGradient(layerFitResultMap.at(showerStartLayer).GetGradient());
340
341 spineTwoDSlidingFit.GetGlobalPosition(lCoordinate, tCoordinate, globalPosition);
342 spineTwoDSlidingFit.GetGlobalDirection(localGradient, globalDirection);
343}
344
345//------------------------------------------------------------------------------------------------------------------------------------------
346
348 const CaloHitList &showerSpineHitList, const CartesianVector &showerStartPosition, const CartesianVector &showerStartDirection,
349 const bool isEndDownstream, CartesianPointVector &showerRegionPositionVector) const
350{
351 CaloHitList viewShowerHitList;
352 LArPfoHelper::GetCaloHits(pShowerPfo, hitType, viewShowerHitList);
353
354 // Find shower region hits
355 CaloHitList showerRegionHitList;
356
357 for (const CaloHit *const pCaloHit : viewShowerHitList)
358 {
359 if (std::find(showerSpineHitList.begin(), showerSpineHitList.end(), pCaloHit) != showerSpineHitList.end())
360 continue;
361
362 const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
363 float l(showerStartDirection.GetDotProduct(hitPosition - showerStartPosition));
364
365 l *= isEndDownstream ? 1.f : -1.f;
366
367 if (l < 0.f)
368 continue;
369
370 if (showerStartDirection.GetCrossProduct(hitPosition - showerStartPosition).GetMagnitude() > m_molliereRadius)
371 continue;
372
373 showerRegionPositionVector.push_back(pCaloHit->GetPositionVector());
374 showerRegionHitList.push_back(pCaloHit);
375 }
376
377 // Searching for a continuous shower, so truncate at first gap
378 CartesianPointVector coordinateListP, coordinateListN;
379 try
380 {
381 // Perform shower sliding fit
382 const TwoDSlidingShowerFitResult twoDShowerSlidingFit(
383 &showerRegionPositionVector, m_showerSlidingFitWindow, LArGeometryHelper::GetWirePitch(this->GetPandora(), hitType));
384 const LayerFitResultMap &layerFitResultMapS(twoDShowerSlidingFit.GetShowerFitResult().GetLayerFitResultMap());
385 const LayerFitResultMap &layerFitResultMapP(twoDShowerSlidingFit.GetPositiveEdgeFitResult().GetLayerFitResultMap());
386 const LayerFitResultMap &layerFitResultMapN(twoDShowerSlidingFit.GetNegativeEdgeFitResult().GetLayerFitResultMap());
387
388 float showerStartL(0.f), showerStartT(0.f);
389 twoDShowerSlidingFit.GetShowerFitResult().GetLocalPosition(showerStartPosition, showerStartL, showerStartT);
390
391 const int startLayer(twoDShowerSlidingFit.GetShowerFitResult().GetLayer(showerStartL));
392
393 // Check for gaps in the shower
394 for (LayerFitResultMap::const_iterator iterS = layerFitResultMapS.begin(); iterS != layerFitResultMapS.end(); ++iterS)
395 {
396 const int layer(iterS->first);
397
398 if (isEndDownstream && (layer < startLayer))
399 continue;
400
401 if (!isEndDownstream && (layer > startLayer))
402 continue;
403
404 LayerFitResultMap::const_iterator iterP = layerFitResultMapP.find(layer);
405 LayerFitResultMap::const_iterator iterN = layerFitResultMapN.find(layer);
406
407 if (layerFitResultMapP.end() != iterP)
408 {
409 CartesianVector positiveEdgePosition(0.f, 0.f, 0.f);
410 twoDShowerSlidingFit.GetShowerFitResult().GetGlobalPosition(iterP->second.GetL(), iterP->second.GetFitT(), positiveEdgePosition);
411 coordinateListP.push_back(positiveEdgePosition);
412 }
413
414 if (layerFitResultMapN.end() != iterN)
415 {
416 CartesianVector negativeEdgePosition(0.f, 0.f, 0.f);
417 twoDShowerSlidingFit.GetShowerFitResult().GetGlobalPosition(iterN->second.GetL(), iterN->second.GetFitT(), negativeEdgePosition);
418 coordinateListN.push_back(negativeEdgePosition);
419 }
420 }
421
422 if ((coordinateListP.size() == 0) || (coordinateListN.size() == 0))
423 return STATUS_CODE_FAILURE;
424
425 std::sort(coordinateListP.begin(), coordinateListP.end(), LArConnectionPathwayHelper::SortByDistanceToPoint(showerStartPosition));
426 std::sort(coordinateListN.begin(), coordinateListN.end(), LArConnectionPathwayHelper::SortByDistanceToPoint(showerStartPosition));
427
428 float pMaximumL(std::numeric_limits<float>::max());
429 CartesianVector previousCoordinateP(coordinateListP.front());
430
431 for (auto iterP = std::next(coordinateListP.begin()); iterP != coordinateListP.end(); ++iterP)
432 {
433 const CartesianVector &coordinateP(*iterP);
434 const float separationSquared((coordinateP - previousCoordinateP).GetMagnitudeSquared());
435
436 if (separationSquared > (m_maxEdgeGap * m_maxEdgeGap))
437 break;
438
439 float thisT(0.f);
440 twoDShowerSlidingFit.GetShowerFitResult().GetLocalPosition(coordinateP, pMaximumL, thisT);
441
442 previousCoordinateP = coordinateP;
443 }
444
445 float nMaximumL(std::numeric_limits<float>::max());
446 CartesianVector previousCoordinateN(coordinateListN.front());
447
448 for (auto iterN = std::next(coordinateListN.begin()); iterN != coordinateListN.end(); ++iterN)
449 {
450 const CartesianVector &coordinateN(*iterN);
451 const float separationSquared((coordinateN - previousCoordinateN).GetMagnitudeSquared());
452
453 if (separationSquared > (m_maxEdgeGap * m_maxEdgeGap))
454 break;
455
456 float thisT(0.f);
457 twoDShowerSlidingFit.GetShowerFitResult().GetLocalPosition(coordinateN, nMaximumL, thisT);
458
459 previousCoordinateN = coordinateN;
460 }
461
462 // Now truncate the halo hit position vector
463 showerRegionPositionVector.clear();
464
465 for (const CaloHit *const pCaloHit : showerRegionHitList)
466 {
467 float thisL(0.f), thisT(0.f);
468 const CartesianVector &hitPosition(pCaloHit->GetPositionVector());
469
470 twoDShowerSlidingFit.GetShowerFitResult().GetLocalPosition(hitPosition, thisL, thisT);
471
472 // because the end of showers can get really narrow and thus fail the opening angle check
473 if (isEndDownstream && (thisL > (m_longitudinalShowerFraction * std::max(pMaximumL, nMaximumL))))
474 continue;
475
476 if (!isEndDownstream && (thisL < (m_longitudinalShowerFraction * std::min(pMaximumL, nMaximumL))))
477 continue;
478
479 showerRegionPositionVector.push_back(pCaloHit->GetPositionVector());
480 }
481 }
482 catch (const StatusCodeException &)
483 {
484 return STATUS_CODE_FAILURE;
485 }
486
487 return STATUS_CODE_SUCCESS;
488}
489
490//------------------------------------------------------------------------------------------------------------------------------------------
491
492StatusCode ShowerStartFinderTool::CharacteriseShowerTopology(const CartesianPointVector &showerRegionPositionVector, const CartesianVector &showerStartPosition,
493 const HitType hitType, const bool isEndDownstream, const CartesianVector &showerStartDirection, CartesianVector &positiveEdgeStart,
494 CartesianVector &positiveEdgeEnd, CartesianVector &negativeEdgeStart, CartesianVector &negativeEdgeEnd, bool &isBetween) const
495{
496 try
497 {
498 // Perform shower sliding fit
499 const TwoDSlidingShowerFitResult twoDShowerSlidingFit(
500 &showerRegionPositionVector, m_showerSlidingFitWindow, LArGeometryHelper::GetWirePitch(this->GetPandora(), hitType));
501 const LayerFitResultMap &layerFitResultMapS(twoDShowerSlidingFit.GetShowerFitResult().GetLayerFitResultMap());
502 const LayerFitResultMap &layerFitResultMapP(twoDShowerSlidingFit.GetPositiveEdgeFitResult().GetLayerFitResultMap());
503 const LayerFitResultMap &layerFitResultMapN(twoDShowerSlidingFit.GetNegativeEdgeFitResult().GetLayerFitResultMap());
504
505 float showerStartL(0.f), showerStartT(0.f);
506 twoDShowerSlidingFit.GetShowerFitResult().GetLocalPosition(showerStartPosition, showerStartL, showerStartT);
507
508 const int startLayer(twoDShowerSlidingFit.GetShowerFitResult().GetLayer(showerStartL));
509 const int endLayer(twoDShowerSlidingFit.GetShowerFitResult().GetMaxLayer());
510
511 // Does the shower look to originate from the shower start position
512 int layerCount(0);
513 bool isFirstBetween(false), isLastBetween(false);
514 CartesianPointVector coordinateListP, coordinateListN;
515
516 for (LayerFitResultMap::const_iterator iterS = layerFitResultMapS.begin(); iterS != layerFitResultMapS.end(); ++iterS)
517 {
518 int layer(iterS->first);
519
520 if (isEndDownstream && (layer < startLayer))
521 continue;
522
523 if (!isEndDownstream && (layer > startLayer))
524 continue;
525
526 LayerFitResultMap::const_iterator iterP = layerFitResultMapP.find(layer);
527 LayerFitResultMap::const_iterator iterN = layerFitResultMapN.find(layer);
528
529 CartesianVector positiveEdgePosition(0.f, 0.f, 0.f), negativeEdgePosition(0.f, 0.f, 0.f);
530 if (layerFitResultMapP.end() != iterP)
531 {
532 twoDShowerSlidingFit.GetShowerFitResult().GetGlobalPosition(iterP->second.GetL(), iterP->second.GetFitT(), positiveEdgePosition);
533 coordinateListP.push_back(positiveEdgePosition);
534 }
535
536 if (layerFitResultMapN.end() != iterN)
537 {
538 twoDShowerSlidingFit.GetShowerFitResult().GetGlobalPosition(iterN->second.GetL(), iterN->second.GetFitT(), negativeEdgePosition);
539 coordinateListN.push_back(negativeEdgePosition);
540 }
541
542 if ((layerFitResultMapP.end() != iterP) && (layerFitResultMapN.end() != iterN))
543 {
544 const CartesianVector positiveDisplacement((positiveEdgePosition - showerStartPosition).GetUnitVector());
545 const bool isPositiveClockwise(this->IsClockwiseRotation(showerStartDirection, positiveDisplacement));
546
547 const CartesianVector negativeDisplacement((negativeEdgePosition - showerStartPosition).GetUnitVector());
548 const bool isNegativeClockwise(this->IsClockwiseRotation(showerStartDirection, negativeDisplacement));
549
550 ++layerCount;
551
552 if (layerCount == 1)
553 isFirstBetween = (isPositiveClockwise != isNegativeClockwise);
554
555 isLastBetween = (isPositiveClockwise != isNegativeClockwise);
556 }
557 }
558
559 isBetween = (isFirstBetween || isLastBetween);
560
561 // Find the extremal points of the shower
562 if (this->GetBoundaryExtremalPoints(twoDShowerSlidingFit, layerFitResultMapP, showerStartPosition, startLayer, endLayer,
563 positiveEdgeStart, positiveEdgeEnd) != STATUS_CODE_SUCCESS)
564 {
565 return STATUS_CODE_FAILURE;
566 }
567
568 if (this->GetBoundaryExtremalPoints(twoDShowerSlidingFit, layerFitResultMapN, showerStartPosition, startLayer, endLayer,
569 negativeEdgeStart, negativeEdgeEnd) != STATUS_CODE_SUCCESS)
570 {
571 return STATUS_CODE_FAILURE;
572 }
573 }
574 catch (const StatusCodeException &)
575 {
576 return STATUS_CODE_FAILURE;
577 }
578
579 return STATUS_CODE_SUCCESS;
580}
581
582//------------------------------------------------------------------------------------------------------------------------------------------
583
584bool ShowerStartFinderTool::IsClockwiseRotation(const CartesianVector &showerStartDirection, const CartesianVector &displacementVector) const
585{
586 // Clockwise with respect to +ve Z
587 const float openingAngleFromCore(showerStartDirection.GetOpeningAngle(displacementVector));
588
589 const CartesianVector clockwiseRotation(
590 displacementVector.GetZ() * std::sin(openingAngleFromCore) + displacementVector.GetX() * std::cos(openingAngleFromCore), 0.f,
591 displacementVector.GetZ() * std::cos(openingAngleFromCore) - displacementVector.GetX() * std::sin(openingAngleFromCore));
592
593 const CartesianVector anticlockwiseRotation(
594 displacementVector.GetZ() * std::sin(-1.f * openingAngleFromCore) + displacementVector.GetX() * std::cos(-1.f * openingAngleFromCore), 0.f,
595 displacementVector.GetZ() * std::cos(-1.f * openingAngleFromCore) - displacementVector.GetX() * std::sin(-1.f * openingAngleFromCore));
596
597 const float clockwiseT((clockwiseRotation - showerStartDirection).GetMagnitude());
598 const float anticlockwiseT((anticlockwiseRotation - showerStartDirection).GetMagnitude());
599 const bool isClockwise(clockwiseT < anticlockwiseT);
600
601 return isClockwise;
602}
603
604//------------------------------------------------------------------------------------------------------------------------------------------
605
607 const LayerFitResultMap &layerFitResultMap, const CartesianVector &showerStartPosition, const int showerStartLayer,
608 const int showerEndLayer, CartesianVector &boundaryEdgeStart, CartesianVector &boundaryEdgeEnd) const
609{
610 int boundaryStartLayer(std::numeric_limits<int>::max());
611 int boundaryEndLayer(std::numeric_limits<int>::max());
612
613 for (auto &entry : layerFitResultMap)
614 {
615 const int bestStartSeparation(std::abs(showerStartLayer - boundaryStartLayer));
616 const int thisStartSeparation(std::abs(showerStartLayer - entry.first));
617
618 if (((bestStartSeparation - thisStartSeparation) > 0) && (thisStartSeparation < bestStartSeparation))
619 boundaryStartLayer = entry.first;
620
621 const int bestEndSeparation(std::abs(showerEndLayer - boundaryEndLayer));
622 const int thisEndSeparation(std::abs(showerEndLayer - entry.first));
623
624 if (((bestEndSeparation - thisEndSeparation) > 0) && (thisEndSeparation < bestEndSeparation))
625 boundaryEndLayer = entry.first;
626 }
627
628 if (std::abs(showerStartLayer - boundaryStartLayer) > m_maxLayerSeparation)
629 return STATUS_CODE_FAILURE;
630
631 const float showerStartBoundaryLocalL(layerFitResultMap.at(boundaryStartLayer).GetL()),
632 showerStartBoundaryLocalT(layerFitResultMap.at(boundaryStartLayer).GetFitT());
633 const float showerEndBoundaryLocalL(layerFitResultMap.at(boundaryEndLayer).GetL()),
634 showerEndBoundaryLocalT(layerFitResultMap.at(boundaryEndLayer).GetFitT());
635
636 showerTwoDSlidingFit.GetShowerFitResult().GetGlobalPosition(showerStartBoundaryLocalL, showerStartBoundaryLocalT, boundaryEdgeStart);
637 showerTwoDSlidingFit.GetShowerFitResult().GetGlobalPosition(showerEndBoundaryLocalL, showerEndBoundaryLocalT, boundaryEdgeEnd);
638
639 // Swap start and end if needs be
640 if ((showerStartPosition - boundaryEdgeEnd).GetMagnitudeSquared() < (showerStartPosition - boundaryEdgeStart).GetMagnitude())
641 {
642 const CartesianVector startTemp(boundaryEdgeStart), endTemp(boundaryEdgeEnd);
643
644 boundaryEdgeStart = endTemp;
645 boundaryEdgeEnd = startTemp;
646 }
647
648 return STATUS_CODE_SUCCESS;
649}
650
651//------------------------------------------------------------------------------------------------------------------------------------------
652
654{
656 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SpineSlidingFitWindow", m_spineSlidingFitWindow));
657
658 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
659 XmlHelper::ReadValue(xmlHandle, "LongitudinalCoordinateBinSize", m_longitudinalCoordinateBinSize));
660
662 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "nInitialEnergyBins", m_nInitialEnergyBins));
663
665 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinSigmaDeviation", m_minSigmaDeviation));
666
667 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxEdgeGap", m_maxEdgeGap));
668
669 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
670 XmlHelper::ReadValue(xmlHandle, "LongitudinalShowerFraction", m_longitudinalShowerFraction));
671
673 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinShowerOpeningAngle", m_minShowerOpeningAngle));
674
675 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MolliereRadius", m_molliereRadius));
676
678 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ShowerSlidingFitWindow", m_showerSlidingFitWindow));
679
681 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxLayerSeparation", m_maxLayerSeparation));
682
683 return STATUS_CODE_SUCCESS;
684}
685
686} // namespace lar_content
Grouping of header files for many classes of use in particle flow algorithms.
Header file for the algorithm tool class.
Header file for the connection pathway helper class.
Header file for the geometry helper class.
Header file for the pfo helper class.
Header file for the lar two dimensional sliding fit result class.
Header file for the lar two dimensional sliding shower fit result class.
Header file for the shower start finder tool class.
#define PANDORA_RETURN_RESULT_IF_AND_IF(StatusCode1, StatusCode2, Operator, Command)
Definition StatusCodes.h:31
static float GetWirePitch(const pandora::Pandora &pandora, const pandora::HitType view, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
static void GetCaloHits(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::CaloHitList &caloHitList)
Get a list of calo hits of a particular hit type from a list of pfos.
pandora::StatusCode GetBoundaryExtremalPoints(const TwoDSlidingShowerFitResult &showerTwoDSlidingFit, const LayerFitResultMap &layerFitResultMap, const pandora::CartesianVector &showerStartPosition, const int showerStartLayer, const int showerEndLayer, pandora::CartesianVector &boundaryEdgeStart, pandora::CartesianVector &boundaryEdgeEnd) const
Determine the start and end positions of a shower boundary.
unsigned int m_spineSlidingFitWindow
The sliding window used to fit the shower spine.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
std::map< int, pandora::CaloHitList > LayerToHitMap
pandora::StatusCode CharacteriseShowerTopology(const pandora::CartesianPointVector &showerRegionPositionVector, const pandora::CartesianVector &showerStartPosition, const pandora::HitType hitType, const bool isEndDownstream, const pandora::CartesianVector &showerStartDirection, pandora::CartesianVector &positiveEdgeStart, pandora::CartesianVector &positiveEdgeEnd, pandora::CartesianVector &negativeEdgeStart, pandora::CartesianVector &negativeEdgeEnd, bool &isBetween) const
Parameterise the topological structure of the shower region.
void ConvertLongitudinalProjectionToGlobal(const TwoDSlidingFitResult &spineTwoDSlidingFit, const float longitudinalDistance, pandora::CartesianVector &globalPosition, pandora::CartesianVector &globalDirection) const
Determine the (X,Y,Z) position and direction at a given longitudinal distance along the spine.
unsigned int m_showerSlidingFitWindow
The sliding window used to fit the shower region.
float m_minShowerOpeningAngle
The min. opening angle of a sensible shower.
void ObtainLongitudinalDecomposition(const TwoDSlidingFitResult &spineTwoDSlidingFit, const pandora::CaloHitList &showerSpineHitList, LongitudinalPositionMap &longitudinalPositionMap) const
Create the [shower spine hit -> shower spine fit longitudinal projection] map.
int FindShowerStartLongitudinalCoordinate(const pandora::ParticleFlowObject *const pShowerPfo, const pandora::HitType hitType, const TwoDSlidingFitResult &spineTwoDSlidingFit, const EnergySpectrumMap &energySpectrumMap, const pandora::CaloHitList &showerSpineHitList, const bool isEndDownstream, const T startIter, const T endIter) const
Find the longitudinal bin which corresponds to the start position of the shower cascade.
void FindShowerStartAndDirection(const pandora::ParticleFlowObject *const pShowerPfo, const pandora::HitType hitType, const TwoDSlidingFitResult &spineTwoDSlidingFit, const EnergySpectrumMap &energySpectrumMap, const pandora::CaloHitList &showerSpineHitList, const bool isEndDownstream, pandora::CartesianVector &showerStartPosition, pandora::CartesianVector &showerStartDirection) const
Find the position at which the shower cascade looks to originate, and its initial direction.
pandora::StatusCode Run(const pandora::ParticleFlowObject *const pShowerPfo, const pandora::CartesianVector &peakDirection, const pandora::HitType hitType, const pandora::CaloHitList &showerSpineHitList, pandora::CartesianVector &showerStartPosition, pandora::CartesianVector &showerStartDirection)
std::map< const pandora::CaloHit *, float > LongitudinalPositionMap
float m_minSigmaDeviation
The min. average energy deviation of a candidate shower start.
bool IsShowerTopology(const pandora::ParticleFlowObject *const pShowerPfo, const pandora::HitType hitType, const TwoDSlidingFitResult &spineTwoDSlidingFit, const float longitudinalDistance, const pandora::CaloHitList &showerSpineHitList, const bool isEndDownstream) const
Whether a sensible shower cascade looks to originate at a given position.
bool IsClockwiseRotation(const pandora::CartesianVector &showerStartDirection, const pandora::CartesianVector &displacementVector) const
Determine whether a point lies on the RHS or LHS (wrt +ve Z) of the shower core.
void GetEnergyDistribution(const pandora::CaloHitList &showerSpineHitList, const LongitudinalPositionMap &longitudinalPositionMap, EnergySpectrumMap &energySpectrumMap) const
Create the longituidnal energy distribution.
pandora::StatusCode BuildShowerRegion(const pandora::ParticleFlowObject *const pShowerPfo, const pandora::HitType hitType, const pandora::CaloHitList &showerSpineHitList, const pandora::CartesianVector &showerStartPosition, const pandora::CartesianVector &showerStartDirection, const bool isEndDownstream, pandora::CartesianPointVector &showerRegionPositionVector) const
Build the downstream 'shower region' at a given longitudinal distance along the spine.
int m_maxLayerSeparation
The max. allowed separation between the shower start and boundary start layers.
float m_maxEdgeGap
The max. allowed layer gap in a shower boundary.
unsigned int m_nInitialEnergyBins
The number of longitudinal bins that define the initial region.
void CharacteriseInitialEnergy(const EnergySpectrumMap &energySpectrumMap, const bool isEndDownstream, float &meanEnergy, float &energySigma) const
Find the mean and standard deviation of the energy depositions in the initial region.
float m_longitudinalCoordinateBinSize
The longitudinal coordinate bin size.
float m_longitudinalShowerFraction
The shower region fraction considered.
float m_molliereRadius
The max. distance from the shower core of a collected shower region hit.
void GetLocalPosition(const pandora::CartesianVector &position, float &rL, float &rT) const
Get local sliding fit coordinates for a given global position.
const LayerFitResultMap & GetLayerFitResultMap() const
Get the layer fit result map.
void GetGlobalPosition(const float rL, const float rT, pandora::CartesianVector &position) const
Get global coordinates for given sliding linear fit coordinates.
int GetMaxLayer() const
Get the maximum occupied layer in the sliding fit.
int GetLayer(const float rL) const
Get layer number for given sliding linear fit longitudinal coordinate.
void GetGlobalDirection(const float dTdL, pandora::CartesianVector &direction) const
Get global direction coordinates for given sliding linear fit gradient.
const TwoDSlidingFitResult & GetNegativeEdgeFitResult() const
Get the sliding fit result for the negative shower edge.
const TwoDSlidingFitResult & GetShowerFitResult() const
Get the sliding fit result for the full shower cluster.
const TwoDSlidingFitResult & GetPositiveEdgeFitResult() const
Get the sliding fit result for the positive shower edge.
CaloHit class.
Definition CaloHit.h:26
CartesianVector class.
float GetX() const
Get the cartesian x coordinate.
float GetZ() const
Get the cartesian z coordinate.
float GetDotProduct(const CartesianVector &rhs) const
Get the dot product of the cartesian vector with a second cartesian vector.
float GetMagnitude() const
Get the magnitude.
CartesianVector GetCrossProduct(const CartesianVector &rhs) const
Get the cross product of the cartesian vector with a second cartesian vector.
float GetOpeningAngle(const CartesianVector &rhs) const
Get the opening angle of the cartesian vector with respect to a second cartesian vector.
ParticleFlowObject class.
const Pandora & GetPandora() const
Get the associated pandora instance.
Definition Process.h:116
StatusCodeException class.
static StatusCode ReadValue(const TiXmlHandle &xmlHandle, const std::string &xmlElementName, T &t)
Read a value from an xml element.
Definition XmlHelper.h:136
std::map< int, LayerFitResult > LayerFitResultMap
HitType
Calorimeter hit type enum.
std::vector< CartesianVector > CartesianPointVector
MANAGED_CONTAINER< const CaloHit * > CaloHitList
StatusCode
The StatusCode enum.