Belle II Software  release-06-02-00
TrackVariables.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 // Own includes
10 #include <analysis/variables/TrackVariables.h>
11 #include <analysis/VariableManager/Manager.h>
12 
13 // framework - DataStore
14 #include <framework/datastore/StoreObjPtr.h>
15 #include <framework/dataobjects/Helix.h>
16 
17 // dataobjects from the MDST
18 #include <mdst/dataobjects/Track.h>
19 #include <mdst/dataobjects/MCParticle.h>
20 #include <mdst/dataobjects/TrackFitResult.h>
21 #include <mdst/dataobjects/EventLevelTrackingInfo.h>
22 #include <mdst/dataobjects/HitPatternVXD.h>
23 #include <mdst/dataobjects/ECLCluster.h>
24 
25 // framework aux
26 #include <framework/logging/Logger.h>
27 
28 #include <cmath>
29 
30 namespace Belle2 {
35  namespace Variable {
36 
37  static const double realNaN = std::numeric_limits<double>::quiet_NaN();
38  static const TVector3 vecNaN(realNaN, realNaN, realNaN);
39 
40  double trackNHits(const Particle* part, const Const::EDetector& det)
41  {
42  auto trackFit = part->getTrackFitResult();
43  if (!trackFit) return realNaN;
44 
45  // Before release-05 (MC13 + proc 11 and older) the hit patterns of TrackFitResults for V0s from the V0Finder were set to 0.
46  // Then, we have to take the detour via the related track to access the number of track hits.
47  if (trackFit->getHitPatternCDC().getNHits() + trackFit->getHitPatternVXD().getNdf() < 1) {
48  trackFit = part->getTrack()->getTrackFitResultWithClosestMass(Const::ChargedStable(std::abs(part->getPDGCode())));
49  }
50  if (det == Const::EDetector::CDC) {
51  return trackFit->getHitPatternCDC().getNHits();
52  } else if (det == Const::EDetector::SVD) {
53  return trackFit->getHitPatternVXD().getNSVDHits();
54  } else if (det == Const::EDetector::PXD) {
55  return trackFit->getHitPatternVXD().getNPXDHits();
56  } else {
57  return realNaN;
58  }
59  }
60 
61  double trackNCDCHits(const Particle* part)
62  {
63  return trackNHits(part, Const::EDetector::CDC);
64  }
65 
66  double trackNSVDHits(const Particle* part)
67  {
68  return trackNHits(part, Const::EDetector::SVD);
69  }
70 
71  double trackNPXDHits(const Particle* part)
72  {
73  return trackNHits(part, Const::EDetector::PXD);
74  }
75 
76  double trackNVXDHits(const Particle* part)
77  {
78  return trackNPXDHits(part) + trackNSVDHits(part);
79  }
80 
81  double trackNDF(const Particle* part)
82  {
83  auto trackFit = part->getTrackFitResult();
84  if (!trackFit) return realNaN;
85  return trackFit->getNDF();
86  }
87 
88  double trackChi2(const Particle* part)
89  {
90  auto trackFit = part->getTrackFitResult();
91  if (!trackFit) return realNaN;
92  return trackFit->getChi2();
93  }
94 
95  double trackFirstSVDLayer(const Particle* part)
96  {
97  auto trackFit = part->getTrackFitResult();
98  if (!trackFit) return realNaN;
99  // Before release-05 (MC13 + proc 11 and older) the hit patterns of TrackFitResults for V0s from the V0Finder were set to 0.
100  // Then, we have to take the detour via the related track to access the real pattern and get the first SVD layer if available.
101  if (trackFit->getHitPatternCDC().getNHits() + trackFit->getHitPatternVXD().getNdf() < 1) {
102  trackFit = part->getTrack()->getTrackFitResultWithClosestMass(Const::ChargedStable(std::abs(part->getPDGCode())));
103  }
104  return trackFit->getHitPatternVXD().getFirstSVDLayer();
105  }
106 
107  double trackFirstPXDLayer(const Particle* part)
108  {
109  auto trackFit = part->getTrackFitResult();
110  if (!trackFit) return realNaN;
111  // Before release-05 (MC13 + proc 11 and older) the hit patterns of TrackFitResults for V0s from the V0Finder were set to 0.
112  // Then, we have to take the detour via the related track to access the real pattern and get the first PXD layer if available.
113  if (trackFit->getHitPatternCDC().getNHits() + trackFit->getHitPatternVXD().getNdf() < 1) {
114  trackFit = part->getTrack()->getTrackFitResultWithClosestMass(Const::ChargedStable(std::abs(part->getPDGCode())));
115  }
116  return trackFit->getHitPatternVXD().getFirstPXDLayer(HitPatternVXD::PXDMode::normal);
117  }
118 
119  double trackFirstCDCLayer(const Particle* part)
120  {
121  auto trackFit = part->getTrackFitResult();
122  if (!trackFit) return realNaN;
123  // Before release-05 (MC13 + proc 11 and older) the hit patterns of TrackFitResults for V0s from the V0Finder were set to 0.
124  // Then, we have to take the detour via the related track to access the real pattern and get the first CDC layer if available.
125  if (trackFit->getHitPatternCDC().getNHits() + trackFit->getHitPatternVXD().getNdf() < 1) {
126  trackFit = part->getTrack()->getTrackFitResultWithClosestMass(Const::ChargedStable(std::abs(part->getPDGCode())));
127  }
128  return trackFit->getHitPatternCDC().getFirstLayer();
129  }
130 
131  double trackLastCDCLayer(const Particle* part)
132  {
133  auto trackFit = part->getTrackFitResult();
134  if (!trackFit) return realNaN;
135  // Before release-05 (MC13 + proc 11 and older) the hit patterns of TrackFitResults for V0s from the V0Finder were set to 0.
136  // Then, we have to take the detour via the related track to access the real pattern and get the last CDC layer if available.
137  if (trackFit->getHitPatternCDC().getNHits() + trackFit->getHitPatternVXD().getNdf() < 1) {
138  trackFit = part->getTrack()->getTrackFitResultWithClosestMass(Const::ChargedStable(std::abs(part->getPDGCode())));
139  }
140  return trackFit->getHitPatternCDC().getLastLayer();
141  }
142 
143  double trackD0(const Particle* part)
144  {
145  auto trackFit = part->getTrackFitResult();
146  if (!trackFit) return realNaN;
147  return trackFit->getD0();
148  }
149 
150  double trackPhi0(const Particle* part)
151  {
152  auto trackFit = part->getTrackFitResult();
153  if (!trackFit) return realNaN;
154  return trackFit->getPhi0();
155  }
156 
157  double trackOmega(const Particle* part)
158  {
159  auto trackFit = part->getTrackFitResult();
160  if (!trackFit) return realNaN;
161  return trackFit->getOmega();
162  }
163 
164  double trackZ0(const Particle* part)
165  {
166  auto trackFit = part->getTrackFitResult();
167  if (!trackFit) return realNaN;
168  return trackFit->getZ0();
169  }
170 
171  double trackTanLambda(const Particle* part)
172  {
173  auto trackFit = part->getTrackFitResult();
174  if (!trackFit) return realNaN;
175  return trackFit->getTanLambda();
176  }
177 
178  double trackD0Error(const Particle* part)
179  {
180  auto trackFit = part->getTrackFitResult();
181  if (!trackFit) return realNaN;
182 
183  double errorSquared = trackFit->getCovariance5()[0][0];
184  if (errorSquared <= 0) return realNaN;
185  return sqrt(errorSquared);
186  }
187 
188  double trackPhi0Error(const Particle* part)
189  {
190  auto trackFit = part->getTrackFitResult();
191  if (!trackFit) return realNaN;
192 
193  double errorSquared = trackFit->getCovariance5()[1][1];
194  if (errorSquared <= 0) return realNaN;
195  return sqrt(errorSquared);
196  }
197 
198  double trackOmegaError(const Particle* part)
199  {
200  auto trackFit = part->getTrackFitResult();
201  if (!trackFit) return realNaN;
202 
203  double errorSquared = trackFit->getCovariance5()[2][2];
204  if (errorSquared <= 0) return realNaN;
205  return sqrt(errorSquared);
206  }
207 
208  double trackZ0Error(const Particle* part)
209  {
210  auto trackFit = part->getTrackFitResult();
211  if (!trackFit) return realNaN;
212 
213  double errorSquared = trackFit->getCovariance5()[3][3];
214  if (errorSquared <= 0) return realNaN;
215  return sqrt(errorSquared);
216  }
217 
218  double trackTanLambdaError(const Particle* part)
219  {
220  auto trackFit = part->getTrackFitResult();
221  if (!trackFit) return realNaN;
222 
223  double errorSquared = trackFit->getCovariance5()[4][4];
224  if (errorSquared <= 0) return realNaN;
225  return sqrt(errorSquared);
226  }
227 
228  double trackPValue(const Particle* part)
229  {
230  auto trackFit = part->getTrackFitResult();
231  if (!trackFit) return realNaN;
232  return trackFit->getPValue();
233  }
234 
235  double trackFitHypothesisPDG(const Particle* part)
236  {
237  auto trackFit = part->getTrackFitResult();
238  if (!trackFit) return realNaN;
239  return trackFit->getParticleType().getPDGCode();
240  }
241 
242  double trackNECLClusters(const Particle* part)
243  {
244  const Track* track = part->getTrack();
245  if (!track) return realNaN;
246 
247  // count the number of nPhotons hypothesis ecl clusters
248  int count = 0;
249  for (const ECLCluster& cluster : track->getRelationsTo<ECLCluster>())
250  if (cluster.hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons))
251  ++count;
252  return count;
253  }
254 
255  // used in trackHelixExtTheta and trackHelixExtPhi
256  TVector3 getPositionOnHelix(const Particle* part, const std::vector<double>& pars)
257  {
258  if (pars.size() != 3) {
259  B2FATAL("Exactly three parameters (r, zfwd, zbwd) required.");
260  }
261 
262  const double r = pars[0];
263  const double zfwd = pars[1];
264  const double zbwd = pars[2];
265 
266  // get the track fit
267  auto trackFit = part->getTrackFitResult();
268  if (!trackFit) return vecNaN;
269 
270  // get helix and parameters
271  const double z0 = trackFit->getZ0();
272  const double tanlambda = trackFit->getTanLambda();
273  const Helix h = trackFit->getHelix();
274 
275  // extrapolate to radius
276  const double arcLength = h.getArcLength2DAtCylindricalR(r);
277  const double lHelixRadius = arcLength > 0 ? arcLength : std::numeric_limits<double>::max();
278 
279  // extrapolate to FWD z
280  const double lFWD = (zfwd - z0) / tanlambda > 0 ? (zfwd - z0) / tanlambda : std::numeric_limits<double>::max();
281 
282  // extrapolate to BWD z
283  const double lBWD = (zbwd - z0) / tanlambda > 0 ? (zbwd - z0) / tanlambda : std::numeric_limits<double>::max();
284 
285  // pick smallest arclength
286  const double l = std::min({lHelixRadius, lFWD, lBWD});
287 
288  return h.getPositionAtArcLength2D(l);
289  }
290 
291  // returns extrapolated theta position based on helix parameters
292  double trackHelixExtTheta(const Particle* part, const std::vector<double>& pars)
293  {
294  if (pars.size() != 3) {
295  B2FATAL("Exactly three parameters (r, zfwd, zbwd) required for helixExtTheta.");
296  }
297  TVector3 position = getPositionOnHelix(part, pars);
298  if (position == vecNaN) return realNaN;
299  return position.Theta();
300  }
301 
302  // returns extrapolated phi position based on helix parameters
303  double trackHelixExtPhi(const Particle* part, const std::vector<double>& pars)
304  {
305  if (pars.size() != 3) {
306  B2FATAL("Exactly three parameters (r, zfwd, zbwd) required for helixExtPhi.");
307  }
308  TVector3 position = getPositionOnHelix(part, pars);
309  if (position == vecNaN) return realNaN;
310  return position.Phi();
311  }
312 
313 
314  /***************************************************
315  * Event level tracking quantities
316  */
317 
318  // The number of CDC hits in the event not assigned to any track
319  double nExtraCDCHits(const Particle*)
320  {
321  StoreObjPtr<EventLevelTrackingInfo> elti;
322  if (!elti) return realNaN;
323  return elti->getNCDCHitsNotAssigned();
324  }
325 
326  // The number of CDC hits in the event not assigned to any track nor very
327  // likely beam background (i.e. hits that survive a cleanup selection)
328  double nExtraCDCHitsPostCleaning(const Particle*)
329  {
330  StoreObjPtr<EventLevelTrackingInfo> elti;
331  if (!elti) return realNaN;
332  return elti->getNCDCHitsNotAssignedPostCleaning();
333  }
334 
335  // Check for the presence of a non-assigned hit in the specified CDC layer
336  double hasExtraCDCHitsInLayer(const Particle*, const std::vector<double>& layer)
337  {
338  StoreObjPtr<EventLevelTrackingInfo> elti;
339  if (!elti) return realNaN;
340  int ilayer = std::lround(layer[0]);
341  return elti->hasCDCLayer(ilayer);
342  }
343 
344  // Check for the presence of a non-assigned hit in the specified CDC SuperLayer
345  double hasExtraCDCHitsInSuperLayer(const Particle*, const std::vector<double>& layer)
346  {
347  StoreObjPtr<EventLevelTrackingInfo> elti;
348  if (!elti) return realNaN;
349  int ilayer = std::lround(layer[0]);
350  return elti->hasCDCSLayer(ilayer);
351  }
352 
353  // The number of segments that couldn't be assigned to any track
354  double nExtraCDCSegments(const Particle*)
355  {
356  StoreObjPtr<EventLevelTrackingInfo> elti;
357  if (!elti) return realNaN;
358  return elti->getNCDCSegments();
359  }
360 
361  // The number of VXD hits not assigned to any track in the specified layer
362  double nExtraVXDHitsInLayer(const Particle*, const std::vector<double>& layer)
363  {
364  StoreObjPtr<EventLevelTrackingInfo> elti;
365  if (!elti) return realNaN;
366  int ilayer = std::lround(layer[0]);
367  return elti->getNVXDClustersInLayer(ilayer);
368  }
369 
370  // The number of VXD hits not assigned to any track
371  double nExtraVXDHits(const Particle*)
372  {
373  StoreObjPtr<EventLevelTrackingInfo> elti;
374  if (!elti) return realNaN;
375  double out = 0.0;
376  for (uint16_t ilayer = 1; ilayer < 7; ++ilayer)
377  out += elti->getNVXDClustersInLayer(ilayer);
378  return out;
379  }
380 
381  // time of first SVD sample relative to event T0
382  double svdFirstSampleTime(const Particle*)
383  {
384  StoreObjPtr<EventLevelTrackingInfo> elti;
385  if (!elti) return realNaN;
386  return elti->getSVDFirstSampleTime();
387  }
388 
389  // A flag set by the tracking if there is reason to assume there was a track
390  // in the event missed by the tracking or the track finding was (partly) aborted
391  // for this event. Further information about this can be obtained from the flagBlock
392  // of the EventLevelTrackingInfo object.
393  double trackFindingFailureFlag(const Particle*)
394  {
395  StoreObjPtr<EventLevelTrackingInfo> elti;
396  if (!elti) return realNaN;
397  return elti->hasAnErrorFlag();
398  }
399 
400  double getHelixParameterPullAtIndex(const Particle* particle, const int index)
401  {
402  if (!particle) return realNaN;
403 
404  const MCParticle* mcparticle = particle->getMCParticle();
405  if (!mcparticle) return realNaN;
406 
407  const Belle2::TrackFitResult* trackfit = particle->getTrackFitResult();
408  if (!trackfit) return realNaN;
409 
410  const Belle2::UncertainHelix measHelix = trackfit->getUncertainHelix();
411  const TMatrixDSym measCovariance = measHelix.getCovariance();
412  const TVector3 mcProdVertex = mcparticle->getVertex();
413  const TVector3 mcMomentum = mcparticle->getMomentum();
414 
415  const double BzAtProdVertex = Belle2::BFieldManager::getFieldInTesla(mcProdVertex).Z();
416  const double mcParticleCharge = mcparticle->getCharge();
417  const Belle2::Helix mcHelix = Belle2::Helix(mcProdVertex, mcMomentum, mcParticleCharge, BzAtProdVertex);
418 
419  const std::vector<double> mcHelixPars = {mcHelix.getD0(), mcHelix.getPhi0(), mcHelix.getOmega(), mcHelix.getZ0(), mcHelix.getTanLambda()};
420  const std::vector<double> measHelixPars = {measHelix.getD0(), measHelix.getPhi0(), measHelix.getOmega(), measHelix.getZ0(), measHelix.getTanLambda()};
421  const std::vector<double> measErrSquare = {measCovariance[0][0], measCovariance[1][1], measCovariance[2][2], measCovariance[3][3], measCovariance[4][4]};
422 
423  return (mcHelixPars.at(index) - measHelixPars.at(index)) / std::sqrt(measErrSquare.at(index));
424  }
425 
426  double getHelixD0Pull(const Particle* part)
427  {
428  return getHelixParameterPullAtIndex(part, 0);
429  }
430 
431  double getHelixPhi0Pull(const Particle* part)
432  {
433  return getHelixParameterPullAtIndex(part, 1);
434  }
435 
436  double getHelixOmegaPull(const Particle* part)
437  {
438  return getHelixParameterPullAtIndex(part, 2);
439  }
440 
441  double getHelixZ0Pull(const Particle* part)
442  {
443  return getHelixParameterPullAtIndex(part, 3);
444  }
445  double getHelixTanLambdaPull(const Particle* part)
446  {
447  return getHelixParameterPullAtIndex(part, 4);
448  }
449 
450 
451  VARIABLE_GROUP("Tracking");
452  REGISTER_VARIABLE("d0Pull", getHelixD0Pull, "(mc-meas)/err_meas for d0");
453  REGISTER_VARIABLE("phi0Pull", getHelixPhi0Pull, "(mc-meas)/err_meas for phi0");
454  REGISTER_VARIABLE("omegaPull", getHelixOmegaPull, "(mc-meas)/err_meas for omega");
455  REGISTER_VARIABLE("z0Pull", getHelixZ0Pull, "(mc-meas)/err_meas for z0");
456  REGISTER_VARIABLE("tanLambdaPull", getHelixTanLambdaPull, "(mc-meas)/err_meas for tanLambda");
457 
458  REGISTER_VARIABLE("nCDCHits", trackNCDCHits, "Number of CDC hits associated to the track");
459  REGISTER_VARIABLE("nSVDHits", trackNSVDHits, "Number of SVD hits associated to the track");
460  REGISTER_VARIABLE("nPXDHits", trackNPXDHits, "Number of PXD hits associated to the track");
461  REGISTER_VARIABLE("nVXDHits", trackNVXDHits, "Number of PXD and SVD hits associated to the track");
462  REGISTER_VARIABLE("ndf", trackNDF,
463  R"DOC(Number of degrees of freedom of the track fit. Note that it is not NHIT-5 due to outlier hit rejection.
464 For mdst versions < 5.1, returns quiet_NaN().)DOC"
465  );
466  REGISTER_VARIABLE("chi2", trackChi2,
467  R"DOC(Chi2 of the track fit.
468 Computed based on pValue and ndf. Note that for pValue exactly equal to 0 it returns infinity().
469 For mdst versions < 5.1, returns quiet_NaN().)DOC");
470  REGISTER_VARIABLE("firstSVDLayer", trackFirstSVDLayer, "First activated SVD layer associated to the track");
471  REGISTER_VARIABLE("firstPXDLayer", trackFirstPXDLayer, "First activated PXD layer associated to the track");
472  REGISTER_VARIABLE("firstCDCLayer", trackFirstCDCLayer, "First activated CDC layer associated to the track");
473  REGISTER_VARIABLE("lastCDCLayer", trackLastCDCLayer, "Last CDC layer associated to the track");
474  REGISTER_VARIABLE("d0", trackD0, "Signed distance to the POCA in the r-phi plane");
475  REGISTER_VARIABLE("phi0", trackPhi0, "Angle of the transverse momentum in the r-phi plane");
476  REGISTER_VARIABLE("omega", trackOmega, "Curvature of the track");
477  REGISTER_VARIABLE("z0", trackZ0, "z coordinate of the POCA");
478  REGISTER_VARIABLE("tanLambda", trackTanLambda, "Slope of the track in the r-z plane");
479  REGISTER_VARIABLE("d0Err", trackD0Error, "Error of signed distance to the POCA in the r-phi plane");
480  REGISTER_VARIABLE("phi0Err", trackPhi0Error, "Error of angle of the transverse momentum in the r-phi plane");
481  REGISTER_VARIABLE("omegaErr", trackOmegaError, "Error of curvature of the track");
482  REGISTER_VARIABLE("z0Err", trackZ0Error, "Error of z coordinate of the POCA");
483  REGISTER_VARIABLE("tanLambdaErr", trackTanLambdaError, "Error of slope of the track in the r-z plane");
484  REGISTER_VARIABLE("pValue", trackPValue, "chi2 probability of the track fit");
485  REGISTER_VARIABLE("trackFitHypothesisPDG", trackFitHypothesisPDG, "PDG code of the track hypothesis actually used for the fit");
486  REGISTER_VARIABLE("trackNECLClusters", trackNECLClusters,
487  "Number ecl clusters matched to the track. This is always 0 or 1 with newer versions of ECL reconstruction.");
488  REGISTER_VARIABLE("helixExtTheta", trackHelixExtTheta,
489  "Returns theta of extrapolated helix parameters (parameters (in cm): radius, z fwd, z bwd)");
490  REGISTER_VARIABLE("helixExtPhi", trackHelixExtPhi,
491  "Returns phi of extrapolated helix parameters (parameters (in cm): radius, z fwd, z bwd)");
492 
493  REGISTER_VARIABLE("nExtraCDCHits", nExtraCDCHits, "[Eventbased] The number of CDC hits in the event not assigned to any track");
494  REGISTER_VARIABLE("nExtraCDCHitsPostCleaning", nExtraCDCHitsPostCleaning,
495  "[Eventbased] The number of CDC hits in the event not assigned to any track nor very likely beam background (i.e. hits that survive a cleanup selection)");
496  REGISTER_VARIABLE("hasExtraCDCHitsInLayer(i)", hasExtraCDCHitsInLayer,
497  "[Eventbased] Returns 1 if a non-assigned hit exists in the specified CDC layer");
498  REGISTER_VARIABLE("hasExtraCDCHitsInSuperLayer(i)", hasExtraCDCHitsInSuperLayer,
499  "[Eventbased] Returns 1 if a non-assigned hit exists in the specified CDC SuperLayer");
500  REGISTER_VARIABLE("nExtraCDCSegments", nExtraCDCSegments, "[Eventbased] The number of CDC segments not assigned to any track");
501  // TODO: once the Tracking group fill the dataobject these can be
502  // uncommented - at the moment they are not filled, so leave out
503  //REGISTER_VARIABLE("nExtraVXDHitsInLayer(i)", nExtraVXDHitsInLayer,
504  //"[Eventbased] The number VXD hits not assigned in the specified VXD layer");
505  //REGISTER_VARIABLE("nExtraVXDHits", nExtraVXDHits, "[Eventbased] The number of VXD hits not assigned to any track");
506  //REGISTER_VARIABLE("svdFirstSampleTime", svdFirstSampleTime, "[Eventbased] The time of first SVD sample relatvie to event T0");
507  REGISTER_VARIABLE("trackFindingFailureFlag", trackFindingFailureFlag,
508  "[Eventbased] A flag set by the tracking if there is reason to assume there was a track in the event missed by the tracking, "
509  "or the track finding was (partly) aborted for this event.");
510 
511 
512  }
514 }
DataType Z() const
access variable Z (= .at(2) without boundary check)
Definition: B2Vector3.h:420
static B2Vector3D getFieldInTesla(const B2Vector3D &pos)
return the magnetic field at a given position in Tesla.
Definition: BFieldManager.h:70
Helix parameter class.
Definition: Helix.h:48
EDetector
Enum for identifying the detector components (detector and subdetector).
Definition: Const.h:42
@ c_nPhotons
CR is split into n photons (N1)
Values of the result of a track fit with a given particle hypothesis.
UncertainHelix getUncertainHelix() const
Conversion to framework Uncertain Helix (i.e., with covariance).
This class represents an ideal helix in perigee parameterization including the covariance matrix of t...
const TMatrixDSym & getCovariance() const
Getter for covariance matrix of perigee parameters in matrix form.
static const double realNaN
shortcut for NaN of double type
static const TVector3 vecNaN(realNaN, realNaN, realNaN)
vector with NaN entries
Abstract base class for different kinds of events.