ATLAS Offline Software
StaticEngine.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 ///////////////////////////////////////////////////////////////////
6 // StaticEngine.icc, (c) ATLAS Detector software
7 ///////////////////////////////////////////////////////////////////
8 
9 #include "TrkExInterfaces/INavigationEngine.h"
10 #include "TrkExInterfaces/IPropagationEngine.h"
11 #include "TrkExInterfaces/IMaterialEffectsEngine.h"
12 #include "TrkSurfaces/Surface.h"
13 #include "TrkGeometry/TrackingGeometry.h"
14 #include "TrkGeometry/TrackingVolume.h"
15 #include "TrkGeometry/Layer.h"
16 #include <iostream>
17 #include <iomanip>
18 
19 template <class T> Trk::ExtrapolationCode Trk::StaticEngine::extrapolateT(Trk::ExtrapolationCell<T>& eCell,
20  const Trk::Surface* sf,
21  Trk::PropDirection pDir,
22  const Trk::BoundaryCheck& bcheck) const
23 {
24  Trk::ExtrapolationCode eCode = Trk::ExtrapolationCode::InProgress;
25  // ---- [0] check the direct propagation exit
26  //
27  // obviously need a surface to exercise the fallback & need to be configured to do so
28  if (sf && eCell.checkConfigurationMode(Trk::ExtrapolationMode::Direct)){
29  EX_MSG_DEBUG(++eCell.navigationStep, "extrapolate", "", "direct extapolation in volume : " << eCell.leadVolume->volumeName());
30  // propagate to the surface, possible return codes are : SuccessPathLimit, SucessDestination, FailureDestination
31  eCode = m_propagationEngine->propagate(eCell,*sf,pDir,bcheck,eCell.destinationCurvilinear);
32  // eCode can be directly returned
33  return eCode;
34  }
35  EX_MSG_DEBUG(++eCell.navigationStep, "extrapolate", "", "extrapolation in static environment in volume : " << eCell.leadVolume->volumeName());
36  // evoke or finish the navigation initialization, possible return codes are:
37  // - InProgress : everything is fine, extrapolation in static volume is in progress
38  // - FailureNavigation : navigation setup could not be resolved, but reovery was not configured
39  // - Recovered : navigation setup could not be resolved, recovery by fallback to directly kicked in (and worked)
40  eCode = initNavigationT<T>(eCell,sf,pDir,bcheck);
41  CHECK_ECODE_CONTINUE(eCell, eCode);
42  // ----- [1] handle the ( leadLayer == endLayer )case :
43  //
44  // - this case does not need a layer to layer loop
45  if (sf && eCell.leadLayer == eCell.endLayer && eCell.initialVolume()){
46  // screen output for startLayer == endLayer
47  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "start and destination layer are identical -> jumping to final propagation.");
48  // set the leadLayerSurface to the parameters surface
49  eCell.leadLayerSurface = &(eCell.leadParameters->associatedSurface());
50  // resolve the layer, it is the final extrapolation
51  // - InProgress : layer resolving went without problem
52  // - SuccessPathLimit : path limit reached & configured to stop (rather unlikely within a layer)
53  // - SuccessMaterialLimit : material limit reached & configured to stop there
54  // if the lead layer is also the startLayer found by initialization -> no material handling
55  eCode = resolveLayerT<T>(eCell,
56  sf,
57  pDir,
58  bcheck,
59  eCell.leadLayer->hasSubStructure(eCell.checkConfigurationMode(Trk::ExtrapolationMode::CollectSensitive)),
60  (eCell.leadLayer == eCell.startLayer && eCell.leadVolume == eCell.startVolume),
61  true);
62  // Success triggers a return
63  CHECK_ECODE_SUCCESS_NODEST(eCell, eCode);
64  // extrapolation to destination was not successful
65  // - handle the return as configured (e.g. fallback)
66  return handleReturnT<T>(eCode, eCell, sf, pDir, bcheck);
67  }
68  // ----- [2] now do the layer-to-layer loop
69  //
70  // the volume returns the layers ordered by distance :
71  // - give potential start and end layer (latter only for the final volume)
72  // - start and end layer will be part of the loop
73  // - surface on approach is not yet resolved
74  const Trk::Layer* fLayer = eCell.finalVolumeReached() ? eCell.endLayer : 0;
75  auto layerIntersections = eCell.leadVolume->materialLayersOrdered(eCell.leadLayer, fLayer,
76  *eCell.leadParameters,
77  pDir,
78  true);
79 
80  EX_MSG_VERBOSE(eCell.navigationStep, "layer", "loop", "found " << layerIntersections.size() << " layers for the layer-to-layer loop.");
81  // layer-to-layer loop starts here
82  for (auto& layerCandidate : layerIntersections ) {
83  // assign the leadLayer
84  eCell.leadLayer = layerCandidate.object;
85  // screen output for layer-to-layer loop
86  EX_MSG_VERBOSE(eCell.navigationStep, "layer", "loop", "processing layer with index : " << eCell.leadLayer->layerIndex().value());
87  // resolve the approach surface situation
88  // - it is the approaching surface for all layers but the very first one (where it's the parameter surface)
89  eCell.leadLayerSurface = (eCell.leadLayer == eCell.startLayer) ? &(eCell.leadParameters->associatedSurface()) :
90  &(eCell.leadLayer->surfaceOnApproach(eCell.leadParameters->position(),
91  eCell.leadParameters->momentum(),
92  pDir,
93  true,
94  true));
95  // handle the layer, possible returns are :
96  // - InProgress : fine, whatever happened on the lead layer, may also be missed
97  // - SuccessWithPathLimit : propagation towards layer exceeded path limit
98  // - SuccessWithMaterialLimit : material interaction killed track
99  // - FailureDestination : destination was not hit appropriately
100  eCode = handleLayerT<T>(eCell, sf, pDir, bcheck);
101  EX_MSG_VERBOSE(eCell.navigationStep, "layer", layerCandidate.object->layerIndex().value(), "handleLayerT returned extrapolation code : " << eCode.toString());
102  // Possibilities are:
103  // - SuccessX -> return (via handleReturnT)
104  // - FailureX -> return (via handleReturnT that might evoke a fallback)
105  // - InProgess -> continue layer-to-layer loop
106  if (!eCode.inProgress()) return handleReturnT<T>(eCode, eCell, sf, pDir, bcheck);
107  }
108  // the layer 2 layer loop is done, the lead parameters are at the last valid option
109  // ----- [3] now resolve the boundary situation, call includes information wheather one is alreay at a boundary
110  //
111  // the navigaiton engine ca trigger different return codes
112  // - InProgress : fine, boundary surface has been found
113  // - SuccessWithPathLimit : propagation towards boundary surface exceeded path limit
114  // - FailureLoop/Navigation : problem in boundary resolving
115  eCode = m_navigationEngine->resolveBoundary(eCell, pDir);
116  // SuccessX and FailureX trigger a return
117  CHECK_ECODE_SUCCESS_NODEST(eCell, eCode);
118  // handle the return of the boudnary resolving
119  return handleReturnT<T>(eCode, eCell, sf, pDir, bcheck);
120 }
121 
122 template <class T> Trk::ExtrapolationCode Trk::StaticEngine::initNavigationT(Trk::ExtrapolationCell<T>& eCell,
123  const Trk::Surface* sf,
124  Trk::PropDirection pDir,
125  Trk::BoundaryCheck bcheck) const
126 {
127  // initialize the Navigation stream ----------------------------------------------------------------------------------------
128  //
129  // this is the global initialization, it only associated direct objects
130  // detailed navigation search needs to be done by the sub engines (since they know best)
131  EX_MSG_DEBUG(++eCell.navigationStep, "navigation", "", "complete for static environment.");
132  // [A] the initial volume
133  if (eCell.startVolume == eCell.leadVolume && eCell.startLayer) {
134  // - found the initial start layer through association
135  EX_MSG_VERBOSE(eCell.navigationStep, "navigation", "", "this is the initial volume, everything set up already.");
136  // assigning it to the leadLayer
137  eCell.leadLayer = eCell.startLayer;
138  // return progress
139  return Trk::ExtrapolationCode::InProgress;
140  }
141  // [B] any volume if we don't have a leadLayer
142  if (!eCell.leadLayer){
143  // - finding it through global search, never a boundary layer ... convention says that you update by exit
144  eCell.leadLayer = eCell.leadVolume->associatedLayer(eCell.leadParameters->position());
145  EX_MSG_VERBOSE(eCell.navigationStep, "navigation", "", "no start layer found yet, looking for it ..." << OH_CHECKFOUND(eCell.leadLayer) );
146  }
147  // [C] the final volume - everything's fine
148  if (eCell.leadVolume == eCell.endVolume && sf) {
149  if (eCell.endLayer) {
150  // the end layer had been found already by association
151  EX_MSG_VERBOSE(eCell.navigationStep, "navigation", "", "this is the final volume, everything set up already.");
152  return Trk::ExtrapolationCode::InProgress;
153  } else {
154  // make a straight line intersection
155  Trk::Intersection sfI = sf->straightLineIntersection(eCell.leadParameters->position(), pDir*eCell.leadParameters->momentum(), true);
156  // use this to find endVolume and endLayer
157  eCell.endLayer = eCell.leadVolume->associatedLayer(sfI.position);
158  // if you have a surface you need to require an end layer for the validation, otherwise you need to do a fallbac
159  return eCell.endLayer ? Trk::ExtrapolationCode::InProgress : handleReturnT<T>(Trk::ExtrapolationCode::FailureNavigation, eCell, sf, pDir, bcheck);
160  }
161  }
162  // return that you're in progress
163  return Trk::ExtrapolationCode::InProgress;
164 }
165 
166 /** handle the layer */
167 template <class T> Trk::ExtrapolationCode Trk::StaticEngine::handleLayerT(Trk::ExtrapolationCell<T>& eCell,
168  const Trk::Surface* sf,
169  Trk::PropDirection pDir,
170  Trk::BoundaryCheck bcheck) const
171 {
172  Trk::ExtrapolationCode eCode = Trk::ExtrapolationCode::InProgress;
173  EX_MSG_DEBUG(++eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "handle this layer" );
174  // layer has sub structure - this can be (and the layer will tell you):
175  // - sensitive surface which should be tried to hit
176  // - material sub structure to be resolved (independent of sensitive surface)
177  bool hasSubStructure = eCell.leadLayer->hasSubStructure(eCell.checkConfigurationMode(Trk::ExtrapolationMode::CollectSensitive));
178  // [A] layer is a pure navigation layer and has no sub structure -> skip it, but only if it is not the final layer
179  if (!hasSubStructure && !eCell.leadLayer->layerIndex().value() && eCell.leadLayer != eCell.endLayer){
180  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "layer is a navigation layer -> skipping it ...");
181  return Trk::ExtrapolationCode::InProgress;
182  }
183  // [B] layer resolving is necessary -> resolve it
184  // - (a) layer has sub structure - this can be (and the layer will tell you):
185  // - sensitive surface which should be tried to hit
186  // - material sub structure to be resolved (independent of sensitive surface)
187  // - (b) layer is start layer (can not be if there was a volume switch)
188  bool isStartLayer = eCell.initialVolume() && eCell.leadLayer->onLayer(*eCell.leadParameters);
189  // - (c) layer is destination layer
190  // - final propagation to the layer and update if necessary
191  bool isDestinationLayer = (sf && eCell.leadLayer == eCell.endLayer);
192  // sub structure, start and destination need resolving of the layer setp
193  if (hasSubStructure || isStartLayer || isDestinationLayer ){
194  // screen output for sub strucutred layer
195  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "has sub structure, is start layer, or destination layer -> resolving it ..." );
196  // resolve the layer, it handles all possible return types and gives them directly to extrapolateT<T>
197  // - InProgress : layer resolving went without problem
198  // - SuccessPathLimit : path limit reached & configured to stop
199  // - SuccessMaterialLimit : material limit reached & configured to stop there
200  // - SuccessDestination : destination reached & everything is fine
201  return resolveLayerT<T>(eCell,sf,pDir,bcheck,hasSubStructure,isStartLayer,isDestinationLayer);
202  }
203  // [C] layer is a material layer without sub structure but material -> pass through
204  // no resolving ob sub structure to be done, an intermediate layer to be crossed
205  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "intermediate layer without sub structure -> passing through ...");
206  // propagate to it, possible return codes ( with the default of finalPropagation = false):
207  // - SuccessPathLimit : propagation to layer exceeded path limit
208  // - InProgress : layer was hit successfuly, try to handle the material and sub structure, these are new parameters
209  // - Recovered : layer was not hit, so can be ignored in the layer to layer loop
210  eCode = m_propagationEngine->propagate(eCell,*eCell.leadLayerSurface,pDir,true,eCell.navigationCurvilinear);
211  CHECK_ECODE_SUCCESS_NODEST(eCell, eCode);
212  // record the passive parameters
213  if (eCode!=Trk::ExtrapolationCode::Recovered) eCell.stepParameters(eCell.leadParameters, Trk::ExtrapolationMode::CollectPassive);
214  // check if the layer was actually hit
215  if (eCode.inProgress()){
216  // successful layer hit
217  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "has been succesful hit, handling material update.");
218  // layer has no sub-structure : it is an intermediate layer that just needs pass-throgh
219  // return possbilities:
220  // - InProgress : material update performed or not (depending on material)
221  // - SuccessMaterialLimit : material limit reached & configured to stop there
222  eCode = m_materialEffectsEngine->handleMaterial(eCell,pDir,Trk::fullUpdate);
223  CHECK_ECODE_CONTINUE(eCell, eCode);
224  // return the progress eCode back to the extrapolateT
225  return eCode;
226  }
227  // hit or not hit : it's always in progress since we are in the layer to layer loop
228  return Trk::ExtrapolationCode::InProgress;
229 }
230 
231 
232 /** main sub structure layer handling */
233 template <class T> Trk::ExtrapolationCode Trk::StaticEngine::resolveLayerT(Trk::ExtrapolationCell<T>& eCell,
234  const Trk::Surface* sf,
235  Trk::PropDirection pDir,
236  Trk::BoundaryCheck bcheck,
237  bool hasSubStructure,
238  bool isStartLayer,
239  bool isDestinationLayer) const
240 {
241  Trk::ExtrapolationCode eCode = Trk::ExtrapolationCode::InProgress;
242  EX_MSG_DEBUG(++eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "resolve it with" << (hasSubStructure ? " " : "out ") << "sub structure"
243  << (isDestinationLayer ? " -> destination layer." : (isStartLayer ? " -> start layer." : "") ) );
244 
245  // cache the leadLayer - this is needed for the layer-to-layer loop not to be broken
246  const Trk::Layer* initialLayer = eCell.leadLayer;
247  // ----- [0] the start situation on the layer needs to be resolved:
248  // - either for sensitive parameters
249  // - or for material substructure
250  // [A] the layer is not the start layer and not the destination layer
251  // - the surfaceOnApproach() call should have sorted out that this is actually an approaching representation
252  // - the destination layer is excluded from the propagation because it can lead to punch-through to the other side of layers
253  if (!isStartLayer && !isDestinationLayer){
254  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "not the start layer (with sub structue), propagate to it.");
255  // propagate to the representing surface of this layer
256  // - InProgress : propagation to approaching surface worked - check material update
257  // - SuccessPathLimit : propagation to approaching surface reached the path limit
258  // - Recovered : layer was not hit, so can be ignored in the layer to layer loop
259  eCode = m_propagationEngine->propagate(eCell,*eCell.leadLayerSurface,pDir,true,eCell.sensitiveCurvilinear);
260  CHECK_ECODE_SUCCESS_NODEST(eCell,eCode);
261  // the extrapolation to the initial layer did not succeed - skip this layer in the layer-to-layer loop
262  if (eCode == Trk::ExtrapolationCode::Recovered) {
263  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "has not been hit, skipping it.");
264  return Trk::ExtrapolationCode::InProgress;
265  }
266  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "successfuly hit.");
267  // fill the corresponding parameters, the material effects updator can attach material to them
268  eCell.stepParameters(eCell.leadParameters, Trk::ExtrapolationMode::CollectPassive);
269  // the correct material layer needs to be assigned - in case of the approach surface not being hit, his can be the layer surface
270  if (eCell.leadLayerSurface->materialLayer() ||
271  (eCell.leadLayerSurface == &(eCell.leadLayer->surfaceRepresentation()) && eCell.leadLayer->layerMaterialProperties()) ){
272  // screen output for debugging
273  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "needs material update.");
274  // assign the right lead layer for the material update
275  if (eCell.leadLayerSurface->materialLayer())
276  eCell.leadLayer = eCell.leadLayerSurface->materialLayer();
277  // now handle the material (full update when passing approach surface), return codes are:
278  // - SuccessMaterialLimit : material limit reached, return back
279  // - InProgress : material update done or not (depending on the material description)
280  eCode = m_materialEffectsEngine->handleMaterial(eCell,pDir,Trk::fullUpdate);
281  CHECK_ECODE_CONTINUE(eCell, eCode);
282  }
283  } else if (isStartLayer) {
284  // [B] the layer is the start layer
285  // - let's check if a post update on the start surface has to be done
286  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "start layer (with sub structure), no propagation to be done.");
287  // the start surface could have a material layer attached
288  if (eCell.leadParameters->associatedSurface().materialLayer()){
289  eCell.leadLayer = eCell.leadParameters->associatedSurface().materialLayer();
290  // now handle the material (post update on start layer), return codes are:
291  // - SuccessMaterialLimit : material limit reached, return back
292  // - InProgress : material update done or not (depending on the material description)
293  eCode = m_materialEffectsEngine->handleMaterial(eCell,pDir,Trk::postUpdate);
294  CHECK_ECODE_CONTINUE(eCell, eCode);
295  // let's reset the lead layer
296  eCell.leadLayer = initialLayer;
297  }
298  }
299  // ----- [1] the sub structure of the layer needs to be resolved:
300  // resolve the substructure
301  std::vector<Trk::SurfaceIntersection> cSurfaces;
302  // this will give you the compatible surfaces of the layer : provided start and destination surface are excluded
303  // - surfaces without material are only provided if they are active and CollectSensitive is configured
304  // - surfaces with material are provided in order to make the necessary material update
305  size_t ncSurfaces = eCell.leadLayer->compatibleSurfaces(cSurfaces,
306  *eCell.leadParameters,
307  pDir,
308  bcheck,
309  !eCell.checkConfigurationMode(Trk::ExtrapolationMode::CollectSensitive),
310  (isStartLayer ? &(eCell.leadParameters->associatedSurface()) : eCell.leadLayerSurface),
311  (isDestinationLayer ? sf : 0) );
312  // some screen output for the sub structure
313  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "found " << ncSurfaces << " sub structrue surfaces to test.");
314  // check if you have to do something
315  if (ncSurfaces){
316  // now loop over the surfaces:
317  // the surfaces will be sorted
318  for (auto& csf : cSurfaces ) {
319  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "trying candidate surfaces with straight line path length " << csf.intersection.pathLength);
320  // propagate to the compatible surface, return types are
321  // - InProgress : propagation to compatible surface worked
322  // - Recovered : propagation to compatible surface did not work, leadParameters stay the same
323  // - SuccessPathLimit : propagation to compatible surface reached the path limit
324  eCode = m_propagationEngine->propagate(eCell,*(csf.object),pDir,true,eCell.sensitiveCurvilinear);
325  CHECK_ECODE_SUCCESS_NODEST(eCell,eCode);
326  // check if the propagation was successful
327  if (eCode.inProgress()){
328  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "successfully hit sub structure surface.");
329  // record the parameters as sensitive or passive depending on the surface
330  Trk::ExtrapolationMode::eMode emode = csf.object->isActive() ? Trk::ExtrapolationMode::CollectSensitive : Trk::ExtrapolationMode::CollectPassive;
331  // fill the corresponding parameters, the material effects updator can attach material to them
332  eCell.stepParameters(eCell.leadParameters, emode);
333  // check if the surface holds a material layer
334  // - yes : it is a sub surface that has a material layer attached
335  // - yes : it is any other layer for the material integration
336  if (csf.object->materialLayer() || ( csf.object->associatedLayer() && csf.object == &(csf.object->associatedLayer()->surfaceRepresentation()) ) ) {
337  // the resolved surface has material, set the leadLayer to
338  // - the materialLayer ( has higher priority than the associatedLayer() )
339  // - the associatedLayer ( it is the representing layer )
340  eCell.leadLayer = csf.object->materialLayer() ? csf.object->materialLayer() : csf.object->associatedLayer();
341  // now handle the material, return codes are:
342  // - SuccessMaterialLimit : material limit reached,return back
343  // - InProgress : material update done or not (depending on the material description)
344  eCode = m_materialEffectsEngine->handleMaterial(eCell,pDir,Trk::fullUpdate);
345  CHECK_ECODE_CONTINUE(eCell, eCode);
346  }
347  } else if (eCode== Trk::ExtrapolationCode::SuccessPathLimit) {
348  eCell.stepParameters(eCell.leadParameters, Trk::ExtrapolationMode::CollectPassive);
349  }
350  } // loop over test surfaces done
351  } // there are compatible surfaces
352 
353  // ----- [3] the destination situation on the layer needs to be resolved:
354  // the layer is a destination layer
355  // - the final propagation call is indepenent of whether sub structure was resolved or not
356  // - the eCell.leadParameters are at the last possible parameters
357  if (sf && isDestinationLayer) {
358  // [B] the layer is start and destination layer but has no sub-structure
359  // -> propagation to destination surface
360  // (a) the starting layer is the same layer :
361  // - neither preUpdate nore postUpdate to be done, this is old-style within-layer extrapolation
362  // - material will be taken into account either when the layer was reached from another layer
363  // or when the layer is left to another destination
364  // (b) the starting layer is not the same layer :
365  // - apply the preUpdate on the parameters whein they reached the surface
366  // Possible return types:
367  // - SuccessDestination : great, desintation surface hit - but post-update needs to be done
368  // - SuccessPathLimit : pathlimit was reached on the way to the destination surface
369  eCode = m_propagationEngine->propagate(eCell,*sf,pDir,false,eCell.destinationCurvilinear);
370  // check for success return path limit
371  CHECK_ECODE_SUCCESS_NODEST(eCell,eCode);
372  EX_MSG_VERBOSE(eCell.navigationStep, "layer", eCell.leadLayer->layerIndex().value(), "attempt to hit destination surface resulted in " << eCode.toString() );
373  // check for a potential preUpdate
374  // - in case teh destination surface has material and the surface was hit
375  if ( sf->materialLayer() && eCode.isSuccess() ){
376  // the resolved surface has material, set the leadLayer to
377  eCell.leadLayer = sf->materialLayer();
378  // finally do the material update
379  // - this is the final call - still check for SuccessMaterialLimit
380  // the material effects updator usually returns inProgress, this needs to be ingored
381  m_materialEffectsEngine->handleMaterial(eCell,pDir,Trk::preUpdate);
382  // check if success was triggered through path limit reached on the way to the layer
383  CHECK_ECODE_SUCCESS(eCell,eCode);
384  }
385  // return what you have handleLayerT or extrapolateT will resolve that
386  return eCode;
387  }
388  // reset the lead layer to ensure the layer-to-layer loop
389  eCell.leadLayer = initialLayer;
390  // return the code:
391  // - if it came until here, return InProgress to not break the layer-to-layer loop
392  return Trk::ExtrapolationCode::InProgress;
393 }
394 
395 /** handle the failure - as configured */
396 template <class T> Trk::ExtrapolationCode Trk::StaticEngine::handleReturnT(Trk::ExtrapolationCode eCode,
397  Trk::ExtrapolationCell<T>& eCell,
398  const Trk::Surface* sf,
399  Trk::PropDirection pDir,
400  Trk::BoundaryCheck bcheck) const
401 {
402  EX_MSG_DEBUG(++eCell.navigationStep, "return", "", "handleReturnT with code " << eCode.toString() << " called." );
403  if (eCode.isSuccessOrRecovered() || eCode.inProgress() ){
404  EX_MSG_VERBOSE(eCell.navigationStep, "return", "", "leaving static extrapolator successfully with code " << eCode.toString());
405  return eCode;
406  }
407  EX_MSG_VERBOSE(eCell.navigationStep, "return", "", "failure detected as " << eCode.toString() << " - checking fallback configuration.");
408  // obviously we need a surface to exercise the fallback
409  if (sf && !eCell.checkConfigurationMode(Trk::ExtrapolationMode::AvoidFallback)){
410  EX_MSG_VERBOSE(eCell.navigationStep, "return", "", "fallback configured. Trying to hit destination surface from last valid parameters.");
411  // check if you hit the surface, could still be stopped by PathLimit, but would also count as recovered
412  eCode = m_propagationEngine->propagate(eCell,*sf,pDir,bcheck,eCell.destinationCurvilinear);
413  }
414 
415  return eCode;
416 }
417 
418