Pandora
Pandora source code navigator
Loading...
Searching...
No Matches
ClusterFitHelper.cc
Go to the documentation of this file.
1
10
11#include "Objects/Cluster.h"
12
13#include <algorithm>
14#include <cmath>
15#include <limits>
16
17namespace pandora
18{
19
20StatusCode ClusterFitHelper::FitStart(const Cluster *const pCluster, const unsigned int maxOccupiedLayers, ClusterFitResult &clusterFitResult)
21{
22 if (maxOccupiedLayers < 2)
23 return STATUS_CODE_INVALID_PARAMETER;
24
25 const OrderedCaloHitList &orderedCaloHitList = pCluster->GetOrderedCaloHitList();
26 const unsigned int listSize(orderedCaloHitList.size());
27
28 if (0 == listSize)
29 return STATUS_CODE_NOT_INITIALIZED;
30
31 if (listSize < 2)
32 return STATUS_CODE_OUT_OF_RANGE;
33
34 unsigned int occupiedLayerCount(0);
35
36 ClusterFitPointList clusterFitPointList;
37 for (const OrderedCaloHitList::value_type &layerIter : orderedCaloHitList)
38 {
39 if (++occupiedLayerCount > maxOccupiedLayers)
40 break;
41
42 for (const CaloHit *const pCaloHit : *layerIter.second)
43 {
44 clusterFitPointList.push_back(ClusterFitPoint(pCaloHit));
45 }
46 }
47
48 return FitPoints(clusterFitPointList, clusterFitResult);
49}
50
51//------------------------------------------------------------------------------------------------------------------------------------------
52
53StatusCode ClusterFitHelper::FitEnd(const Cluster *const pCluster, const unsigned int maxOccupiedLayers, ClusterFitResult &clusterFitResult)
54{
55 if (maxOccupiedLayers < 2)
56 return STATUS_CODE_INVALID_PARAMETER;
57
58 const OrderedCaloHitList &orderedCaloHitList = pCluster->GetOrderedCaloHitList();
59 const unsigned int listSize(orderedCaloHitList.size());
60
61 if (0 == listSize)
62 return STATUS_CODE_NOT_INITIALIZED;
63
64 if (listSize < 2)
65 return STATUS_CODE_OUT_OF_RANGE;
66
67 unsigned int occupiedLayerCount(0);
68
69 ClusterFitPointList clusterFitPointList;
70 for (OrderedCaloHitList::const_reverse_iterator iter = orderedCaloHitList.rbegin(), iterEnd = orderedCaloHitList.rend(); iter != iterEnd; ++iter)
71 {
72 if (++occupiedLayerCount > maxOccupiedLayers)
73 break;
74
75 for (const CaloHit *const pCaloHit : *iter->second)
76 {
77 clusterFitPointList.push_back(ClusterFitPoint(pCaloHit));
78 }
79 }
80
81 return FitPoints(clusterFitPointList, clusterFitResult);
82}
83
84//------------------------------------------------------------------------------------------------------------------------------------------
85
87{
88 const OrderedCaloHitList &orderedCaloHitList = pCluster->GetOrderedCaloHitList();
89 const unsigned int listSize(orderedCaloHitList.size());
90
91 if (0 == listSize)
92 return STATUS_CODE_NOT_INITIALIZED;
93
94 if (listSize < 2)
95 return STATUS_CODE_OUT_OF_RANGE;
96
97 ClusterFitPointList clusterFitPointList;
98 for (const OrderedCaloHitList::value_type &layerIter : orderedCaloHitList)
99 {
100 for (const CaloHit *const pCaloHit : *layerIter.second)
101 {
102 clusterFitPointList.push_back(ClusterFitPoint(pCaloHit));
103 }
104 }
105
106 return FitPoints(clusterFitPointList, clusterFitResult);
107}
108
109//------------------------------------------------------------------------------------------------------------------------------------------
110
111StatusCode ClusterFitHelper::FitLayers(const Cluster *const pCluster, const unsigned int startLayer, const unsigned int endLayer,
112 ClusterFitResult &clusterFitResult)
113{
114 if (startLayer >= endLayer)
115 return STATUS_CODE_INVALID_PARAMETER;
116
117 const OrderedCaloHitList &orderedCaloHitList = pCluster->GetOrderedCaloHitList();
118 const unsigned int listSize(orderedCaloHitList.size());
119
120 if (0 == listSize)
121 return STATUS_CODE_NOT_INITIALIZED;
122
123 if (listSize < 2)
124 return STATUS_CODE_OUT_OF_RANGE;
125
126 ClusterFitPointList clusterFitPointList;
127 for (const OrderedCaloHitList::value_type &layerIter : orderedCaloHitList)
128 {
129 const unsigned int pseudoLayer(layerIter.first);
130
131 if (startLayer > pseudoLayer)
132 continue;
133
134 if (endLayer < pseudoLayer)
135 break;
136
137 for (const CaloHit *const pCaloHit : *layerIter.second)
138 {
139 clusterFitPointList.push_back(ClusterFitPoint(pCaloHit));
140 }
141 }
142
143 return FitPoints(clusterFitPointList, clusterFitResult);
144}
145
146//------------------------------------------------------------------------------------------------------------------------------------------
147
148StatusCode ClusterFitHelper::FitLayerCentroids(const Cluster *const pCluster, const unsigned int startLayer, const unsigned int endLayer,
149 ClusterFitResult &clusterFitResult)
150{
151 try
152 {
153 if (startLayer >= endLayer)
154 return STATUS_CODE_INVALID_PARAMETER;
155
156 const OrderedCaloHitList &orderedCaloHitList = pCluster->GetOrderedCaloHitList();
157 const unsigned int listSize(orderedCaloHitList.size());
158
159 if (0 == listSize)
160 return STATUS_CODE_NOT_INITIALIZED;
161
162 if (listSize < 2)
163 return STATUS_CODE_OUT_OF_RANGE;
164
165 ClusterFitPointList clusterFitPointList;
166 for (const OrderedCaloHitList::value_type &layerIter : orderedCaloHitList)
167 {
168 const unsigned int pseudoLayer(layerIter.first);
169
170 if (startLayer > pseudoLayer)
171 continue;
172
173 if (endLayer < pseudoLayer)
174 break;
175
176 const unsigned int nCaloHits(layerIter.second->size());
177
178 if (0 == nCaloHits)
179 throw StatusCodeException(STATUS_CODE_FAILURE);
180
181 float cellLengthScaleSum(0.f), cellEnergySum(0.f);
182 CartesianVector cellNormalVectorSum(0.f, 0.f, 0.f);
183
184 for (const CaloHit *const pCaloHit : *layerIter.second)
185 {
186 cellLengthScaleSum += pCaloHit->GetCellLengthScale();
187 cellNormalVectorSum += pCaloHit->GetCellNormalVector();
188 cellEnergySum += pCaloHit->GetInputEnergy();
189 }
190
191 clusterFitPointList.push_back(ClusterFitPoint(pCluster->GetCentroid(pseudoLayer), cellNormalVectorSum.GetUnitVector(),
192 cellLengthScaleSum / static_cast<float>(nCaloHits), cellEnergySum / static_cast<float>(nCaloHits), pseudoLayer));
193 }
194
195 return FitPoints(clusterFitPointList, clusterFitResult);
196 }
197 catch (StatusCodeException &statusCodeException)
198 {
199 clusterFitResult.SetSuccessFlag(false);
200 return statusCodeException.GetStatusCode();
201 }
202}
203
204//------------------------------------------------------------------------------------------------------------------------------------------
205
207{
208 std::sort(clusterFitPointList.begin(), clusterFitPointList.end());
209
210 try
211 {
212 const unsigned int nFitPoints(clusterFitPointList.size());
213
214 if (nFitPoints < 2)
215 return STATUS_CODE_INVALID_PARAMETER;
216
217 clusterFitResult.Reset();
218 CartesianVector positionSum(0.f, 0.f, 0.f);
219 CartesianVector normalVectorSum(0.f, 0.f, 0.f);
220
221 for (const ClusterFitPoint &clusterFitPoint : clusterFitPointList)
222 {
223 positionSum += clusterFitPoint.GetPosition();
224 normalVectorSum += clusterFitPoint.GetCellNormalVector();
225 }
226
227 return PerformLinearFit(positionSum * (1.f / static_cast<float>(nFitPoints)), normalVectorSum.GetUnitVector(), clusterFitPointList, clusterFitResult);
228 }
229 catch (StatusCodeException &statusCodeException)
230 {
231 std::cout << "ClusterFitHelper: linear fit to cluster failed. " << std::endl;
232 clusterFitResult.SetSuccessFlag(false);
233 return statusCodeException.GetStatusCode();
234 }
235}
236
237//------------------------------------------------------------------------------------------------------------------------------------------
238
239StatusCode ClusterFitHelper::PerformLinearFit(const CartesianVector &centralPosition, const CartesianVector &centralDirection,
240 ClusterFitPointList &clusterFitPointList, ClusterFitResult &clusterFitResult)
241{
242 std::sort(clusterFitPointList.begin(), clusterFitPointList.end());
243
244 // Extract the data
245 double sumP(0.), sumQ(0.), sumR(0.), sumWeights(0.);
246 double sumPR(0.), sumQR(0.), sumRR(0.);
247
248 const CartesianVector chosenAxis(0.f, 0.f, 1.f);
249 const double cosTheta(centralDirection.GetCosOpeningAngle(chosenAxis));
250 const double sinTheta(std::sin(std::acos(cosTheta)));
251
252 const CartesianVector rotationAxis((std::fabs(cosTheta) > 0.99) ? CartesianVector(1.f, 0.f, 0.f) :
253 centralDirection.GetCrossProduct(chosenAxis).GetUnitVector());
254
255 for (const ClusterFitPoint &clusterFitPoint : clusterFitPointList)
256 {
257 const CartesianVector position(clusterFitPoint.GetPosition() - centralPosition);
258 const double weight(1.);
259
260 const double p( (cosTheta + rotationAxis.GetX() * rotationAxis.GetX() * (1. - cosTheta)) * position.GetX() +
261 (rotationAxis.GetX() * rotationAxis.GetY() * (1. - cosTheta) - rotationAxis.GetZ() * sinTheta) * position.GetY() +
262 (rotationAxis.GetX() * rotationAxis.GetZ() * (1. - cosTheta) + rotationAxis.GetY() * sinTheta) * position.GetZ() );
263 const double q( (rotationAxis.GetY() * rotationAxis.GetX() * (1. - cosTheta) + rotationAxis.GetZ() * sinTheta) * position.GetX() +
264 (cosTheta + rotationAxis.GetY() * rotationAxis.GetY() * (1. - cosTheta)) * position.GetY() +
265 (rotationAxis.GetY() * rotationAxis.GetZ() * (1. - cosTheta) - rotationAxis.GetX() * sinTheta) * position.GetZ() );
266 const double r( (rotationAxis.GetZ() * rotationAxis.GetX() * (1. - cosTheta) - rotationAxis.GetY() * sinTheta) * position.GetX() +
267 (rotationAxis.GetZ() * rotationAxis.GetY() * (1. - cosTheta) + rotationAxis.GetX() * sinTheta) * position.GetY() +
268 (cosTheta + rotationAxis.GetZ() * rotationAxis.GetZ() * (1. - cosTheta)) * position.GetZ() );
269
270 sumP += p * weight; sumQ += q * weight; sumR += r * weight;
271 sumPR += p * r * weight; sumQR += q * r * weight; sumRR += r * r * weight;
272 sumWeights += weight;
273 }
274
275 // Perform the fit
276 const double denominatorR(sumR * sumR - sumWeights * sumRR);
277
278 if (std::fabs(denominatorR) < std::numeric_limits<double>::epsilon())
279 return STATUS_CODE_FAILURE;
280
281 const double aP((sumR * sumP - sumWeights * sumPR) / denominatorR);
282 const double bP((sumP - aP * sumR) / sumWeights);
283 const double aQ((sumR * sumQ - sumWeights * sumQR) / denominatorR);
284 const double bQ((sumQ - aQ * sumR) / sumWeights);
285
286 // Extract direction and intercept
287 const double magnitude(std::sqrt(1. + aP * aP + aQ * aQ));
288 const double dirP(aP / magnitude), dirQ(aQ / magnitude), dirR(1. / magnitude);
289
290 CartesianVector direction(
291 static_cast<float>((cosTheta + rotationAxis.GetX() * rotationAxis.GetX() * (1. - cosTheta)) * dirP +
292 (rotationAxis.GetX() * rotationAxis.GetY() * (1. - cosTheta) + rotationAxis.GetZ() * sinTheta) * dirQ +
293 (rotationAxis.GetX() * rotationAxis.GetZ() * (1. - cosTheta) - rotationAxis.GetY() * sinTheta) * dirR),
294 static_cast<float>((rotationAxis.GetY() * rotationAxis.GetX() * (1. - cosTheta) - rotationAxis.GetZ() * sinTheta) * dirP +
295 (cosTheta + rotationAxis.GetY() * rotationAxis.GetY() * (1. - cosTheta)) * dirQ +
296 (rotationAxis.GetY() * rotationAxis.GetZ() * (1. - cosTheta) + rotationAxis.GetX() * sinTheta) * dirR),
297 static_cast<float>((rotationAxis.GetZ() * rotationAxis.GetX() * (1. - cosTheta) + rotationAxis.GetY() * sinTheta) * dirP +
298 (rotationAxis.GetZ() * rotationAxis.GetY() * (1. - cosTheta) - rotationAxis.GetX() * sinTheta) * dirQ +
299 (cosTheta + rotationAxis.GetZ() * rotationAxis.GetZ() * (1. - cosTheta)) * dirR) );
300
301 CartesianVector intercept(centralPosition + CartesianVector(
302 static_cast<float>((cosTheta + rotationAxis.GetX() * rotationAxis.GetX() * (1. - cosTheta)) * bP +
303 (rotationAxis.GetX() * rotationAxis.GetY() * (1. - cosTheta) + rotationAxis.GetZ() * sinTheta) * bQ),
304 static_cast<float>((rotationAxis.GetY() * rotationAxis.GetX() * (1. - cosTheta) - rotationAxis.GetZ() * sinTheta) * bP +
305 (cosTheta + rotationAxis.GetY() * rotationAxis.GetY() * (1. - cosTheta)) * bQ),
306 static_cast<float>((rotationAxis.GetZ() * rotationAxis.GetX() * (1. - cosTheta) + rotationAxis.GetY() * sinTheta) * bP +
307 (rotationAxis.GetZ() * rotationAxis.GetY() * (1. - cosTheta) - rotationAxis.GetX() * sinTheta) * bQ) ));
308
309 // Extract radial direction cosine
310 float dirCosR(direction.GetDotProduct(intercept) / intercept.GetMagnitude());
311
312 if (0.f > dirCosR)
313 {
314 dirCosR = -dirCosR;
315 direction = direction * -1.f;
316 }
317
318 // Now calculate something like a chi2
319 double chi2_P(0.), chi2_Q(0.), rms(0.);
320 double sumA(0.), sumL(0.), sumAL(0.), sumLL(0.);
321
322 for (const ClusterFitPoint &clusterFitPoint : clusterFitPointList)
323 {
324 const CartesianVector position(clusterFitPoint.GetPosition() - centralPosition);
325
326 const double p( (cosTheta + rotationAxis.GetX() * rotationAxis.GetX() * (1. - cosTheta)) * position.GetX() +
327 (rotationAxis.GetX() * rotationAxis.GetY() * (1. - cosTheta) - rotationAxis.GetZ() * sinTheta) * position.GetY() +
328 (rotationAxis.GetX() * rotationAxis.GetZ() * (1. - cosTheta) + rotationAxis.GetY() * sinTheta) * position.GetZ() );
329 const double q( (rotationAxis.GetY() * rotationAxis.GetX() * (1. - cosTheta) + rotationAxis.GetZ() * sinTheta) * position.GetX() +
330 (cosTheta + rotationAxis.GetY() * rotationAxis.GetY() * (1. - cosTheta)) * position.GetY() +
331 (rotationAxis.GetY() * rotationAxis.GetZ() * (1. - cosTheta) - rotationAxis.GetX() * sinTheta) * position.GetZ() );
332 const double r( (rotationAxis.GetZ() * rotationAxis.GetX() * (1. - cosTheta) - rotationAxis.GetY() * sinTheta) * position.GetX() +
333 (rotationAxis.GetZ() * rotationAxis.GetY() * (1. - cosTheta) + rotationAxis.GetX() * sinTheta) * position.GetY() +
334 (cosTheta + rotationAxis.GetZ() * rotationAxis.GetZ() * (1. - cosTheta)) * position.GetZ() );
335
336 const double error(clusterFitPoint.GetCellSize() / 3.46);
337 const double chiP((p - aP * r - bP) / error);
338 const double chiQ((q - aQ * r - bQ) / error);
339
340 chi2_P += chiP * chiP;
341 chi2_Q += chiQ * chiQ;
342
343 const CartesianVector difference(clusterFitPoint.GetPosition() - intercept);
344 rms += (direction.GetCrossProduct(difference)).GetMagnitudeSquared();
345
346 const float a(direction.GetDotProduct(difference));
347 const float l(static_cast<float>(clusterFitPoint.GetPseudoLayer()));
348 sumA += a; sumL += l; sumAL += a * l; sumLL += l * l;
349 }
350
351 const double nPoints(static_cast<double>(clusterFitPointList.size()));
352 const double denominatorL(sumL * sumL - nPoints * sumLL);
353
354 if (std::fabs(denominatorL) > std::numeric_limits<double>::epsilon())
355 {
356 if (0. > ((sumL * sumA - nPoints * sumAL) / denominatorL))
357 direction = direction * -1.f;
358 }
359
360 clusterFitResult.SetDirection(direction);
361 clusterFitResult.SetIntercept(intercept);
362 clusterFitResult.SetChi2(static_cast<float>((chi2_P + chi2_Q) / nPoints));
363 clusterFitResult.SetRms(static_cast<float>(std::sqrt(rms / nPoints)));
364 clusterFitResult.SetRadialDirectionCosine(dirCosR);
365 clusterFitResult.SetSuccessFlag(true);
366
367 return STATUS_CODE_SUCCESS;
368}
369
370//------------------------------------------------------------------------------------------------------------------------------------------
371//------------------------------------------------------------------------------------------------------------------------------------------
372
374 m_position(pCaloHit->GetPositionVector()),
375 m_cellNormalVector(pCaloHit->GetCellNormalVector()),
376 m_cellSize(pCaloHit->GetCellLengthScale()),
377 m_energy(pCaloHit->GetInputEnergy()),
378 m_pseudoLayer(pCaloHit->GetPseudoLayer())
379{
380 if (m_cellSize < std::numeric_limits<float>::epsilon())
381 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
382}
383
384//------------------------------------------------------------------------------------------------------------------------------------------
385
386ClusterFitPoint::ClusterFitPoint(const CartesianVector &position, const CartesianVector &cellNormalVector, const float cellSize,
387 const float energy, const unsigned int pseudoLayer) :
388 m_position(position),
389 m_cellNormalVector(cellNormalVector.GetUnitVector()),
390 m_cellSize(cellSize),
391 m_energy(energy),
392 m_pseudoLayer(pseudoLayer)
393{
394 if (m_cellSize < std::numeric_limits<float>::epsilon())
395 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
396}
397
398//------------------------------------------------------------------------------------------------------------------------------------------
399
401{
402 const CartesianVector deltaPosition(rhs.GetPosition() - this->GetPosition());
403
404 if (std::fabs(deltaPosition.GetZ()) > std::numeric_limits<float>::epsilon())
405 return (deltaPosition.GetZ() > std::numeric_limits<float>::epsilon());
406
407 if (std::fabs(deltaPosition.GetX()) > std::numeric_limits<float>::epsilon())
408 return (deltaPosition.GetX() > std::numeric_limits<float>::epsilon());
409
410 if (std::fabs(deltaPosition.GetY()) > std::numeric_limits<float>::epsilon())
411 return (deltaPosition.GetY() > std::numeric_limits<float>::epsilon());
412
413 return (this->GetEnergy() > rhs.GetEnergy());
414}
415
416} // namespace pandora
Header file for the cluster class.
Header file for the cluster fit helper class.
CaloHit class.
Definition CaloHit.h:26
CartesianVector class.
float GetCosOpeningAngle(const CartesianVector &rhs) const
Get the cosine of the opening angle of the cartesian vector with respect to a second cartesian vector...
float GetX() const
Get the cartesian x coordinate.
CartesianVector GetUnitVector() const
Get a unit vector in the direction of the cartesian vector.
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 GetY() const
Get the cartesian y coordinate.
static StatusCode FitStart(const Cluster *const pCluster, const unsigned int maxOccupiedLayers, ClusterFitResult &clusterFitResult)
Fit points in first n occupied pseudolayers of a cluster.
static StatusCode FitLayers(const Cluster *const pCluster, const unsigned int startLayer, const unsigned int endLayer, ClusterFitResult &clusterFitResult)
Fit all cluster points within the specified (inclusive) pseudolayer range.
static StatusCode PerformLinearFit(const CartesianVector &centralPosition, const CartesianVector &centralDirection, ClusterFitPointList &clusterFitPointList, ClusterFitResult &clusterFitResult)
Perform linear fit to cluster fit points.
static StatusCode FitEnd(const Cluster *const pCluster, const unsigned int maxOccupiedLayers, ClusterFitResult &clusterFitResult)
Fit points in last n occupied pseudolayers of a cluster.
static StatusCode FitFullCluster(const Cluster *const pCluster, ClusterFitResult &clusterFitResult)
Fit all points in a cluster.
static StatusCode FitLayerCentroids(const Cluster *const pCluster, const unsigned int startLayer, const unsigned int endLayer, ClusterFitResult &clusterFitResult)
Fit all cluster centroids within the specified (inclusive) pseudolayer range.
static StatusCode FitPoints(ClusterFitPointList &clusterFitPointList, ClusterFitResult &clusterFitResult)
Perform linear regression of x vs d and y vs d and z vs d (assuming same error on all hits)
ClusterFitPoint class.
float m_cellSize
The size of the cell in which the point was recorded.
ClusterFitPoint(const CaloHit *const pCaloHit)
Constructor.
bool operator<(const ClusterFitPoint &rhs) const
operator< to define an ordering for cluster fit points
float GetEnergy() const
Get the energy deposited in the cell in which the point was recorded.
const CartesianVector & GetPosition() const
Get the position vector of the fit point.
ClusterFitResult class.
void SetSuccessFlag(const bool successFlag)
Set the fit success flag.
void SetRms(const float rms)
Set the fit rms.
void SetRadialDirectionCosine(const float radialDirectionCosine)
Set the fit direction cosine w.r.t. the radial direction.
void SetDirection(const CartesianVector &direction)
Set the fit direction.
void Reset()
Reset the cluster fit result.
void SetIntercept(const CartesianVector &intercept)
Set the fit intercept.
void SetChi2(const float chi2)
Set the fit chi2.
Cluster class.
Definition Cluster.h:31
const CartesianVector GetCentroid(const unsigned int pseudoLayer) const
Get unweighted centroid for cluster at a particular pseudo layer, calculated using cached values of h...
Definition Cluster.cc:37
const OrderedCaloHitList & GetOrderedCaloHitList() const
Get the ordered calo hit list.
Definition Cluster.h:470
Calo hit lists arranged by pseudo layer.
const_reverse_iterator rbegin() const
Returns a const reverse iterator referring to the first element in the ordered calo hit list.
const_reverse_iterator rend() const
Returns a const reverse iterator referring to the past-the-end element in the ordered calo hit list.
TheList::const_reverse_iterator const_reverse_iterator
unsigned int size() const
Returns the number of elements in the container.
StatusCodeException class.
StatusCode GetStatusCode() const
Get status code.
std::vector< ClusterFitPoint > ClusterFitPointList
StatusCode
The StatusCode enum.