CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
PFRecoTauDiscriminationByIsolation.cc
Go to the documentation of this file.
1 #include <functional>
8 
9 #include "TMath.h"
10 #include "TFormula.h"
11 
12 /* class PFRecoTauDiscriminationByIsolation
13  * created : Jul 23 2007,
14  * revised : Thu Aug 13 14:44:40 PDT 2009
15  * contributors : Ludovic Houchu (IPHC, Strasbourg),
16  * Christian Veelken (UC Davis),
17  * Evan K. Friis (UC Davis)
18  * Michalis Bachtis (UW Madison)
19  */
20 
21 using namespace reco;
22 using namespace std;
23 
25 {
26  public:
29  moduleLabel_(pset.getParameter<std::string>("@module_label")),
30  qualityCutsPSet_(pset.getParameter<edm::ParameterSet>("qualityCuts"))
31  {
32  includeTracks_ = pset.getParameter<bool>(
33  "ApplyDiscriminationByTrackerIsolation");
34  includeGammas_ = pset.getParameter<bool>(
35  "ApplyDiscriminationByECALIsolation");
36 
37  calculateWeights_ = pset.exists("ApplyDiscriminationByWeightedECALIsolation") ?
38  pset.getParameter<bool>("ApplyDiscriminationByWeightedECALIsolation") : false;
39 
40  applyOccupancyCut_ = pset.getParameter<bool>("applyOccupancyCut");
41  maximumOccupancy_ = pset.getParameter<uint32_t>("maximumOccupancy");
42 
43  applySumPtCut_ = pset.getParameter<bool>("applySumPtCut");
44  maximumSumPt_ = pset.getParameter<double>("maximumSumPtCut");
45 
46  applyRelativeSumPtCut_ = pset.getParameter<bool>(
47  "applyRelativeSumPtCut");
48  maximumRelativeSumPt_ = pset.getParameter<double>(
49  "relativeSumPtCut");
50  offsetRelativeSumPt_ = pset.exists("relativeSumPtOffset") ?
51  pset.getParameter<double>("relativeSumPtOffset") : 0.0;
52 
53  storeRawOccupancy_ = pset.exists("storeRawOccupancy") ?
54  pset.getParameter<bool>("storeRawOccupancy") : false;
55  storeRawSumPt_ = pset.exists("storeRawSumPt") ?
56  pset.getParameter<bool>("storeRawSumPt") : false;
57  storeRawPUsumPt_ = pset.exists("storeRawPUsumPt") ?
58  pset.getParameter<bool>("storeRawPUsumPt") : false;
59 
60  // Sanity check on requested options. We can't apply cuts and store the
61  // raw output at the same time
62  if ( applySumPtCut_ || applyOccupancyCut_ || applyRelativeSumPtCut_ ) {
63  if ( storeRawSumPt_ || storeRawOccupancy_ || storeRawPUsumPt_ ) {
64  throw cms::Exception("BadIsoConfig")
65  << "A 'store raw' and a 'apply cut' option have been set to true "
66  << "simultaneously. These options are mutually exclusive.";
67  }
68  }
69 
70  // sanity check2 - can't use weighted and unweighted iso at the same time
71  if(includeGammas_ && calculateWeights_)
72  {
73  throw cms::Exception("BasIsoConfig")
74  << "Both 'ApplyDiscriminationByECALIsolation' and 'ApplyDiscriminationByWeightedECALIsolation' "
75  << "have been set to true. These options are mutually exclusive.";
76  }
77 
78  // Can only store one type
79  int numStoreOptions = 0;
80  if ( storeRawSumPt_ ) ++numStoreOptions;
81  if ( storeRawOccupancy_ ) ++numStoreOptions;
82  if ( storeRawPUsumPt_ ) ++numStoreOptions;
83  if ( numStoreOptions > 1 ) {
84  throw cms::Exception("BadIsoConfig")
85  << "Both 'store sum pt' and 'store occupancy' options are set."
86  << " These options are mutually exclusive.";
87  }
88 
89  if ( pset.exists("customOuterCone") ) {
90  customIsoCone_ = pset.getParameter<double>("customOuterCone");
91  } else {
92  customIsoCone_ = -1;
93  }
94 
95  // Get the quality cuts specific to the isolation region
96  edm::ParameterSet isolationQCuts = qualityCutsPSet_.getParameterSet(
97  "isolationQualityCuts");
98 
99  qcuts_.reset(new tau::RecoTauQualityCuts(isolationQCuts));
100 
101  vertexAssociator_.reset(
102  new tau::RecoTauVertexAssociator(qualityCutsPSet_,consumesCollector()));
103 
104  applyDeltaBeta_ = pset.exists("applyDeltaBetaCorrection") ?
105  pset.getParameter<bool>("applyDeltaBetaCorrection") : false;
106 
107  if ( applyDeltaBeta_ || calculateWeights_ ) {
108  // Factorize the isolation QCuts into those that are used to
109  // select PU and those that are not.
110  std::pair<edm::ParameterSet, edm::ParameterSet> puFactorizedIsoQCuts =
111  reco::tau::factorizePUQCuts(isolationQCuts);
112 
113  // Determine the pt threshold for the PU tracks
114  // First check if the user specifies explicitly the cut.
115  if ( pset.exists("deltaBetaPUTrackPtCutOverride") ) {
116  puFactorizedIsoQCuts.second.addParameter<double>(
117  "minTrackPt",
118  pset.getParameter<double>("deltaBetaPUTrackPtCutOverride"));
119  } else {
120  // Secondly take it from the minGammaEt
121  puFactorizedIsoQCuts.second.addParameter<double>(
122  "minTrackPt",
123  isolationQCuts.getParameter<double>("minGammaEt"));
124  }
125 
126  pileupQcutsPUTrackSelection_.reset(new tau::RecoTauQualityCuts(
127  puFactorizedIsoQCuts.first));
128 
129  pileupQcutsGeneralQCuts_.reset(new tau::RecoTauQualityCuts(
130  puFactorizedIsoQCuts.second));
131 
132  pfCandSrc_ = pset.getParameter<edm::InputTag>("particleFlowSrc");
133  pfCand_token=consumes<reco::PFCandidateCollection>(pfCandSrc_);
134  vertexSrc_ = pset.getParameter<edm::InputTag>("vertexSrc");
135  vertex_token=consumes<reco::VertexCollection>(vertexSrc_);
136  deltaBetaCollectionCone_ = pset.getParameter<double>(
137  "isoConeSizeForDeltaBeta");
138  std::string deltaBetaFactorFormula =
139  pset.getParameter<string>("deltaBetaFactor");
140  deltaBetaFormula_.reset(
141  new TFormula("DB_corr", deltaBetaFactorFormula.c_str()));
142  }
143 
144  applyRhoCorrection_ = pset.exists("applyRhoCorrection") ?
145  pset.getParameter<bool>("applyRhoCorrection") : false;
146  if ( applyRhoCorrection_ ) {
147  rhoProducer_ = pset.getParameter<edm::InputTag>("rhoProducer");
148  rho_token=consumes<double>(rhoProducer_);
149  rhoConeSize_ = pset.getParameter<double>("rhoConeSize");
150  rhoUEOffsetCorrection_ =
151  pset.getParameter<double>("rhoUEOffsetCorrection");
152  }
153  useAllPFCands_ = pset.exists("UseAllPFCandsForWeights") ?
154  pset.getParameter<bool>("UseAllPFCandsForWeights") : false;
155 
156  verbosity_ = ( pset.exists("verbosity") ) ?
157  pset.getParameter<int>("verbosity") : 0;
158  }
159 
161 
162  void beginEvent(const edm::Event& evt, const edm::EventSetup& evtSetup) override;
163  double discriminate(const PFTauRef& pfTau) const override;
164 
165  inline double weightedSum(std::vector<PFCandidatePtr> inColl_, double eta, double phi) const {
166  double out = 1.0;
167  for (auto const & inObj_ : inColl_){
168  double sum = (inObj_->pt()*inObj_->pt())/(deltaR2(eta,phi,inObj_->eta(),inObj_->phi()));
169  if(sum > 1.0) out *= sum;
170  }
171  return out;
172  }
173 
174  private:
176 
178  std::auto_ptr<tau::RecoTauQualityCuts> qcuts_;
179 
180  // Inverted QCut which selects tracks with bad DZ/trackWeight
181  std::auto_ptr<tau::RecoTauQualityCuts> pileupQcutsPUTrackSelection_;
182  std::auto_ptr<tau::RecoTauQualityCuts> pileupQcutsGeneralQCuts_;
183 
184  std::auto_ptr<tau::RecoTauVertexAssociator> vertexAssociator_;
185 
197 
198  // Options to store the raw value in the discriminator instead of boolean pass/fail flag
202 
203  /* **********************************************************************
204  **** Pileup Subtraction Parameters ***********************************
205  **********************************************************************/
206 
207  // Delta Beta correction
211  // Keep track of how many vertices are in the event
214  std::vector<reco::PFCandidatePtr> chargedPFCandidatesInEvent_;
215  // Size of cone used to collect PU tracks
217  std::auto_ptr<TFormula> deltaBetaFormula_;
219 
220  // Rho correction
225  double rhoConeSize_;
229 
230  // Flag to enable/disable debug output
232 };
233 
235 {
236  // NB: The use of the PV in this context is necessitated by its use in
237  // applying quality cuts to the different objects in the isolation cone
238  // The vertex associator contains the logic to select the appropriate vertex
239  // We need to pass it the event so it can load the vertices.
240  vertexAssociator_->setEvent(event);
241 
242  // If we are applying the delta beta correction, we need to get the PF
243  // candidates from the event so we can find the PU tracks.
244  if ( applyDeltaBeta_ || calculateWeights_ ) {
245  // Collect all the PF pile up tracks
247  event.getByToken(pfCand_token, pfCandidates);
248  chargedPFCandidatesInEvent_.clear();
249  chargedPFCandidatesInEvent_.reserve(pfCandidates->size());
250  size_t numPFCandidates = pfCandidates->size();
251  for ( size_t i = 0; i < numPFCandidates; ++i ) {
252  reco::PFCandidatePtr pfCandidate(pfCandidates, i);
253  if ( pfCandidate->charge() != 0 ) {
254  chargedPFCandidatesInEvent_.push_back(pfCandidate);
255  }
256  }
257  // Count all the vertices in the event, to parameterize the DB
258  // correction factor
260  event.getByToken(vertex_token, vertices);
261  size_t nVtxThisEvent = vertices->size();
262  deltaBetaFactorThisEvent_ = deltaBetaFormula_->Eval(nVtxThisEvent);
263  }
264 
265  if ( applyRhoCorrection_ ) {
266  edm::Handle<double> rhoHandle_;
267  event.getByToken(rho_token, rhoHandle_);
268  rhoThisEvent_ = (*rhoHandle_ - rhoUEOffsetCorrection_)*
269  (3.14159)*rhoConeSize_*rhoConeSize_;
270  }
271 }
272 
273 double
275 {
276  LogDebug("discriminate") << " tau: Pt = " << pfTau->pt() << ", eta = " << pfTau->eta() << ", phi = " << pfTau->phi();
277  LogDebug("discriminate") << *pfTau ;
278 
279  // collect the objects we are working with (ie tracks, tracks+gammas, etc)
280  std::vector<PFCandidatePtr> isoCharged_;
281  std::vector<PFCandidatePtr> isoNeutral_;
282  std::vector<PFCandidatePtr> isoPU_;
283  PFCandidateCollection isoNeutralWeight_;
284  std::vector<PFCandidatePtr> chPV_;
285  isoCharged_.reserve(pfTau->isolationPFChargedHadrCands().size());
286  isoNeutral_.reserve(pfTau->isolationPFGammaCands().size());
287  isoPU_.reserve(chargedPFCandidatesInEvent_.size());
288  isoNeutralWeight_.reserve(pfTau->isolationPFGammaCands().size());
289 
290  chPV_.reserve(chargedPFCandidatesInEvent_.size());
291 
292  // Get the primary vertex associated to this tau
293  reco::VertexRef pv = vertexAssociator_->associatedVertex(*pfTau);
294  // Let the quality cuts know which the vertex to use when applying selections
295  // on dz, etc.
296  if ( verbosity_ ) {
297  if ( pv.isNonnull() ) {
298  LogTrace("discriminate") << "pv: x = " << pv->position().x() << ", y = " << pv->position().y() << ", z = " << pv->position().z() ;
299  } else {
300  LogTrace("discriminate") << "pv: N/A" ;
301  }
302  if ( pfTau->leadPFChargedHadrCand().isNonnull() ) {
303  LogTrace("discriminate") << "leadPFChargedHadron:"
304  << " Pt = " << pfTau->leadPFChargedHadrCand()->pt() << ","
305  << " eta = " << pfTau->leadPFChargedHadrCand()->eta() << ","
306  << " phi = " << pfTau->leadPFChargedHadrCand()->phi() ;
307  } else {
308  LogTrace("discriminate") << "leadPFChargedHadron: N/A" ;
309  }
310  }
311 
312  // CV: isolation is not well defined in case primary vertex or leading charged hadron do not exist
313  if ( !(pv.isNonnull() && pfTau->leadPFChargedHadrCand().isNonnull()) ) return 0.;
314 
315  qcuts_->setPV(pv);
316  qcuts_->setLeadTrack(pfTau->leadPFChargedHadrCand());
317 
318  if ( applyDeltaBeta_ || calculateWeights_) {
319  pileupQcutsGeneralQCuts_->setPV(pv);
320  pileupQcutsGeneralQCuts_->setLeadTrack(pfTau->leadPFChargedHadrCand());
321  pileupQcutsPUTrackSelection_->setPV(pv);
322  pileupQcutsPUTrackSelection_->setLeadTrack(pfTau->leadPFChargedHadrCand());
323  }
324 
325  // Load the tracks if they are being used.
326  if ( includeTracks_ ) {
327  for( auto const & cand : pfTau->isolationPFChargedHadrCands() ) {
328  if ( qcuts_->filterCandRef(cand) ) {
329  LogTrace("discriminate") << "adding charged iso cand with pt " << cand->pt() ;
330  isoCharged_.push_back(cand);
331  }
332  }
333  }
334  if ( includeGammas_ || calculateWeights_ ) {
335  for( auto const & cand : pfTau->isolationPFGammaCands() ) {
336  if ( qcuts_->filterCandRef(cand) ) {
337  LogTrace("discriminate") << "adding neutral iso cand with pt " << cand->pt() ;
338  isoNeutral_.push_back(cand);
339  }
340  }
341  }
342 
345 
346  // If desired, get PU tracks.
347  if ( applyDeltaBeta_ || calculateWeights_) {
348  // First select by inverted the DZ/track weight cuts. True = invert
349  if ( verbosity_ ) {
350  std::cout << "Initial PFCands: " << chargedPFCandidatesInEvent_.size() << std::endl;
351  }
352 
353  std::vector<PFCandidatePtr> allPU =
354  pileupQcutsPUTrackSelection_->filterCandRefs(
355  chargedPFCandidatesInEvent_, true);
356 
357  std::vector<PFCandidatePtr> allNPU =
358  pileupQcutsPUTrackSelection_->filterCandRefs(
359  chargedPFCandidatesInEvent_);
360  LogTrace("discriminate") << "After track cuts: " << allPU.size() ;
361 
362  // Now apply the rest of the cuts, like pt, and TIP, tracker hits, etc
363  if(!useAllPFCands_){
364  std::vector<PFCandidatePtr> cleanPU =
365  pileupQcutsGeneralQCuts_->filterCandRefs(allPU);
366 
367  std::vector<PFCandidatePtr> cleanNPU =
368  pileupQcutsGeneralQCuts_->filterCandRefs(allNPU);
369 
370 
371  LogTrace("discriminate") << "After cleaning cuts: " << cleanPU.size() ;
372 
373 
374  // Only select PU tracks inside the isolation cone.
375  DRFilter deltaBetaFilter(pfTau->p4(), 0, deltaBetaCollectionCone_);
376  for(auto const & cand : cleanPU) {
377  if ( deltaBetaFilter(cand) ) isoPU_.push_back(cand);
378  }
379 
380  for(auto const & cand : cleanNPU) {
381  if ( deltaBetaFilter(cand) ) chPV_.push_back(cand);
382  }
383  LogTrace("discriminate") << "After cone cuts: " << isoPU_.size() << " " << chPV_.size() ;
384  }else{
385  isoPU_=allPU;
386  chPV_= allNPU;
387  }
388  }
389 
390  if (calculateWeights_)
391  {
392  for( auto const & isoObject : isoNeutral_ ) {
393  if(isoObject->charge() !=0){
394  // weight only neutral objects
395  isoNeutralWeight_.push_back(*isoObject);
396  continue;
397  }
398 
399  double eta=isoObject->eta();
400  double phi=isoObject->phi();
401  double sumNPU = 0.5*log(weightedSum(chPV_,eta,phi));
402 
403  double sumPU = 0.5*log(weightedSum(isoPU_,eta,phi));
404  PFCandidate neutral = *isoObject;
405  if (sumNPU+sumPU>0) neutral.setP4(((sumNPU)/(sumNPU+sumPU))*neutral.p4());
406 
407  isoNeutralWeight_.push_back(neutral);
408  }
409  }
410 
411  // Check if we want a custom iso cone
412  if ( customIsoCone_ >= 0. ) {
413  DRFilter filter(pfTau->p4(), 0, customIsoCone_);
414  DRFilter2 filter2(pfTau->p4(), 0, customIsoCone_);
415  std::vector<PFCandidatePtr> isoCharged_filter;
416  std::vector<PFCandidatePtr> isoNeutral_filter;
417  PFCandidateCollection isoNeutralWeight_filter;
418  // Remove all the objects not in our iso cone
419  for( auto const & isoObject : isoCharged_ ) {
420  if ( filter(isoObject) ) isoCharged_filter.push_back(isoObject);
421  }
422  if(!calculateWeights_){
423  for( auto const & isoObject : isoNeutral_ ) {
424  if ( filter(isoObject) ) isoNeutral_filter.push_back(isoObject);
425  }
426  isoNeutral_ = isoNeutral_filter;
427  }else{
428  for( auto const & isoObject : isoNeutralWeight_){
429  if ( filter2(isoObject) ) isoNeutralWeight_filter.push_back(isoObject);
430  }
431  isoNeutralWeight_ = isoNeutralWeight_filter;
432  }
433  isoCharged_ = isoCharged_filter;
434  }
435 
436  bool failsOccupancyCut = false;
437  bool failsSumPtCut = false;
438  bool failsRelativeSumPtCut = false;
439 
440 //--- nObjects requirement
441  int neutrals = isoNeutral_.size();
442 
443  if ( applyDeltaBeta_ ) {
444  neutrals -= TMath::Nint(deltaBetaFactorThisEvent_*isoPU_.size());
445  }
446  if ( neutrals < 0 ) {
447  neutrals = 0;
448  }
449 
450  size_t nOccupants = isoCharged_.size() + neutrals;
451 
452  failsOccupancyCut = ( nOccupants > maximumOccupancy_ );
453 
454  double totalPt = 0.0;
455  double puPt = 0.0;
456 //--- Sum PT requirement
457  if ( applySumPtCut_ || applyRelativeSumPtCut_ || storeRawSumPt_ || storeRawPUsumPt_ ) {
458  double chargedPt = 0.0;
459  double neutralPt = 0.0;
460  double weightedNeutralPt = 0.0;
461  for( auto const & isoObject : isoCharged_ ) {
462  chargedPt += isoObject->pt();
463  }
464  if(!calculateWeights_){
465  for( auto const & isoObject : isoNeutral_ ) {
466  neutralPt += isoObject->pt();
467  }
468  }else{
469  for( auto const & isoObject : isoNeutralWeight_){
470  weightedNeutralPt+=isoObject.pt();
471  }
472  }
473  for( auto const & isoObject : isoPU_ ) {
474  puPt += isoObject->pt();
475  }
476  LogTrace("discriminate") << "chargedPt = " << chargedPt ;
477  LogTrace("discriminate") << "neutralPt = " << neutralPt ;
478  LogTrace("discriminate") << "weighted neutral Pt = " << weightedNeutralPt ;
479  LogTrace("discriminate") << "puPt = " << puPt << " (delta-beta corr. = " << (deltaBetaFactorThisEvent_*puPt) << ")" ;
480  if( calculateWeights_) {
481  neutralPt = weightedNeutralPt;
482  }
483 
484  if ( applyDeltaBeta_ ) {
485  neutralPt -= deltaBetaFactorThisEvent_*puPt;
486  }
487 
488  if ( applyRhoCorrection_ ) {
489  neutralPt -= rhoThisEvent_;
490  }
491 
492  if ( neutralPt < 0.0 ) {
493  neutralPt = 0.0;
494  }
495 
496  totalPt = chargedPt + neutralPt;
497  LogTrace("discriminate") << "totalPt = " << totalPt << " (cut = " << maximumSumPt_ << ")" ;
498 
499  failsSumPtCut = (totalPt > maximumSumPt_);
500 
501 //--- Relative Sum PT requirement
502  failsRelativeSumPtCut = (totalPt > ((pfTau->pt() - offsetRelativeSumPt_)*maximumRelativeSumPt_));
503  }
504 
505  bool fails = (applyOccupancyCut_ && failsOccupancyCut) ||
506  (applySumPtCut_ && failsSumPtCut) ||
507  (applyRelativeSumPtCut_ && failsRelativeSumPtCut);
508 
509  // We did error checking in the constructor, so this is safe.
510  if ( storeRawSumPt_ ) {
511  return totalPt;
512  } else if ( storeRawPUsumPt_ ) {
513  if ( applyDeltaBeta_ ) return puPt;
514  else if ( applyRhoCorrection_ ) return rhoThisEvent_;
515  else return 0.;
516  } else if ( storeRawOccupancy_ ) {
517  return nOccupants;
518  } else {
519  return (fails ? 0. : 1.);
520  }
521 }
522 
#define LogDebug(id)
PFRecoTauDiscriminationByIsolation(const edm::ParameterSet &pset)
T getParameter(std::string const &) const
int i
Definition: DBlmapReader.cc:9
double weightedSum(std::vector< PFCandidatePtr > inColl_, double eta, double phi) const
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:250
std::auto_ptr< tau::RecoTauQualityCuts > pileupQcutsGeneralQCuts_
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:17
void beginEvent(const edm::Event &evt, const edm::EventSetup &evtSetup) override
bool exists(std::string const &parameterName) const
checks if a parameter exists
virtual void setP4(const LorentzVector &p4)
set 4-momentum
T eta() const
std::vector< PFCandidatePtr > pfCandidates(const PFJet &jet, int particleId, bool sort=true)
edm::EDGetTokenT< reco::PFCandidateCollection > pfCand_token
double deltaR2(const T1 &t1, const T2 &t2)
Definition: deltaR.h:36
std::vector< reco::PFCandidatePtr > chargedPFCandidatesInEvent_
std::pair< edm::ParameterSet, edm::ParameterSet > factorizePUQCuts(const edm::ParameterSet &inputSet)
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger but the state exists so we define the behavior If all triggers are the negative crieriion will lead to accepting the event(this again matches the behavior of"!*"before the partial wildcard feature was incorporated).The per-event"cost"of each negative criterion with multiple relevant triggers is about the same as!*was in the past
double discriminate(const PFTauRef &pfTau) const override
#define LogTrace(id)
std::auto_ptr< tau::RecoTauQualityCuts > qcuts_
std::auto_ptr< tau::RecoTauQualityCuts > pileupQcutsPUTrackSelection_
tuple out
Definition: dbtoconf.py:99
std::vector< reco::PFCandidate > PFCandidateCollection
collection of PFCandidates
ParameterSet const & getParameterSet(std::string const &) const
Particle reconstructed by the particle flow algorithm.
Definition: PFCandidate.h:39
std::auto_ptr< tau::RecoTauVertexAssociator > vertexAssociator_
tuple cout
Definition: gather_cfg.py:121
moduleLabel_(iConfig.getParameter< string >("@module_label"))
virtual const LorentzVector & p4() const
four-momentum Lorentz vector
Definition: LeafCandidate.h:99
edm::EDGetTokenT< reco::VertexCollection > vertex_token
tuple log
Definition: cmsBatch.py:347
Definition: DDAxes.h:10