2098 {
2099 double maxPath = cache.m_maxPath;
2100 double*
pos = &
P[0];
2101 double*
dir = &
P[3];
2102 double dDir[3] = {0., 0., 0.};
2103
2104 double previousDistance = 0.;
2105 double distanceStepped = 0.;
2106 double BG1[12] = {0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.};
2107
2108 bool firstStep = true;
2111 cache.m_timeStep = 0.;
2114
2115
2116 double helpSoft = 1.;
2117
2118
2119 int restartLimit = 10;
2120
2123
2124
2125 cache.m_binMat = nullptr;
2126 if (cache.m_trackingVolume && cache.m_trackingVolume->isAlignable()) {
2127 const Trk::AlignableTrackingVolume* aliTV =
2128 static_cast<const Trk::AlignableTrackingVolume*>(cache.m_trackingVolume);
2130 }
2131
2132
2133
2134
2135
2136
2137 double tol = 0.001;
2138 solutions.clear();
2139 double distanceToTarget = propDir * maxPath;
2140 cache.m_currentDist.resize(sfs.size());
2141
2142 int nextSf = sfs.size();
2143 int nextSfCand = nextSf;
2144 std::vector<DestSurf>::iterator sIter = sfs.begin();
2145 std::vector<DestSurf>::iterator sBeg = sfs.begin();
2146 unsigned int numSf = 0;
2147 unsigned int iCurr = 0;
2148 int startSf = -99;
2149 for (; sIter != sfs.end(); ++sIter) {
2150 Trk::DistanceSolution distSol = (*sIter).first->straightLineDistanceEstimate(position, direction0);
2151 double distEst = -propDir * maxPath;
2152 double dist1Est = distEst;
2154 distEst = distSol.
first();
2155 dist1Est = distSol.
first();
2157 (std::abs(distEst) < tol || (propDir * distEst < -tol && propDir * distSol.
second() > tol)))
2158 distEst = distSol.
second();
2159 }
2160
2161
2162
2163 if (distEst * propDir > -tol) {
2165 cache.m_currentDist[iCurr] = std::pair<int, std::pair<double, double>>(
2166 0, std::pair<double, double>(distEst, distSol.
currentDistance(
true)));
2167 } else {
2168 cache.m_currentDist[iCurr] = std::pair<int, std::pair<double, double>>(
2169 1, std::pair<double, double>(distEst, distSol.
currentDistance(
true)));
2170 }
2171 if (tol < propDir * distEst && propDir * distEst < propDir * distanceToTarget) {
2172 distanceToTarget = distEst;
2173 nextSf = iCurr;
2174 }
2175 ++numSf;
2176 } else {
2177
2178 cache.m_currentDist[iCurr] = std::pair<int, std::pair<double, double>>(
2180 }
2181 if (std::abs(dist1Est) < tol)
2182 startSf = (
int)iCurr;
2183 ++iCurr;
2184 }
2185
2186 if (distanceToTarget == maxPath || numSf == 0)
2187 return false;
2188
2189
2190 std::vector<std::pair<int, std::pair<double, double>>>::iterator vsBeg = cache.m_currentDist.begin();
2191 std::vector<std::pair<int, std::pair<double, double>>>::iterator vsEnd = cache.m_currentDist.end();
2192 const int num_vs_dist = cache.m_currentDist.size();
2193
2194
2196 double absPath = 0.;
2197 distanceToTarget > 100. ?
h = 100. : distanceToTarget < -100. ?
h = -100. :
h = distanceToTarget;
2198
2200
2201 if (cache.m_binMat) {
2202 const Trk::BinUtility* lbu = cache.m_binMat->layerBinUtility(position);
2203 if (lbu) {
2204 cache.m_currentLayerBin = cache.m_binMat->layerBin(position);
2205 binIDMat = cache.m_binMat->material(position);
2206 std::pair<size_t, float> dist2next = lbu->
distanceToNext(position, propDir * direction0);
2207 if (dist2next.first < lbu->
bins() && std::abs(dist2next.second) > 1. &&
2208 std::abs(dist2next.second) < std::abs(h)) {
2209 h = dist2next.second * propDir;
2210 }
2211 if (binIDMat)
2212 cache.m_material = binIDMat->first.get();
2213 }
2214 }
2215
2216
2217
2218
2219
2220 double distanceTolerance = std::min(std::max(std::abs(distanceToTarget) * cache.m_tolerance, 1e-6), 1e-2);
2221
2222
2223 if (cache.m_brem) {
2224 mom = std::abs(1. /
P[6]);
2226 }
2227
2228 while (numSf > 0 && (std::abs(distanceToTarget) > distanceTolerance ||
2229 std::abs(path + distanceStepped) < tol)) {
2230
2231 if (!rungeKuttaStep(cache, errorPropagation, h,
P, dDir, BG1, firstStep, distanceStepped)) {
2232
2233 if (cache.m_brem) {
2237 m_simMatUpdator->recordBremPhoton(cache.m_timeIn + cache.m_timeOfFlight + cache.m_timeStep,
2239 cache.m_particle);
2240
2241 for (
int i = 0;
i < 3; ++
i)
2242 P[3 + i] = direction[i];
2243
2244 }
2245 }
2246
2248
2249 mom = std::abs(1. /
P[6]);
2250 beta =
mom / std::sqrt(mom * mom + cache.m_particleMass * cache.m_particleMass);
2251 cache.m_timeStep += distanceStepped /
beta / Gaudi::Units::c_light;
2252
2253 if (std::abs(distanceStepped) > 0.001) {
2254 cache.m_sigmaIoni = cache.m_sigmaIoni - cache.m_kazL *
log(std::abs(distanceStepped));
2255 }
2256
2257 if (errorPropagation && cache.m_straggling) {
2258
2259 double sigTot2 = cache.m_sigmaIoni * cache.m_sigmaIoni + cache.m_sigmaRad * cache.m_sigmaRad;
2260
2262 cache.m_stragglingVariance += sigTot2 / (bp2 * bp2) * distanceStepped * distanceStepped;
2263 }
2264 if (cache.m_matstates || errorPropagation) {
2265 cache.m_combinedEloss.update(
2266 cache.m_delIoni * distanceStepped, cache.m_sigmaIoni * std::abs(distanceStepped),
2267 cache.m_delRad * distanceStepped, cache.m_sigmaRad * std::abs(distanceStepped), cache.m_MPV);
2268 }
2269 if (cache.m_material && cache.m_material->x0() != 0.) {
2270 cache.m_combinedThickness += propDir * distanceStepped / cache.m_material->x0();
2271 }
2272
2273 return false;
2274 }
2276 absPath += std::abs(distanceStepped);
2277
2278
2279 mom = std::abs(1. /
P[6]);
2280 beta =
mom / std::sqrt(mom * mom + cache.m_particleMass * cache.m_particleMass);
2281 cache.m_timeStep += distanceStepped /
beta / Gaudi::Units::c_light;
2282
2283 if (std::abs(distanceStepped) > 0.001)
2284 cache.m_sigmaIoni = cache.m_sigmaIoni - cache.m_kazL *
log(std::abs(distanceStepped));
2285
2286 if (errorPropagation && cache.m_straggling) {
2287
2288 double sigTot2 = cache.m_sigmaIoni * cache.m_sigmaIoni + cache.m_sigmaRad * cache.m_sigmaRad;
2289
2291 cache.m_stragglingVariance += sigTot2 / (bp2 * bp2) * distanceStepped * distanceStepped;
2292 }
2293 if (cache.m_matstates || errorPropagation) {
2294 cache.m_combinedEloss.update(
2295 cache.m_delIoni * distanceStepped, cache.m_sigmaIoni * std::abs(distanceStepped),
2296 cache.m_delRad * distanceStepped, cache.m_sigmaRad * std::abs(distanceStepped), cache.m_MPV);
2297 }
2298 if (cache.m_material && cache.m_material->x0() != 0.) {
2299 cache.m_combinedThickness += propDir * distanceStepped / cache.m_material->x0();
2300 }
2301
2302 if (absPath > maxPath)
2303 return false;
2304
2305
2306 if (cache.m_propagateWithPathLimit > 0 && cache.m_pathLimit <= path) {
2307 ++cache.m_propagateWithPathLimit;
2308 return true;
2309 }
2310
2311 bool restart = false;
2312
2313 if (propDir * path < -tol || absPath - std::abs(path) > 10.) {
2314 helpSoft = std::abs(path) / absPath > 0.5 ? std::abs(path) / absPath : 0.5;
2315 }
2316
2319
2320
2321 float distanceToNextBin =
h;
2322 if (cache.m_binMat) {
2323 const Trk::BinUtility* lbu = cache.m_binMat->layerBinUtility(position);
2324 if (lbu) {
2325 size_t layerBin = cache.m_binMat->layerBin(position);
2327 std::pair<size_t, float> dist2next = lbu->
distanceToNext(position, propDir * direction);
2328 distanceToNextBin = dist2next.second;
2329 if (layerBin != cache.m_currentLayerBin) {
2330
2331 std::pair<size_t, float> dist2previous = lbu->
distanceToNext(position, -propDir * direction);
2332 float stepOver = dist2previous.second;
2333 double localp[5];
2335 auto cPar = std::make_unique<Trk::CurvilinearParameters>(
Amg::Vector3D(
P[0],
P[1],
P[2]), localp[2],
2336 localp[3], localp[4]);
2337 if (cache.m_identifiedParameters) {
2338 if (binIDMat && binIDMat->second > 0 && !iMat) {
2339 cache.m_identifiedParameters->emplace_back(cPar->clone(), -binIDMat->second);
2340 } else if (binIDMat && binIDMat->second > 0 &&
2341 (iMat->second == 0 || iMat->second == binIDMat->second)) {
2342 cache.m_identifiedParameters->emplace_back(cPar->clone(), -binIDMat->second);
2343 } else if (iMat && iMat->second > 0) {
2344 cache.m_identifiedParameters->emplace_back(cPar->clone(), iMat->second);
2345 }
2346 }
2347 if (cache.m_hitVector) {
2348 double hitTiming = cache.m_timeIn + cache.m_timeOfFlight + cache.m_timeStep;
2349 if (binIDMat && binIDMat->second > 0 && !iMat) {
2350 cache.m_hitVector->emplace_back(cPar->uniqueClone(), hitTiming, -binIDMat->second, 0.);
2351 } else if (binIDMat && binIDMat->second > 0 &&
2352 (iMat->second == 0 || iMat->second == binIDMat->second)) {
2353 cache.m_hitVector->emplace_back(cPar->uniqueClone(), hitTiming, -binIDMat->second, 0.);
2354 } else if (iMat && iMat->second > 0) {
2355 cache.m_hitVector->emplace_back(cPar->uniqueClone(), hitTiming, iMat->second, 0.);
2356 }
2357 }
2358
2359 cache.m_currentLayerBin = layerBin;
2360 binIDMat = iMat;
2361 if (binIDMat) {
2362
2363
2364
2365
2366
2367 if (cache.m_material) {
2368 updateMaterialEffects(cache, mom,
sin(direction.theta()), sumPath + path - stepOver);
2369 }
2370 cache.m_material = binIDMat->first.get();
2371 }
2372
2373 if (distanceToNextBin < h) {
2374 Amg::Vector3D probe = position + (distanceToNextBin +
h) * propDir * direction;
2375 std::pair<size_t, float> d2n = lbu->
distanceToNext(probe, propDir * direction);
2376 distanceToNextBin += d2n.second +
h;
2377 }
2378 }
else if (dist2next.first < lbu->
bins() && std::abs(distanceToNextBin) < 0.01 &&
2379 h > 0.01) {
2380 double localp[5];
2382 auto cPar = std::make_unique<Trk::CurvilinearParameters>(
Amg::Vector3D(
P[0],
P[1],
P[2]), localp[2],
2383 localp[3], localp[4]);
2384
2386
2387 Amg::Vector3D probe = position + (distanceToNextBin + 0.01) * propDir * direction.normalized();
2388 nextMat = cache.m_binMat->material(probe);
2389
2390 if (cache.m_identifiedParameters) {
2391 if (binIDMat && binIDMat->second > 0 && !nextMat) {
2392 cache.m_identifiedParameters->emplace_back(cPar->clone(), -binIDMat->second);
2393 } else if (binIDMat && binIDMat->second > 0 &&
2394 (nextMat->second == 0 || nextMat->second == binIDMat->second)) {
2395
2396 cache.m_identifiedParameters->emplace_back(cPar->clone(), -binIDMat->second);
2397 } else if (nextMat && nextMat->second > 0) {
2398 cache.m_identifiedParameters->emplace_back(cPar->clone(), nextMat->second);
2399 }
2400 }
2401 if (cache.m_hitVector) {
2402 double hitTiming = cache.m_timeIn + cache.m_timeOfFlight + cache.m_timeStep;
2403 if (binIDMat && binIDMat->second > 0 && !nextMat) {
2404 cache.m_hitVector->emplace_back(cPar->uniqueClone(), hitTiming, -binIDMat->second, 0.);
2405 } else if (binIDMat && binIDMat->second > 0 &&
2406 (nextMat->second == 0 ||
2407 nextMat->second == binIDMat->second)) {
2408 cache.m_hitVector->emplace_back(cPar->uniqueClone(), hitTiming, -binIDMat->second, 0.);
2409 } else if (nextMat && nextMat->second > 0) {
2410 cache.m_hitVector->emplace_back(cPar->uniqueClone(), hitTiming, nextMat->second, 0.);
2411 }
2412 }
2413
2414 cache.m_currentLayerBin = dist2next.first;
2415 if (binIDMat != nextMat) {
2416 binIDMat = nextMat;
2417 if (binIDMat) {
2418 assert(cache.m_material);
2419 updateMaterialEffects(cache, mom,
sin(direction.theta()), sumPath + path);
2420 cache.m_material = binIDMat->first.get();
2421 }
2422 }
2423
2424 std::pair<size_t, float> d2n = lbu->
distanceToNext(probe, propDir * direction.normalized());
2425 distanceToNextBin += d2n.second + 0.01;
2426 }
2427
2428
2429 }
2430 }
2431
2432
2433 bool flipDirection = false;
2434 numSf = 0;
2435 nextSfCand = nextSf;
2436 double dev = direction0.dot(direction);
2437 std::vector<DestSurf>::iterator sIter = sBeg;
2438 std::vector<std::pair<int, std::pair<double, double>>>::iterator vsIter = vsBeg;
2440 int numRestart = 0;
2441
2442 if (cache.m_brem) {
2444
2445
2446 m_simMatUpdator->recordBremPhoton(cache.m_timeIn + cache.m_timeOfFlight + cache.m_timeStep, mom,
2447 cache.m_bremMom, position, direction, cache.m_particle);
2448 cache.m_bremEmitThreshold = 0.;
2449 }
2450 if (mom < cache.m_bremSampleThreshold)
2451 sampleBrem(cache, cache.m_bremSampleThreshold);
2452 }
2453
2454 for (; vsIter != vsEnd; ++vsIter) {
2455 if (restart) {
2456 ++numRestart;
2457 if (numRestart > restartLimit)
2458 return false;
2459
2460 vsIter = vsBeg;
2462 sIter = sBeg;
2463 distanceToTarget = propDir * maxPath;
2464 nextSf = -1;
2465 nextSfCand = -1;
2466 restart = false;
2467 helpSoft = 1.;
2468 }
2469 if ((*vsIter).first != -1 &&
2470 (ic == nextSf || (*vsIter).first == 1 || nextSf < 0 || std::abs((*vsIter).second.first) < 500. ||
2471 std::abs(path) > 0.5 * std::abs((*vsIter).second.second))) {
2472 previousDistance = (*vsIter).second.first;
2473 Trk::DistanceSolution distSol =
2474 (*sIter).
first->straightLineDistanceEstimate(position, propDir * direction);
2475 double distanceEst = -propDir * maxPath;
2477 distanceEst = distSol.
first();
2479 std::abs(distSol.
first() * propDir + distanceStepped - previousDistance) >
2480 std::abs(distSol.
second() * propDir + distanceStepped - previousDistance)) {
2481 distanceEst = distSol.
second();
2482 }
2483
2484
2485
2486
2487
2488 if (ic == startSf && distanceEst < 0 && distSol.
first() > 0)
2489 distanceEst = distSol.
first();
2490 }
2491
2492 if (ic == nextSf && std::abs(distanceEst) < tol && std::abs(path) < tol) {
2493 (*vsIter).first = -1;
2494 vsIter = vsBeg;
2495 restart = true;
2496 distanceToTarget = maxPath;
2497 nextSf = -1;
2498 continue;
2499 }
2500
2501
2502
2503
2504 if ((*vsIter).second.first * propDir * distanceEst < 0. &&
2505 std::abs(distanceEst) > distanceTolerance) {
2506
2507
2509 std::abs((*vsIter).second.second) < tol ||
2511 if (ic == nextSf) {
2512 ((*vsIter).first)++;
2513
2514 if ((*vsIter).first > 3) {
2515 helpSoft = fmax(0.05, 1. - 0.05 * (*vsIter).first);
2516 if ((*vsIter).first > 20)
2517 helpSoft = 1. / (*vsIter).first;
2518 }
2519
2520 if ((*vsIter).first > 50 && h * propDir > 0) {
2521
2522 (*vsIter).first = -1;
2523 vsIter = vsBeg;
2524 restart = true;
2525 continue;
2526 }
2527 if ((*vsIter).first != -1)
2528 flipDirection = true;
2529 } else if (std::abs((*vsIter).second.second) > tol &&
2531
2532 if (ic > nextSf && nextSf != -1) {
2533 if (propDir * distanceEst < (cache.m_currentDist.at(nextSf)).second.first - tol) {
2534 if ((*vsIter).first != -1) {
2535 ((*vsIter).first)++;
2536 flipDirection = true;
2538 }
2539 }
2540 } else if (distanceToTarget >
2541 0.) {
2542 if ((*vsIter).first != -1) {
2543 ((*vsIter).first)++;
2544 flipDirection = true;
2546 }
2547 }
2548 }
2549 } else if (ic == nextSf) {
2550 vsIter = vsBeg;
2551 restart = true;
2552 continue;
2553 }
2554 }
2555
2556
2557 (*vsIter).second.first = propDir * distanceEst;
2559
2560
2561
2562
2563 if ((*vsIter).first != -1 && (distanceEst > 0. || ic == nextSf)) {
2564 ++numSf;
2565 if (distanceEst < std::abs(distanceToTarget)) {
2566 distanceToTarget = propDir * distanceEst;
2568 }
2569 }
2570 } else if (std::abs(path) > std::abs((*vsIter).second.second) || dev < 0.985 ||
2571 nextSf < 0) {
2572 Trk::DistanceSolution distSol =
2573 (*sIter).
first->straightLineDistanceEstimate(position, propDir * direction);
2574 double distanceEst = -propDir * maxPath;
2576 distanceEst = distSol.
first();
2577 }
2578
2579 (*vsIter).second.first = propDir * distanceEst;
2581
2582 if (distanceEst > tol && distanceEst < maxPath) {
2583 (*vsIter).first = 0;
2584 } else {
2586 }
2587 if ((*vsIter).first != -1 && distanceEst > 0.) {
2588 ++numSf;
2589 if (distanceEst < std::abs(distanceToTarget)) {
2590 distanceToTarget = propDir * distanceEst;
2592 }
2593 }
2594 }
2595
2596
2597
2598 if (std::abs(distanceToTarget) <= distanceTolerance && path * propDir < distanceTolerance) {
2599 (*vsIter).first = -1;
2600 vsIter = vsBeg;
2601 restart = true;
2602 continue;
2603 }
2604 ++sIter;
2606 }
2607
2608 if (nextSf < 0 && nextSfCand < 0)
2609 return false;
2610
2611 if (flipDirection) {
2612
2613 if (nextSf < 0 || nextSf >= num_vs_dist)
2614 return false;
2615 distanceToTarget = (*(vsBeg + nextSf)).
second.first;
2617 } else if (nextSfCand != nextSf) {
2618 nextSf = nextSfCand;
2619
2620 if (nextSf < 0 || nextSf >= num_vs_dist)
2621 return false;
2622 if (cache.m_currentDist[nextSf].first < 3)
2623 helpSoft = 1.;
2624 }
2625
2626
2627 if (std::abs(h) > std::abs(distanceToTarget))
2628 h = distanceToTarget;
2629
2630
2631 if (cache.m_binMat && std::abs(h) > std::abs(distanceToNextBin) + 0.001) {
2632 if (distanceToNextBin > 0) {
2633 h = distanceToNextBin * propDir;
2634 }
2635 }
2636
2637 if (helpSoft < 1.)
2639
2640
2641 if (cache.m_propagateWithPathLimit > 0 && h > cache.m_pathLimit)
2642 h = cache.m_pathLimit + tol;
2643
2644
2645 if (std::abs(path) > maxPath)
2646 return false;
2647
2648 if (steps++ > cache.m_maxSteps)
2649 return false;
2650 }
2651
2652 if (!numSf)
2653 return false;
2654
2655
2657
2658
2659 mom = std::abs(1. /
P[6]);
2660 beta =
mom / std::sqrt(mom * mom + cache.m_particleMass * cache.m_particleMass);
2661 cache.m_timeStep += distanceToTarget /
beta / Gaudi::Units::c_light;
2662
2663
2664 pos[0] =
pos[0] + distanceToTarget * (
dir[0] + 0.5 * distanceToTarget *
dDir[0]);
2665 pos[1] =
pos[1] + distanceToTarget * (
dir[1] + 0.5 * distanceToTarget *
dDir[1]);
2666 pos[2] =
pos[2] + distanceToTarget * (
dir[2] + 0.5 * distanceToTarget *
dDir[2]);
2667
2668
2669 dir[0] =
dir[0] + distanceToTarget *
dDir[0];
2670 dir[1] =
dir[1] + distanceToTarget *
dDir[1];
2671 dir[2] =
dir[2] + distanceToTarget *
dDir[2];
2672
2673
2674 double norm = 1. / std::sqrt(dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]);
2681
2682
2683 std::vector<std::pair<int, std::pair<double, double>>>::iterator vsIter = vsBeg;
2684
2686 for (; vsIter != vsEnd; ++vsIter) {
2687 if ((*vsIter).first != -1 && propDir * (*vsIter).second.first >= propDir * distanceToTarget - tol &&
2688 propDir * (*vsIter).second.first < 0.01 && index != nextSf) {
2689 solutions.push_back(index);
2690 }
2691 if (index == nextSf)
2692 solutions.push_back(index);
2694 }
2695
2696 return true;
2697}
const BinnedMaterial * binnedMaterial() const
access to binned material
size_t bins(size_t ba=0) const
Number of bins.
std::pair< size_t, float > distanceToNext(const Amg::Vector3D &position, const Amg::Vector3D &direction, size_t ba=0) const
Distance estimate to next bin.
double second() const
Distance to second intersection solution along direction (for a cylinder surface)
double currentDistance(bool signedDist=false) const
Current distance to surface (spatial), signed (along/opposite to surface normal) if input argument tr...
int numberOfSolutions() const
Number of intersection solutions.
bool signedDistance() const
This method indicates availability of signed current distance (false for Perigee and StraighLineSurfa...
double first() const
Distance to first intersection solution along direction.
DoubleProperty m_momentumCutOff
void sampleBrem(Cache &cache, double mom) const
std::pair< std::shared_ptr< Material >, int > IdentifiedMaterial