CMS 3D CMS Logo

TrackerSimHitProducer.cc
Go to the documentation of this file.
1 #include <memory>
2 
3 #include <memory>
4 #include <vector>
5 
6 // framework
11 
12 // tracking
18 
19 // fastsim
26 
27 // data formats
35 
36 // other
39 
41 // Author: L. Vanelderen, S. Kurz
42 // Date: 29 May 2017
44 
45 typedef std::pair<const GeomDet*, TrajectoryStateOnSurface> DetWithState;
46 
47 namespace fastsim {
49 
55  public:
58 
60  ~TrackerSimHitProducer() override { ; }
61 
63 
69  void interact(Particle& particle,
70  const SimplifiedGeometry& layer,
71  std::vector<std::unique_ptr<Particle>>& secondaries,
72  const RandomEngineAndDistribution& random) override;
73 
75  void registerProducts(edm::ProducesCollector) const override;
76 
78  void storeProducts(edm::Event& iEvent) override;
79 
81 
91  std::pair<double, std::unique_ptr<PSimHit>> createHitOnDetector(const TrajectoryStateOnSurface& particle,
92  int pdgId,
93  double layerThickness,
94  double eLoss,
95  int simTrackId,
96  const GeomDet& detector,
97  GlobalPoint& refPos);
98 
99  private:
100  const double
102  std::unique_ptr<edm::PSimHitContainer> simHitContainer_;
103  double minMomentum_;
105  };
106 } // namespace fastsim
107 
109  : fastsim::InteractionModel(name), onSurfaceTolerance_(0.01), simHitContainer_(new edm::PSimHitContainer) {
110  // Set the minimal momentum
111  minMomentum_ = cfg.getParameter<double>("minMomentumCut");
112  // - if not set, particles from outside the beampipe with a negative speed in R direction are propagated but no SimHits
113  // - particle with positive (negative) z and negative (positive) speed in z direction: no SimHits
114  // -> this is not neccesary since a track reconstruction is not possible in this case anyways
115  doHitsFromInboundParticles_ = cfg.getParameter<bool>("doHitsFromInboundParticles");
116 }
117 
119  producesCollector.produces<edm::PSimHitContainer>("TrackerHits");
120 }
121 
123  iEvent.put(std::move(simHitContainer_), "TrackerHits");
124  simHitContainer_ = std::make_unique<edm::PSimHitContainer>();
125 }
126 
128  const SimplifiedGeometry& layer,
129  std::vector<std::unique_ptr<Particle>>& secondaries,
130  const RandomEngineAndDistribution& random) {
131  // the energy deposit in the layer
132  double energyDeposit = particle.getEnergyDeposit();
133  particle.setEnergyDeposit(0);
134 
135  //
136  // don't save hits from particle that did a loop or are inbound (coming from the outer part of the tracker, going towards the center)
137  //
138  if (!doHitsFromInboundParticles_) {
139  if (particle.isLooper()) {
140  return;
141  }
142  if (particle.momentum().X() * particle.position().X() + particle.momentum().Y() * particle.position().Y() < 0) {
143  particle.setLooper();
144  return;
145  }
146  if (layer.isForward() && ((particle.position().Z() > 0 && particle.momentum().Z() < 0) ||
147  (particle.position().Z() < 0 && particle.momentum().Z() > 0))) {
148  particle.setLooper();
149  return;
150  }
151  }
152 
153  //
154  // check that layer has tracker modules
155  //
156  if (!layer.getDetLayer()) {
157  return;
158  }
159 
160  //
161  // no material
162  //
163  if (layer.getThickness(particle.position(), particle.momentum()) < 1E-10) {
164  return;
165  }
166 
167  //
168  // only charged particles
169  //
170  if (particle.charge() == 0) {
171  return;
172  }
173 
174  //
175  // save hit only if momentum higher than threshold
176  //
177  if (particle.momentum().Perp2() < minMomentum_ * minMomentum_) {
178  return;
179  }
180 
181  // create the trajectory of the particle
182  UniformMagneticField magneticField(layer.getMagneticFieldZ(particle.position()));
183  GlobalPoint position(particle.position().X(), particle.position().Y(), particle.position().Z());
184  GlobalVector momentum(particle.momentum().Px(), particle.momentum().Py(), particle.momentum().Pz());
185  auto plane = layer.getDetLayer()->surface().tangentPlane(position);
186  TrajectoryStateOnSurface trajectory(
187  GlobalTrajectoryParameters(position, momentum, TrackCharge(particle.charge()), &magneticField), *plane);
188 
189  // find detectors compatible with the particle's trajectory
192  std::vector<DetWithState> compatibleDetectors = layer.getDetLayer()->compatibleDets(trajectory, propagator, est);
193 
195  // You have to sort the simHits in the order they occur!
197 
198  // The old algorithm (sorting by distance to IP) doesn't seem to make sense to me (what if particle moves inwards?)
199 
200  // Detector layers have to be sorted by proximity to particle.position
201  // Propagate particle backwards a bit to make sure it's outside any components
202  std::map<double, std::unique_ptr<PSimHit>> distAndHits;
203  // Position relative to which the hits should be sorted
204  GlobalPoint positionOutside(particle.position().x() - particle.momentum().x() / particle.momentum().P() * 10.,
205  particle.position().y() - particle.momentum().y() / particle.momentum().P() * 10.,
206  particle.position().z() - particle.momentum().z() / particle.momentum().P() * 10.);
207 
208  // FastSim: cheat tracking -> assign hits to closest charged daughter if particle decays
209  int pdgId = particle.pdgId();
210  int simTrackId =
211  particle.getMotherSimTrackIndex() >= 0 ? particle.getMotherSimTrackIndex() : particle.simTrackIndex();
212 
213  // loop over the compatible detectors
214  for (const auto& detectorWithState : compatibleDetectors) {
215  const GeomDet& detector = *detectorWithState.first;
216  const TrajectoryStateOnSurface& particleState = detectorWithState.second;
217 
218  // if the detector has no components
219  if (detector.isLeaf()) {
220  std::pair<double, std::unique_ptr<PSimHit>> hitPair = createHitOnDetector(particleState,
221  pdgId,
222  layer.getThickness(particle.position()),
223  energyDeposit,
224  simTrackId,
225  detector,
226  positionOutside);
227  if (hitPair.second) {
228  distAndHits.insert(distAndHits.end(), std::move(hitPair));
229  }
230  } else {
231  // if the detector has components
232  for (const auto component : detector.components()) {
233  std::pair<double, std::unique_ptr<PSimHit>> hitPair =
234  createHitOnDetector(particleState,
235  pdgId,
236  layer.getThickness(particle.position()),
237  energyDeposit,
238  simTrackId,
239  *component,
240  positionOutside);
241  if (hitPair.second) {
242  distAndHits.insert(distAndHits.end(), std::move(hitPair));
243  }
244  }
245  }
246  }
247 
248  // Fill simHitContainer
249  for (std::map<double, std::unique_ptr<PSimHit>>::const_iterator it = distAndHits.begin(); it != distAndHits.end();
250  it++) {
251  simHitContainer_->push_back(*(it->second));
252  }
253 }
254 
255 // Also returns distance to simHit since hits have to be ordered (in time) afterwards. Necessary to do explicit copy of TrajectoryStateOnSurface particle (not call by reference)
256 std::pair<double, std::unique_ptr<PSimHit>> fastsim::TrackerSimHitProducer::createHitOnDetector(
257  const TrajectoryStateOnSurface& particle,
258  int pdgId,
259  double layerThickness,
260  double eLoss,
261  int simTrackId,
262  const GeomDet& detector,
263  GlobalPoint& refPos) {
264  // determine position and momentum of particle in the coordinate system of the detector
265  LocalPoint localPosition;
266  LocalVector localMomentum;
267 
268  // if the particle is close enough, no further propagation is needed
269  if (fabs(detector.toLocal(particle.globalPosition()).z()) < onSurfaceTolerance_) {
270  localPosition = particle.localPosition();
271  localMomentum = particle.localMomentum();
272  }
273  // else, propagate
274  else {
275  // find crossing of particle with detector layer
277  particle.globalMomentum().basicVector(),
278  particle.transverseCurvature(),
279  anyDirection);
280  std::pair<bool, double> path = crossing.pathLength(detector.surface());
281  // case propagation succeeds
282  if (path.first) {
283  localPosition = detector.toLocal(GlobalPoint(crossing.position(path.second)));
284  localMomentum = detector.toLocal(GlobalVector(crossing.direction(path.second)));
285  localMomentum = localMomentum.unit() * particle.localMomentum().mag();
286  }
287  // case propagation fails
288  else {
289  return std::pair<double, std::unique_ptr<PSimHit>>(0, std::unique_ptr<PSimHit>(nullptr));
290  }
291  }
292 
293  // find entry and exit point of particle in detector
294  const Plane& detectorPlane = detector.surface();
295  double halfThick = 0.5 * detectorPlane.bounds().thickness();
296  double pZ = localMomentum.z();
297  LocalPoint entry = localPosition + (-halfThick / pZ) * localMomentum;
298  LocalPoint exit = localPosition + (halfThick / pZ) * localMomentum;
299  double tof = particle.globalPosition().mag() / fastsim::Constants::speedOfLight; // in nanoseconds
300 
301  // make sure the simhit is physically on the module
302  double boundX = detectorPlane.bounds().width() / 2.;
303  double boundY = detectorPlane.bounds().length() / 2.;
304  // Special treatment for TID and TEC trapeziodal modules
305  unsigned subdet = DetId(detector.geographicalId()).subdetId();
306  if (subdet == 4 || subdet == 6)
307  boundX *= 1. - localPosition.y() / detectorPlane.position().perp();
308  if (fabs(localPosition.x()) > boundX || fabs(localPosition.y()) > boundY) {
309  return std::pair<double, std::unique_ptr<PSimHit>>(0, std::unique_ptr<PSimHit>(nullptr));
310  }
311 
312  // Create the hit: the energy loss rescaled to the module thickness
313  // Total thickness is in radiation lengths, 1 radlen = 9.36 cm
314  // Sensitive module thickness is about 30 microns larger than
315  // the module thickness itself
316  eLoss *= (2. * halfThick - 0.003) / (9.36 * layerThickness);
317 
318  // Position of the hit in global coordinates
319  GlobalPoint hitPos(detector.surface().toGlobal(localPosition));
320 
321  return std::pair<double, std::unique_ptr<PSimHit>>((hitPos - refPos).mag(),
322  std::make_unique<PSimHit>(entry,
323  exit,
324  localMomentum.mag(),
325  tof,
326  eLoss,
327  pdgId,
328  detector.geographicalId().rawId(),
329  simTrackId,
330  localMomentum.theta(),
331  localMomentum.phi()));
332 }
333 
TrackerSimHitProducer(const std::string &name, const edm::ParameterSet &cfg)
Constructor.
T perp() const
Definition: PV3DBase.h:69
int getMotherSimTrackIndex() const
Get index of simTrack of mother particle (only makes sense if mother and daughter charged)...
Definition: Particle.h:216
Implementation of a generic detector layer (base class for forward/barrel layers).
virtual float length() const =0
ProductRegistryHelper::BranchAliasSetterT< ProductType > produces()
void registerProducts(edm::ProducesCollector) const override
Register the SimHit collection.
T z() const
Definition: PV3DBase.h:61
Geom::Phi< T > phi() const
Definition: PV3DBase.h:66
Global3DPoint GlobalPoint
Definition: GlobalPoint.h:10
static double constexpr speedOfLight
Speed of light [cm / ns].
Definition: Constants.h:12
const math::XYZTLorentzVector & position() const
Return position of the particle.
Definition: Particle.h:140
std::unique_ptr< edm::PSimHitContainer > simHitContainer_
The SimHit.
Definition: Plane.h:16
virtual float thickness() const =0
~TrackerSimHitProducer() override
Default destructor.
Base class for any interaction model between a particle and a tracker layer.
int TrackCharge
Definition: TrackCharge.h:4
T x() const
Definition: PV3DBase.h:59
T y() const
Definition: PV3DBase.h:60
Produces SimHits in the tracker layers.
void setLooper()
This particle is about to do a loop in the tracker or the direction of the momentum is going inwards...
Definition: Particle.h:94
int iEvent
Definition: GenABIO.cc:224
bool doHitsFromInboundParticles_
If not set, incoming particles (negative speed relative to center of detector) don&#39;t create a SimHits...
GlobalPoint globalPosition() const
std::pair< double, std::unique_ptr< PSimHit > > createHitOnDetector(const TrajectoryStateOnSurface &particle, int pdgId, double layerThickness, double eLoss, int simTrackId, const GeomDet &detector, GlobalPoint &refPos)
Helper funtion to create the actual SimHit on a detector (sub-) module.
double getEnergyDeposit() const
Return the energy the particle deposited in the tracker layer that was last hit (ionization).
Definition: Particle.h:188
T mag() const
Definition: PV3DBase.h:64
int simTrackIndex() const
Return index of the SimTrack.
Definition: Particle.h:153
const BasicVectorType & basicVector() const
Definition: PV3DBase.h:53
int pdgId() const
Return pdgId of the particle.
Definition: Particle.h:134
Definition: DetId.h:17
double isLooper() const
Check if this particle is about to do a loop in the tracker or the direction of the momentum is going...
Definition: Particle.h:195
T mag() const
The vector magnitude. Equivalent to sqrt(vec.mag2())
const PositionType & position() const
double minMomentum_
Set the minimal momentum of incoming particle.
void storeProducts(edm::Event &iEvent) override
Store the SimHit collection.
const math::XYZTLorentzVector & momentum() const
Return momentum of the particle.
Definition: Particle.h:143
GlobalVector globalMomentum() const
void interact(Particle &particle, const SimplifiedGeometry &layer, std::vector< std::unique_ptr< Particle >> &secondaries, const RandomEngineAndDistribution &random) override
Perform the interaction.
std::pair< const GeomDet *, TrajectoryStateOnSurface > DetWithState
double charge() const
Return charge of the particle.
Definition: Particle.h:137
HLT enums.
static int position[264][3]
Definition: ReadPGInfo.cc:289
#define DEFINE_EDM_PLUGIN(factory, type, name)
std::vector< PSimHit > PSimHitContainer
Vector3DBase unit() const
Definition: Vector3DBase.h:54
virtual float width() const =0
void setEnergyDeposit(double energyDeposit)
Set the energy the particle deposited in the tracker layer that was last hit (ionization).
Definition: Particle.h:87
def move(src, dest)
Definition: eostools.py:511
Global3DVector GlobalVector
Definition: GlobalVector.h:10
Geom::Theta< T > theta() const
Definition: PV3DBase.h:72
const double onSurfaceTolerance_
Max distance between particle and active (sub-) module. Otherwise particle has to be propagated...
def exit(msg="")
const Bounds & bounds() const
Definition: Surface.h:87