ATLAS Offline Software
Loading...
Searching...
No Matches
ElectronMaterialMixtureConvolution.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2020-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
12
18
21//
22#include "TrkGeometry/Layer.h"
25
26#include <array>
27namespace {
28
30inline void
31dummyCacheElement(GsfMaterial::Combined& elem)
32{
33 elem.numEntries = 1;
34 elem.deltaPs[0] = 0;
35 elem.parameters[0] = AmgVector(5)::Zero();
36 elem.covariances[0] = AmgSymMatrix(5)::Zero();
37}
38
39// Avoid out-of-line Eigen calls
41inline void
42updateCacheElement(GsfMaterial::Combined& updated,
43 size_t index,
44 const AmgVector(5) & parameters,
45 const AmgSymMatrix(5) * covariance)
46{
47 updated.parameters[index] = parameters;
48 if (covariance) {
49 updated.covariances[index] += *covariance;
50 } else {
51 updated.covariances[index].setZero();
52 }
53}
54
55bool
56updateP(double& qOverP, double deltaP)
57{
58 double p = 1. / std::abs(qOverP);
59 p += deltaP;
60 if (p <= 0.) {
61 return false;
62 }
63 qOverP = qOverP > 0. ? 1. / p : -1. / p;
64 return true;
65}
66
67std::pair<const Trk::MaterialProperties*, double>
68getMaterialProperties(const Trk::TrackParameters* trackParameters,
69 const Trk::Layer& layer)
70{
71
72 const Trk::MaterialProperties* materialProperties(layer.fullUpdateMaterialProperties(*trackParameters));
73 double pathCorrection(0.);
74
75 // Bail out if still no material properties can be found
76 if (!materialProperties) {
77 return { nullptr, 0 };
78 }
79 // Define the path correction
80 pathCorrection =
81 pathCorrection > 0.
82 ? pathCorrection
83 : layer.surfaceRepresentation().pathCorrection(
84 trackParameters->position(), trackParameters->momentum());
85
86 // The pathlength ( in mm ) is the path correction * the thickness of the
87 // material
88 const double pathLength = pathCorrection * materialProperties->thickness();
89 return { materialProperties, pathLength };
90}
91
92Trk::MultiComponentState createMergedState(const GSFUtils::MergeArray& merges,
93 std::vector<GsfMaterial::Combined>& caches,
94 const std::vector<std::pair<size_t, size_t>>& indices,
95 const Trk::MultiComponentState& inputState){
96
98 size_t numComponents = indices.size();
99 // Gather the merges we need
100 std::vector<char> isMerged(numComponents, 0);
101 // Merge components "From" to components "To"
102 const int returnedMerges = merges.size();
103 for (int i = 0; i < returnedMerges; ++i) {
104 const int mini = merges[i].To;
105 const int minj = merges[i].From;
106 // Get the first TP
107 const size_t stateIndex = indices[mini].first;
108 const size_t materialIndex = indices[mini].second;
109 // Copy weight and first parameters as they are needed later on
110 // for updating the covariance
111 const AmgVector(5) firstParameters =
112 caches[stateIndex].parameters[materialIndex];
113 const double firstWeight = caches[stateIndex].weights[materialIndex];
114 // Get the second TP
115 const size_t stateIndex2 = indices[minj].first;
116 const size_t materialIndex2 = indices[minj].second;
117 // Set as merged
118 isMerged[minj] = 1;
119 // Update first parameters and weight
120 Trk::MultiComponentStateCombiner::combineParametersWithWeight(
121 caches[stateIndex].parameters[materialIndex],
122 caches[stateIndex].weights[materialIndex],
123 caches[stateIndex2].parameters[materialIndex2],
124 caches[stateIndex2].weights[materialIndex2]);
125 // Update covariance
126 Trk::MultiComponentStateCombiner::combineCovWithWeight(
127 firstParameters, caches[stateIndex].covariances[materialIndex],
128 firstWeight, caches[stateIndex2].parameters[materialIndex2],
129 caches[stateIndex2].covariances[materialIndex2],
130 caches[stateIndex2].weights[materialIndex2]);
131 // Reset 2nd parameters values just for clarity
132 caches[stateIndex2].parameters[materialIndex2].setZero();
133 caches[stateIndex2].covariances[materialIndex2].setZero();
134 }
135
136 // Loop over remaining unmerged components
137 for (size_t i(0); i < numComponents; ++i) {
138 if (isMerged[i]) {
139 continue;
140 }
141 // Build the TP
142 const size_t stateIndex = indices[i].first;
143 const size_t materialIndex = indices[i].second;
144 AmgVector(5)& stateVector =
145 caches[stateIndex].parameters[materialIndex];
146 AmgSymMatrix(5)& measuredCov =
147 caches[stateIndex].covariances[materialIndex];
148
149 std::unique_ptr<Trk::TrackParameters> updatedTrackParameters =
150 inputState[stateIndex]
151 .params->associatedSurface()
152 .createUniqueTrackParameters(
153 stateVector[Trk::loc1], stateVector[Trk::loc2],
154 stateVector[Trk::phi], stateVector[Trk::theta],
155 stateVector[Trk::qOverP], measuredCov);
156
157 const double updatedWeight = caches[stateIndex].weights[materialIndex];
158
159 assemblerCache.multiComponentState.push_back(
160 {std::move(updatedTrackParameters), updatedWeight});
161 assemblerCache.validWeightSum += updatedWeight;
162 }
164 std::move(assemblerCache));
165}
166} // end of anonymous namespace
167
169 const std::string& type,
170 const std::string& name,
171 const IInterface* parent)
172 : AthAlgTool(type, name, parent)
173{
174 declareInterface<IMaterialMixtureConvolution>(this);
175}
176
178
179StatusCode
181{
183 ATH_MSG_FATAL("Requested MaximumNumberOfComponents > "
185 return StatusCode::FAILURE;
186 }
187
188 m_materialEffects = std::make_unique<ElectronCombinedMaterialEffects>(
190 return StatusCode::SUCCESS;
191}
192
193/* ==========================================
194 Update with full material effects
195 ========================================== */
198 std::vector<GsfMaterial::Combined>& caches,
199 const Trk::MultiComponentState& multiComponentState,
200 const Trk::Layer& layer,
202{
203 const double updateFactor = 1.0;
204 Trk::MultiComponentState updatedMergedState = update(
205 caches, multiComponentState, layer, direction, updateFactor);
206
207 if (updatedMergedState.empty()) {
208 return {};
209 }
211 return updatedMergedState;
212}
213
214/* ==========================================
215 Update with pre-update material effects
216========================================== */
219 std::vector<GsfMaterial::Combined>& caches,
220 const Trk::MultiComponentState& multiComponentState,
221 const Trk::Layer& layer,
223{
224 const double updateFactor =
225 layer.preUpdateMaterialFactor(*multiComponentState.front().params, direction);
226
227 Trk::MultiComponentState updatedMergedState = update(caches,
228 multiComponentState,
229 layer,
230 direction,
231 updateFactor);
232 if (updatedMergedState.empty()) {
233 return {};
234 }
236 return updatedMergedState;
237}
238
239/* ==========================================
240 Update with post-update material effects
241 ========================================== */
244 std::vector<GsfMaterial::Combined>& caches,
245 const Trk::MultiComponentState& multiComponentState,
246 const Trk::Layer& layer,
248{
249 const double updateFactor = layer.postUpdateMaterialFactor(
250 *multiComponentState.front().params, direction);
251
252 Trk::MultiComponentState updatedMergedState =
253 update(caches, multiComponentState, layer, direction, updateFactor);
254
255 if (updatedMergedState.empty()) {
256 return {};
257 }
259 return updatedMergedState;
260}
261
264 std::vector<GsfMaterial::Combined>& caches,
265 const Trk::MultiComponentState& inputState,
266 const Trk::Layer& layer,
268 double updateFactor) const
269{
270
271 // Check the multi-component state is populated
272 if (inputState.empty()) {
273 return {};
274 }
275 if (updateFactor < 0.01) {
276 // Bail out as factor is too small to bother about
277 return {};
278 }
279 caches.resize(inputState.size());
280
281 // Fill cache and work out how many final components there should be
282 size_t numComponents(0);
283 for (size_t i(0); i < inputState.size(); ++i) {
284 const AmgSymMatrix(5)* measuredCov = inputState[i].params->covariance();
285 // If the momentum is too dont apply material effects
286 if (inputState[i].params->momentum().mag() <= 250. * Gaudi::Units::MeV) {
287 dummyCacheElement(caches[i]);
288 updateCacheElement(caches[i], 0, inputState[i].params->parameters(), measuredCov);
289 caches[i].weights[0] = inputState[i].weight;
290 numComponents += caches[i].numEntries;
291 continue;
292 }
293 // Get the material effects and store them in the cache
294 std::pair<const Trk::MaterialProperties*, double> matPropPair =
295 getMaterialProperties(inputState[i].params.get(), layer);
296
297 if (!matPropPair.first) {
298 dummyCacheElement(caches[i]);
299 updateCacheElement(caches[i], 0, inputState[i].params->parameters(), measuredCov);
300 caches[i].weights[0] = inputState[i].weight;
301 numComponents += caches[i].numEntries;
302 continue;
303 }
304 // Now we can compute/apply actual material effects
305 // Apply the update factor
306 matPropPair.second *= updateFactor;
307 m_materialEffects->compute(caches[i],
308 inputState[i],
309 *matPropPair.first,
310 matPropPair.second,
311 direction);
312
313 // Apply material effects to input state and store results in cache
314 // We have i material caches , one for each input state.
315 // Each cache has j entries. They correspond to each
316 // Gausian used to describe the Bethe Heitler.
317 for (size_t j(0); j < caches[i].numEntries; ++j) {
318 updateCacheElement(caches[i], j, inputState[i].params->parameters(), measuredCov);
319 // Adjust q/p of the (delta) Parameters
320 // make sure update is good.
321 if (!updateP(caches[i].parameters[j][Trk::qOverP],
322 caches[i].deltaPs[j])) {
323 ATH_MSG_ERROR("Cannot update state vector momentum!!!");
324 return {};
325 }
326 // Store component weight
327 caches[i].weights[j] *= inputState[i].weight;
328 // Ensure weight of component is not too small to save us from potential
329 // FPE's Value. Weights are double so the min of float should
330 // be small enough and should be handled
331 if (caches[i].weights[j] < std::numeric_limits<float>::min()) {
332 caches[i].weights[j] = std::numeric_limits<float>::min();
333 }
334 }
335 numComponents += caches[i].numEntries;
336 } // End of loop filling the cache
337
338 // Fill information for calculating which components to merge
339 // In addition scan all components for covariance matrices.
340 // If one component is missing its error matrix,
341 // component reduction is impossible.
342 //
343 bool componentWithoutMeasurement = false;
344 // keep track of the state component and material effects indices
345 // Effectively here we have M state X N Material effects
346 // MXN components.
347 std::vector<std::pair<size_t, size_t>> indices{};
348 indices.resize(numComponents);
349 GSFUtils::Component1DArray componentsArray(numComponents);
350 size_t k(0);
351 for (size_t i(0); i < inputState.size(); ++i) {
352 for (size_t j(0); j < caches[i].numEntries; ++j) {
353 const AmgSymMatrix(5)* measuredCov = inputState[i].params->covariance();
354 // Fill in infomation
355 const double cov =
356 measuredCov ? caches[i].covariances[j](Trk::qOverP, Trk::qOverP)
357 : -1.;
358 if (!measuredCov) {
359 componentWithoutMeasurement = true;
360 }
361 componentsArray[k].mean = caches[i].parameters[j][Trk::qOverP];
362 componentsArray[k].cov = cov;
363 componentsArray[k].invCov = cov > 0 ? 1. / cov : 1e10;
364 componentsArray[k].weight = caches[i].weights[j];
365 indices[k] = {i, j};
366 ++k;
367 }
368 }
369
370 // fallback if we have a component without measurement
371 if (componentWithoutMeasurement) {
372 auto* result = std::max_element(
373 componentsArray.begin(), componentsArray.end(),
374 [](const auto& a, const auto& b) { return a.weight < b.weight; });
375 auto index = std::distance(componentsArray.begin(), result);
376 const size_t stateIndex = indices[index].first;
377 const size_t materialIndex = indices[index].second;
378
379 AmgVector(5)& updatedStateVector = caches[stateIndex].parameters[materialIndex];
380 const AmgSymMatrix(5)* measuredCov = inputState[stateIndex].params->covariance();
381 std::optional<AmgSymMatrix(5)> updatedCovariance = std::nullopt;
382 if (measuredCov && caches[stateIndex].covariances.size() > materialIndex) {
383 updatedCovariance =
384 AmgSymMatrix(5)(caches[stateIndex].covariances[materialIndex]);
385 }
386 std::unique_ptr<Trk::TrackParameters> updatedTrackParameters =
387 inputState[stateIndex]
388 .params->associatedSurface()
389 .createUniqueTrackParameters(
390 updatedStateVector[Trk::loc1], updatedStateVector[Trk::loc2],
391 updatedStateVector[Trk::phi], updatedStateVector[Trk::theta],
392 updatedStateVector[Trk::qOverP], std::move(updatedCovariance));
393
394 Trk::ComponentParameters dummyCompParams = {
395 std::move(updatedTrackParameters), 1.};
396 Trk::MultiComponentState returnMultiState;
397 returnMultiState.push_back(std::move(dummyCompParams));
398 return returnMultiState;
399 }
400
401 //Create the state to rerurn accounting for any needed merges.
403 if (numComponents > m_maximumNumberOfComponents) {
404 merges = findMerges(std::move(componentsArray), m_maximumNumberOfComponents);
405 }
406 auto mergedState = createMergedState(merges, caches, indices, inputState);
407
408 if (mergedState.size() > m_maximumNumberOfComponents) {
409 ATH_MSG_ERROR("Merging failed, target size: " << m_maximumNumberOfComponents
410 << " final size: "
411 << mergedState.size());
412 }
413 return mergedState;
414}
415
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_FATAL(x,...)
Definition of component parameters for use in a mixture of many components. In this regime each track...
Class description for convolution of GSF material mixture.
#define AmgSymMatrix(dim)
#define AmgVector(rows)
Utilities to facilitate the calculation of the KL divergence/distance between components of the mixtu...
static Double_t a
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
virtual ~ElectronMaterialMixtureConvolution()
AlgTool initialise method.
virtual MultiComponentState preUpdate(std::vector< GsfMaterial::Combined > &, const MultiComponentState &, const Layer &, PropDirection direction=anyDirection) const override final
Convolution with post-measurement-update material properties.
virtual MultiComponentState update(std::vector< GsfMaterial::Combined > &, const MultiComponentState &, const Layer &, PropDirection direction=anyDirection) const override final
Convolution with pre-measurement-update material properties.
std::unique_ptr< ElectronCombinedMaterialEffects > m_materialEffects
virtual StatusCode initialize() override final
Convolution with full material properties.
ElectronMaterialMixtureConvolution(const std::string &, const std::string &, const IInterface *)
Destructor.
virtual MultiComponentState postUpdate(std::vector< GsfMaterial::Combined > &, const MultiComponentState &, const Layer &, PropDirection direction=anyDirection) const override final
The particle hypothesis we implement material effects for.
Base Class for a Detector Layer in the Tracking realm.
Definition Layer.h:72
Material with information about thickness of material.
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector3D & position() const
Access method for the position.
#define ATH_FLATTEN
constexpr int8_t maxNumberofStateComponents
The state is described by N Gaussian components The Beth Heitler Material effect are also described b...
AlignedDynArray< Component1D, GSFConstants::alignment > Component1DArray
std::vector< Merge > MergeArray
@ qOverP
perigee
@ layer
Definition HitInfo.h:79
MultiComponentState assembledState(MultiComponentStateAssembler::Cache &&cache)
Method to return the cached state object - it performs a reweighting before returning the object base...
void renormaliseState(MultiComponentState &, double norm=1)
Performing renormalisation of total state weighting to one.
Ensure that the ATLAS eigen extensions are properly loaded.
PropDirection
PropDirection, enum for direction of the propagation.
std::vector< ComponentParameters > MultiComponentState
const Amg::Vector3D & direction() const
Method to retrieve the direction at the Intersection.
@ theta
Definition ParamDefs.h:66
@ qOverP
perigee
Definition ParamDefs.h:67
@ loc2
generic first and second local coordinate
Definition ParamDefs.h:35
@ phi
Definition ParamDefs.h:75
@ loc1
Definition ParamDefs.h:34
std::pair< long int, long int > indices
ParametersBase< TrackParametersDim, Charged > TrackParameters
void Zero(TH1D *hin)
Definition generate.cxx:32
Definition index.py:1
iterator end() noexcept
iterator pointing to the past-the-end element
iterator begin() noexcept
iterator pointing to the first element
Helper struct for combined material effects, multicomponent description.
Definition GsfMaterial.h:49
std::array< AmgVector(5), GSFConstants::maxNumberofMatComponents > parameters
Definition GsfMaterial.h:56
std::array< AmgSymMatrix(5), GSFConstants::maxNumberofMatComponents > covariances
Definition GsfMaterial.h:60