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