/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
FastSimulation/SimplifiedGeometryPropagator/src/HelixTrajectory.cc
212 строк
9 KB
Cms Build
Clang-Format
16 май 2019, 15:48
16 май 2019, 15:48
12a0cf0
Код
Авторство
О чём код?
#include "FastSimulation/SimplifiedGeometryPropagator/interface/HelixTrajectory.h" #include "FastSimulation/SimplifiedGeometryPropagator/interface/StraightTrajectory.h" #include "FastSimulation/SimplifiedGeometryPropagator/interface/BarrelSimplifiedGeometry.h" #include "FastSimulation/SimplifiedGeometryPropagator/interface/ForwardSimplifiedGeometry.h" #include "FastSimulation/SimplifiedGeometryPropagator/interface/Particle.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" #include "FastSimulation/SimplifiedGeometryPropagator/interface/Constants.h" #include <cmath> // helix phi definition // ranges from 0 to 2PI // 0 corresponds to the positive x direction // phi increases counterclockwise fastsim::HelixTrajectory::HelixTrajectory(const fastsim::Particle& particle, double magneticFieldZ) : Trajectory(particle) // exact: r = gamma*beta*m_0*c / (q*e*B) = p_T / (q * e * B) // momentum in units of GeV/c: r = p_T * 10^9 / (c * q * B) // in cmssw units: r = p_T / (c * 10^-4 * q * B) , radius_( std::abs(momentum_.Pt() / (fastsim::Constants::speedOfLight * 1e-4 * particle.charge() * magneticFieldZ))), phi_(std::atan(momentum_.Py() / momentum_.Px()) + (momentum_.Px() * particle.charge() < 0 ? 3. * M_PI / 2. : M_PI / 2.)) // maybe consider (for -pi/2<x<pi/2) // cos(atan(x)) = 1 / sqrt(x^2+1) // -> cos(atan(x) + pi/2) = - x / sqrt(x^2+1) // -> cos(atan(x) +3*pi/2) = + x / sqrt(x^2+1) // sin(atan(x)) = x / sqrt(x^2+1) // -> sin(atan(x) + pi/2) = + 1 / sqrt(x^2+1) // -> sin(atan(x) +3*pi/2) = - 1 / sqrt(x^2+1) , centerX_(position_.X() - radius_ * (momentum_.Py() / momentum_.Px()) / std::sqrt((momentum_.Py() / momentum_.Px()) * (momentum_.Py() / momentum_.Px()) + 1) * (momentum_.Px() * particle.charge() < 0 ? 1. : -1.)), centerY_(position_.Y() - radius_ * 1 / std::sqrt((momentum_.Py() / momentum_.Px()) * (momentum_.Py() / momentum_.Px()) + 1) * (momentum_.Px() * particle.charge() < 0 ? -1. : 1.)) //, centerX_(position_.X() - radius_*std::cos(phi_)) //, centerY_(position_.Y() - radius_*std::sin(phi_)) , centerR_(std::sqrt(centerX_ * centerX_ + centerY_ * centerY_)), minR_(std::abs(centerR_ - radius_)), maxR_(centerR_ + radius_) // omega = q * e * B / (gamma * m) = q * e *B / (E / c^2) = q * e * B * c^2 / E // omega: negative for negative q -> seems to be what we want. // energy in units of GeV: omega = q * B * c^2 / (E * 10^9) // in cmssw units: omega[1/ns] = q * B * c^2 * 10^-4 / E , phiSpeed_(-particle.charge() * magneticFieldZ * fastsim::Constants::speedOfLight * fastsim::Constants::speedOfLight * 1e-4 / momentum_.E()) { ; } bool fastsim::HelixTrajectory::crosses(const BarrelSimplifiedGeometry& layer) const { return (minR_ < layer.getRadius() && maxR_ > layer.getRadius()); } double fastsim::HelixTrajectory::nextCrossingTimeC(const BarrelSimplifiedGeometry& layer, bool onLayer) const { if (!crosses(layer)) return -1; // solve the following equation for sin(phi) // (x^2 + y^2 = R_L^2) (1) the layer // x = x_c + R_H*cos(phi) (2) the helix in the xy plane // y = y_c + R_H*sin(phi) (3) the helix in the xy plane // with // R_L: the radius of the layer // x_c,y_c the center of the helix in xy plane // R_H, the radius of the helix // phi, the phase of the helix // // substitute (2) and (3) in (1) // => // x_c^2 + 2*x_c*R_H*cos(phi) + R_H^2*cos^2(phi) // + y_c^2 + 2*y_c*R_H*sin(phi) + R_H^2*sin^2(phi) // = R_L^2 // => // (x_c^2 + y_c^2 + R_H^2 - R_L^2) + (2*y_c*R_H)*sin(phi) = -(2*x_c*R_H)*cos(phi) // // rewrite // E + F *sin(phi) = G *cos(phi) // => // E^2 + 2*E*F*sin(phi) + F^2*sin^2(phi) = G^2*(1-sin^2(phi)) // rearrange // sin^2(phi)*(F^2 + G^2) + sin(phi)*(2*E*F) + (E^2 - G^2) = 0 // // rewrite // sin^2(phi)* a + sin(phi)* b + c = 0 // => sin(phi) = (-b +/- sqrt(b^2 - 4*ac)) / (2*a) // with // a = F^2 + G^2 // b = 2*E*F // c = E^2 - G^2 double E = centerX_ * centerX_ + centerY_ * centerY_ + radius_ * radius_ - layer.getRadius() * layer.getRadius(); double F = 2 * centerY_ * radius_; double G = 2 * centerX_ * radius_; double a = F * F + G * G; double b = 2 * E * F; double c = E * E - G * G; double delta = b * b - 4 * a * c; // case of no solution if (delta < 0) { // Should not be reached: Full Propagation does always have a solution "if(crosses(layer)) == -1" // Even if particle is outside all layers -> can turn around in magnetic field return -1; } // Uses a numerically more stable procedure: // https://people.csail.mit.edu/bkph/articles/Quadratics.pdf double sqrtDelta = sqrt(delta); double phi1 = 0, phi2 = 0; if (b < 0) { phi1 = std::asin((2. * c) / (-b + sqrtDelta)); phi2 = std::asin((-b + sqrtDelta) / (2. * a)); } else { phi1 = std::asin((-b - sqrtDelta) / (2. * a)); phi2 = std::asin((2. * c) / (-b - sqrtDelta)); } // asin is ambiguous, make sure to have the right solution if (std::abs(layer.getRadius() - getRadParticle(phi1)) > 1.0e-2) { phi1 = -phi1 + M_PI; } if (std::abs(layer.getRadius() - getRadParticle(phi2)) > 1.0e-2) { phi2 = -phi2 + M_PI; } // another ambiguity if (phi1 < 0) { phi1 += 2. * M_PI; } if (phi2 < 0) { phi2 += 2. * M_PI; } // find the corresponding times when the intersection occurs // make sure they are positive double t1 = (phi1 - phi_) / phiSpeed_; while (t1 < 0) { t1 += 2 * M_PI / std::abs(phiSpeed_); } double t2 = (phi2 - phi_) / phiSpeed_; while (t2 < 0) { t2 += 2 * M_PI / std::abs(phiSpeed_); } // Check if propagation successful (numerical reasons): both solutions (phi1, phi2) have to be on the layer (same radius) // Can happen due to numerical instabilities of geometrical function (if momentum is almost parallel to x/y axis) // Get crossingTimeC from StraightTrajectory as good approximation if (std::abs(layer.getRadius() - getRadParticle(phi1)) > 1.0e-2 || std::abs(layer.getRadius() - getRadParticle(phi2)) > 1.0e-2) { StraightTrajectory traj(*this); return traj.nextCrossingTimeC(layer, onLayer); } // if the particle is already on the layer, we need to make sure the 2nd solution is picked. // happens if particle turns around in the magnetic field instead of hitting the next layer if (onLayer) { bool particleMovesInwards = momentum_.X() * position_.X() + momentum_.Y() * position_.Y() < 0; double posX1 = centerX_ + radius_ * std::cos(phi1); double posY1 = centerY_ + radius_ * std::sin(phi1); double momX1 = momentum_.X() * std::cos(phi1 - phi_) - momentum_.Y() * std::sin(phi1 - phi_); double momY1 = momentum_.X() * std::sin(phi1 - phi_) + momentum_.Y() * std::cos(phi1 - phi_); bool particleMovesInwards1 = momX1 * posX1 + momY1 * posY1 < 0; double posX2 = centerX_ + radius_ * std::cos(phi2); double posY2 = centerY_ + radius_ * std::sin(phi2); double momX2 = momentum_.X() * std::cos(phi2 - phi_) - momentum_.Y() * std::sin(phi2 - phi_); double momY2 = momentum_.X() * std::sin(phi2 - phi_) + momentum_.Y() * std::cos(phi2 - phi_); bool particleMovesInwards2 = momX2 * posX2 + momY2 * posY2 < 0; if (particleMovesInwards1 != particleMovesInwards) { return t1 * fastsim::Constants::speedOfLight; } else if (particleMovesInwards2 != particleMovesInwards) { return t2 * fastsim::Constants::speedOfLight; } // try to catch numerical issues again.. else { return -1; } } return std::min(t1, t2) * fastsim::Constants::speedOfLight; } void fastsim::HelixTrajectory::move(double deltaTimeC) { double deltaT = deltaTimeC / fastsim::Constants::speedOfLight; double deltaPhi = phiSpeed_ * deltaT; position_.SetXYZT(centerX_ + radius_ * std::cos(phi_ + deltaPhi), centerY_ + radius_ * std::sin(phi_ + deltaPhi), position_.Z() + momentum_.Z() / momentum_.E() * deltaTimeC, position_.T() + deltaT); // Rotation defined by // x' = x cos θ - y sin θ // y' = x sin θ + y cos θ momentum_.SetXYZT(momentum_.X() * std::cos(deltaPhi) - momentum_.Y() * std::sin(deltaPhi), momentum_.X() * std::sin(deltaPhi) + momentum_.Y() * std::cos(deltaPhi), momentum_.Z(), momentum_.E()); } double fastsim::HelixTrajectory::getRadParticle(double phi) const { return sqrt((centerX_ + radius_ * std::cos(phi)) * (centerX_ + radius_ * std::cos(phi)) + (centerY_ + radius_ * std::sin(phi)) * (centerY_ + radius_ * std::sin(phi))); }