ATLAS Offline Software
PseudoJetContainer.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // PseudoJetContainer.cxx
6 
10 #include <map>
11 #include "xAODJet/Jet.h"
12 #include "fastjet/PseudoJet.hh"
13 #include "JetRec/LineFormatter.h" // helper class for debug printing
14 #include <sstream>
15 #include <ios>
16 #include <iostream>
17 #include <exception>
18 
19 using fastjet::PseudoJet;
20 
22  checkInvariants("PseudoJetContainer()");
23 }
24 
25 PseudoJetContainer::PseudoJetContainer(std::unique_ptr<const IConstituentExtractor> c,
26  const std::vector<PseudoJet> & vecPJ,
27  bool debug){
28 
29  m_debug = debug;
30 
31  if (vecPJ.empty()){
32  m_emptyExtractors.insert(std::move(c));
33  return;
34  }
35 
36  if (m_debug){checkInConstituents(vecPJ, "constuctor");}
37  m_allConstituents = vecPJ;
38 
39  // the limits of the Extractor index range correposnd to the
40  // numbering of the EDM objects in th extractors.
41  m_extractorRanges.emplace_back(0,
42  vecPJ.back().user_index(),
43  std::move(c));
44  if (m_debug){checkInvariants("PseudoJetContainer(vcPJ, c)");}
45 }
46 
47 bool
49  const std::vector<PseudoJet>& inConstits) const
50 {
51 
52  // check container integrity if m_debug == true
53  if (m_debug){checkInvariants("extractConstituents()");}
54 
55  // set up mapping to acquire the EDM indices by Extractor
56  std::map<const IConstituentExtractor*, std::vector<int>> sorter;
57 
58  // add an entry into the sorter for each extractor.
59  // this way each extractor will be called, possibly with
60  // an empty index list - this will happen if no pseudojet correponding
61  // to the extractor is received. But an empty list is used
62  // by the extractors to fill zeros into the jet.
63  for(const auto& er : m_extractorRanges){
64  sorter.emplace(er.m_e.get(), std::vector<int>{});
65  }
66 
67  // see header file for explanation of empty extractors.
68  for(const auto& e : m_emptyExtractors){
69  sorter.emplace(e.get(), std::vector<int>{});
70  }
71 
72  // check whether inputs are lgal if m_debug == true
73  if (m_debug){checkInConstituents(inConstits, "extractConsituents()");}
74 
75  for (const auto& pj : inConstits){
76 
77  int pj_ind = pj.user_index();
78 
79  // fastjet clustering may add in pseudojets with the default (-1) index.
80  // ignore these.
81  if (pj_ind == -1) {continue;}
82 
83  // The index of the pseudojet and the low limit
84  // the extractorRange table (which acts as an offset), identifies which
85  // extractorRanges entry to use, and the EDM object that corrsponds to the
86  // pseudojet.
87 
88  auto e = std::find_if(m_extractorRanges.begin(),
89  m_extractorRanges.end(),
90  [pj_ind](const ExtractorRange& r){
91  return pj_ind >= r.m_lo and pj_ind <= r.m_hi;});
92 
93  if(e == m_extractorRanges.end()){return false;}
94 
95  sorter[(*e).m_e.get()].push_back(pj_ind - (*e).m_lo);
96  }
97 
98  // send the jet to the each extractor with a vector of EDM
99  // indices for that extractor
100  for(const auto& s : sorter){s.first -> addToJet(jet, s.second);}
101  return true;
102 }
103 
104 
105 // fill xAOD jet with constit&ghosts extracted from final PSeudoJet
107  const PseudoJet& finalPJ) const {
108 
109  std::vector<PseudoJet> inConstituents = finalPJ.constituents();
110  return extractConstituents(jet, inConstituents);
111 }
112 
113 // fill xAOD jet with correct by-vertex consituents and ghosts
115  std::vector<PseudoJet> allInConstituents = finalPJ.constituents();
116  std::vector<PseudoJet> byVertexConstituents;
117  for (PseudoJet& constituent: allInConstituents){
118  if (constituent.has_user_info<jet::VertexIndexedConstituentUserInfo>()){
119  const jet::VertexIndexedConstituentUserInfo& userInfo = constituent.user_info<jet::VertexIndexedConstituentUserInfo>();
120  const xAOD::Vertex* originVertex = userInfo.vertex();
121 
122  // if constituent has relevant user info, only accept it if it matches the vertex in question
123  if (originVertex == vertex){
124  byVertexConstituents.emplace_back(constituent);
125  }
126  }
127  else{
128  // this must be a ghost constituent, since it does not have userinfo
129  byVertexConstituents.emplace_back(constituent);
130  }
131  }
132  return extractConstituents(jet, byVertexConstituents);
133 }
134 
135 const std::vector<PseudoJet>* PseudoJetContainer::casVectorPseudoJet() const {
136  if (m_debug){checkInvariants("asVectorPseudoJet()");}
137  return &m_allConstituents;
138 }
139 
140 std::vector<PseudoJet>* PseudoJetContainer::casVectorPseudoJet() {
141  if (m_debug){checkInvariants("asVectorPseudoJet()");}
142  return &m_allConstituents;
143 }
144 
146  // Adds the extractors and pseudo jets for other to this container.
147 
148  // add the other extractor and its range to the ExtractorRanges table
149  int offset = m_extractorRanges.empty() ? 0 : m_extractorRanges.back().m_hi+1;
150 
151  std::transform(other->m_extractorRanges.begin(),
152  other->m_extractorRanges.end(),
153  std::back_inserter(m_extractorRanges),
154  [offset](const ExtractorRange& e){return e.bump(offset);});
155 
156  // copy over the pseudojets for the extractor being processed,
157  // and set the user index to match th extractorRange limits.
158 
159 
160  std::transform(other->m_allConstituents.begin(),
161  other->m_allConstituents.end(),
162  std::back_inserter(m_allConstituents),
163  [offset](fastjet::PseudoJet pj){
164  pj.set_user_index(pj.user_index() + offset);return pj;}
165  );
166 
167  for(const auto &e : other->m_emptyExtractors){m_emptyExtractors.emplace(e->clone());}
168 
169  if (m_debug){checkInvariants("append()");}
170 }
171 
172 std::string PseudoJetContainer::toString(int level, int extLevel) const {
173  std::ostringstream oss{"PseudoJetContainer at: ", std::ios::ate};
174  oss << this
175  << "\ndump levels: "<< level << " " << extLevel << '\n'
176  << " ExtractorRanges ranges: [" << m_extractorRanges.size() <<"] " ;
177  for(const auto& er : m_extractorRanges){
178  oss << "(" << er.m_lo << "," <<er.m_hi << "), ";
179  }
180 
181  oss << " empty extractors: " << m_emptyExtractors.size();
182  oss << " Pseudojets: " << m_allConstituents.size();
183 
184  if (level > 0){
185  oss << "\n Extractor dump: \n";
186  for(const auto& er : m_extractorRanges){
187  oss << "Extractor at [" ;
188  oss << er.m_e.get();
189  oss << "]\n";
190  oss << er.m_e->toString(extLevel) << '\n';
191  }
192  }
193 
194  if(level > 1){ oss << dumpPseudoJets();}
195 
196  return oss.str();
197 }
198 
200  std::ostringstream oss{"PseudoJetContainer at: ", std::ios::ate};
201  oss <<"\n PseudoJet energies\n";
202  for(const auto& p : m_allConstituents){
203  oss << "pseudojet user ind " << p.user_index()
204  << " E " << p.e() << " " << p.eta() << '\n';
205  }
206 
207  return oss.str();
208 }
209 
210 
211 bool PseudoJetContainer::checkInvariants(const std::string& from) const {
212 
213  if(!m_debug){return true;}
214 
215  std::ostringstream
216  oss("PseudoJetContainer checkInvariants called from: ",
217  std::ios::ate);
218  oss << from << " ";
219 
220  if (m_extractorRanges.empty()){
221  if(! m_allConstituents.empty()){
222  oss << "No extractors, but pseudojets present";
223  return bad_invariants_exit(oss);
224  }
225  return true;
226  }
227 
228  // have at least one extractor
229  // m_lo == m_hi possible if an empty EDM container has been read in.
230  for(const auto& ex : m_extractorRanges){
231  if (ex.m_lo < 0 or ex.m_lo > ex.m_hi){
232  oss << "bad extractor limits: " << ex.m_lo << " " << ex.m_hi;
233  return bad_invariants_exit(oss);
234  }
235  }
236 
237  // have at least one extractor with non-zero limits
238  auto npj = m_allConstituents.size();
239  auto uExtCount = (m_extractorRanges.back()).m_hi;
240  if (uExtCount < 0){
241  oss << " Illegal extractor range limit " << uExtCount;
242  return bad_invariants_exit(oss);
243  }
244 
245  std::size_t uuExtCount = uExtCount;
246 
247  //The user index for a pseudojet is an index into the EDM objet
248  // array. The comparison here is between th size of the PseudoJet
249  // array and the index of th EDM objects. When each EDM object
250  // gives rise to a PsedoJet, these numbers differ by 1.
251  // Not all EDM objcts give rise to a PseudoJet, so an inequality
252  // is tested here.
253  if (npj > uuExtCount + 1){
254  oss << " Mismatch between pseudo jet count/upper Extractor limit "
255  << npj << "/" << uuExtCount;
256  return bad_invariants_exit(oss);
257  }
258 
259  // have pseudoJets
260 
261  auto firstInd = m_allConstituents[0].user_index();
262  if (firstInd != 0){
263  oss << " first pseudojet does not have index 0 " << firstInd;
264  return bad_invariants_exit(oss);
265  }
266 
267  auto nent = m_extractorRanges.size();
268 
269  for (std::size_t i = 0; i < nent-1; ++i){
270  auto cur = m_extractorRanges[i];
271  auto next = m_extractorRanges[i+1];
272  if (cur.m_hi != next.m_lo - 1){
273  oss << "Hi limit for extractor " << i
274  << " != low limit for extractor " << i+1;
275  return bad_invariants_exit(oss);
276  }
277  }
278 
279  if(!checkPseudoJetVector(m_allConstituents, "checkInvariants()")) {
280  return bad_invariants_exit(oss);
281  }
282 
283  for(const auto& pj : m_allConstituents){
284  try{
285  pj.e();
286  } catch(...){
287  oss << "PseudoJet.e() fails of PJ in m_allConstituents";
288  return bad_invariants_exit(oss);
289  }
290  }
291 
292  for(const ExtractorRange& er : m_extractorRanges){
293  if (!((er.m_e)->checkIntegrity())){
294  oss << "IConstituentExtractor fails integrity test";
295  return bad_invariants_exit(oss);
296  }
297  }
298 
299  oss << "No of PseudoJets: "<< m_allConstituents.size()
300  << " No of Extractors " << m_extractorRanges.size() <<" all OK";
301 
302  return true;
303 }
304 
305 bool PseudoJetContainer::checkPseudoJetVector(const std::vector<PseudoJet>& v,
306  const std::string& from) const{
307 
308  // Pseudojets in th vector v contain the indices into the
309  // the EDM object vector held in the Extractors. If there is more than
310  // one extractor, an extractor dependent offset is added to index.
311  // The indices should be ordered, and start from a value >= 0.
312 
313  if(!m_debug){return true;}
314 
315  std::ostringstream
316  oss("PseudoJetContainer checkPseudoJetVector called from: ",
317  std::ios::ate);
318  oss << from << " ";
319 
320  if(v.empty()){
321  oss << "Empty pseudojet vector " ;
322  return true; // empty not a problem
323  }
324 
325  oss <<"PseudoJetVector energy dump:\n";
326  std::vector<float> energies;
327  energies.reserve(v.size());
328  std::transform(v.begin(),
329  v.end(),
330  std::back_inserter(energies),
331  [](const PseudoJet& p){return p.e();});
332 
333  LineFormatter formatter(10); // dump the energies, 10 values/line.
334  oss << formatter(energies);
335 
336 
337  bool ok{true};
338  if (v[0].user_index() < 0){
339  ok = false;
340  oss << "First pj has index < 0: " << v[0].user_index();
341  }
342 
343  std::vector<int> indices(v.size());
344  std::transform(v.begin(),
345  v.end(),
346  std::back_inserter(indices),
347  [](const PseudoJet & p){return p.user_index();});
348 
349  if(!std::is_sorted(indices.begin(), indices.end())){
350  oss << "Pseudojets out of order ";
351  ok = false;
352  }
353 
354  if(ok){oss << v.size() << " checked ok";}
355 
356  return ok;
357 }
358 
359 bool
360 PseudoJetContainer::checkInConstituents(const std::vector<PseudoJet>& v,
361  const std::string& from) const {
362 
363  if(!m_debug){return true;}
364 
365  std::ostringstream
366  oss("PseudoJetContainer checkInConstituents called from: ",
367  std::ios::ate);
368  oss << from << " ";
369  oss << v.size() << " entries\n";
370 
371  std::vector<double> energies;
372  energies.reserve(v.size());
373  std::transform(v.begin(),
374  v.end(),
375  std::back_inserter(energies),
376  [](const PseudoJet & p){return p.e();});
377 
378 
379  LineFormatter formatter(10); // dump the energies, 10 values/line.
380  oss << formatter(energies);
381 
382  for(const auto& pj: v){
383  if(pj.user_index() == -1){oss << "PJ index -1, E() " << pj.E() << '\n';}
384  }
385 
386  std::vector<int> indices;
387  indices.reserve(v.size());
388  std::transform(v.begin(),
389  v.end(),
390  std::back_inserter(indices),
391  [](const PseudoJet & p){return p.user_index();});
392 
393  oss <<"PseudoJet indices\n";
394  oss << formatter(indices);
395 
396 
397  std::map<int, int> counter;
398  if(!m_extractorRanges.empty()) {
399  int lo = m_extractorRanges[0].m_lo;
400  int hi = m_extractorRanges.back().m_hi;
401 
402  for (auto ind : indices){
403  // ind = -1 pseudojets can be produced by fastjet.
404  if (ind == -1){continue;}
405  if (ind < lo or ind > hi){++(counter[ind]);}
406  }
407  }
408 
409  bool bad = !counter.empty();
410 
411  if(bad){
412  oss <<"Out of range values[counts]: ";
413 
414  for(auto ent: counter){oss << ent.first << "/" << ent.second << '\n';}
415  oss << "Extractor ranges: \n";
416  for(const auto& er: m_extractorRanges){
417  oss << er.m_lo << " " << er.m_hi << '\n';
418  }
419 
420  bad_invariants_exit(oss);
421  }
422 
423 
424  return true;
425 }
426 
427 bool
428 PseudoJetContainer::bad_invariants_exit(const std::ostringstream& oss) const {
429 
430  auto errMsg = oss.str();
431 
432  if (m_debug) {
433  std::cerr << errMsg << '\n';
434  throw std::runtime_error(errMsg);
435  }
436 
437  return false;
438 }
439 
440 std::size_t PseudoJetContainer::size() const {
441  return m_allConstituents.size();
442 }
443 
444 bool PseudoJetContainer::debug() const{ return m_debug;}
446 std::ostream& operator << (std::ostream& os, const PseudoJetContainer& c){
447  os << c.toString(0);
448  return os;
449 }
bad
@ bad
Definition: SUSYToolsTester.cxx:100
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
PseudoJetContainer::ExtractorRange
Definition: PseudoJetContainer.h:105
beamspotman.r
def r
Definition: beamspotman.py:676
PseudoJetContainer::bad_invariants_exit
bool bad_invariants_exit(const std::ostringstream &) const
Definition: PseudoJetContainer.cxx:428
VertexIndexedConstituentUserInfo.h
Jet.h
operator<<
std::ostream & operator<<(std::ostream &os, const PseudoJetContainer &c)
Definition: PseudoJetContainer.cxx:446
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
PseudoJetContainer::m_allConstituents
std::vector< PseudoJet > m_allConstituents
Definition: PseudoJetContainer.h:96
PseudoJetContainer::checkPseudoJetVector
bool checkPseudoJetVector(const std::vector< PseudoJet > &, const std::string &) const
Definition: PseudoJetContainer.cxx:305
jet::VertexIndexedConstituentUserInfo::vertex
const xAOD::Vertex * vertex() const
Returns the associated vertex if this constit is a track. Else returns null. *‍/.
Definition: VertexIndexedConstituentUserInfo.h:28
beamspotman.cur
def cur
Definition: beamspotman.py:671
PseudoJetContainer::m_debug
bool m_debug
Definition: PseudoJetContainer.h:148
IConstituentExtractor.h
Trk::indices
std::pair< long int, long int > indices
Definition: AlSymMatBase.h:24
LineFormatter.h
postInclude.sorter
sorter
Definition: postInclude.SortInput.py:23
PseudoJetContainer
Definition: PseudoJetContainer.h:48
PseudoJetContainer::checkInvariants
bool checkInvariants(const std::string &) const
Definition: PseudoJetContainer.cxx:211
python.iconfTool.models.loaders.level
level
Definition: loaders.py:20
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
jet
Definition: JetCalibTools_PlotJESFactors.cxx:23
PseudoJetContainer::PseudoJet
fastjet::PseudoJet PseudoJet
Definition: PseudoJetContainer.h:50
PseudoJetContainer::m_extractorRanges
std::vector< ExtractorRange > m_extractorRanges
Definition: PseudoJetContainer.h:140
fillPileUpNoiseLumi.next
next
Definition: fillPileUpNoiseLumi.py:52
lumiFormat.i
int i
Definition: lumiFormat.py:85
Amg::transform
Amg::Vector3D transform(Amg::Vector3D &v, Amg::Transform3D &tr)
Transform a point from a Trasformation3D.
Definition: GeoPrimitivesHelpers.h:156
jet::VertexIndexedConstituentUserInfo
Definition: VertexIndexedConstituentUserInfo.h:16
PseudoJetContainer::toString
std::string toString(int level, int extLevel=0) const
Definition: PseudoJetContainer.cxx:172
PseudoJetContainer::extractConstituents
bool extractConstituents(xAOD::Jet &, const std::vector< PseudoJet > &) const
Definition: PseudoJetContainer.cxx:48
PseudoJetContainer::append
void append(const PseudoJetContainer *)
Definition: PseudoJetContainer.cxx:145
ReadFromCoolCompare.os
os
Definition: ReadFromCoolCompare.py:231
PseudoJetContainer::debug
bool debug() const
Definition: PseudoJetContainer.cxx:444
PseudoJetContainer::PseudoJetContainer
PseudoJetContainer()
Definition: PseudoJetContainer.cxx:21
PseudoJetContainer::m_emptyExtractors
std::set< std::unique_ptr< const IConstituentExtractor > > m_emptyExtractors
Definition: PseudoJetContainer.h:146
debug
const bool debug
Definition: MakeUncertaintyPlots.cxx:53
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
vtune_athena.formatter
formatter
Definition: vtune_athena.py:19
LineFormatter
Definition: LineFormatter.h:14
python.PyAthena.v
v
Definition: PyAthena.py:154
xAOD::Jet_v1
Class describing a jet.
Definition: Jet_v1.h:57
Trk::vertex
@ vertex
Definition: MeasurementType.h:21
PseudoJetContainer.h
InDetDD::other
@ other
Definition: InDetDD_Defs.h:16
xAOD::Vertex_v1
Class describing a Vertex.
Definition: Vertex_v1.h:42
PseudoJetContainer::size
std::size_t size() const
Definition: PseudoJetContainer.cxx:440
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
PseudoJetContainer::casVectorPseudoJet
const std::vector< PseudoJet > * casVectorPseudoJet() const
Definition: PseudoJetContainer.cxx:135
PseudoJetContainer::dumpPseudoJets
std::string dumpPseudoJets() const
Definition: PseudoJetContainer.cxx:199
PseudoJetContainer::checkInConstituents
bool checkInConstituents(const std::vector< PseudoJet > &, const std::string &) const
Definition: PseudoJetContainer.cxx:360
test_pyathena.counter
counter
Definition: test_pyathena.py:15
python.compressB64.c
def c
Definition: compressB64.py:93
PseudoJetContainer::extractByVertexConstituents
bool extractByVertexConstituents(xAOD::Jet &jet, const PseudoJet &finalPJ, const xAOD::Vertex *vertex) const
Definition: PseudoJetContainer.cxx:114
checkFileSG.ind
list ind
Definition: checkFileSG.py:118