Belle II Software  release-08-01-10
SectorGraph.h
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 #pragma once
10 
11 #include <framework/logging/Logger.h>
12 #include <tracking/trackFindingVXD/sectorMapTools/SubGraphID.h>
13 #include <tracking/trackFindingVXD/sectorMapTools/SubGraph.h>
14 
15 #include <iostream>
16 #include <fstream>
17 #include <string>
18 #include <vector>
19 #include <unordered_map>
20 #include <utility> // std::pair, std::move
21 #include <TH1.h>
22 
23 
24 namespace Belle2 {
31  template<class FilterType> class SectorGraph {
32  protected:
33  std::unordered_map<SubGraphID, SubGraph<FilterType>> m_subgraphs;
35  std::vector<FilterType> m_filterIDs;
36  public:
37 
39  explicit SectorGraph(const std::vector<FilterType>& fIDs) : m_filterIDs(fIDs)
40  { if (m_filterIDs.empty()) { B2FATAL("SectorGraph-constructor: passed filterIDs are empty, this is an illegal usage of this class!"); } }
41 
43  using Iterator = typename std::unordered_map<SubGraphID, SubGraph<FilterType>>::iterator;
44 
46  Iterator find(SubGraphID idChain) { return m_subgraphs.find(idChain); }
47 
49  Iterator begin() { return m_subgraphs.begin(); }
50 
52  Iterator end() { return m_subgraphs.end(); }
53 
55  unsigned size() const { return m_subgraphs.size(); }
56 
58  unsigned long nFoundTotal() const
59  {
60  unsigned long nFound = 0;
61  for (auto& pack : m_subgraphs) { nFound += pack.second.getFound(); }
62  return nFound;
63  }
64 
67  {
68  if (m_subgraphs.find(newID) != end())
69  { B2WARNING("SectorGraph::add: given ID " << newID.print() << " is already in graph, not added again..."); return end(); }
70  std::pair<Iterator, bool> pos = m_subgraphs.insert({newID, SubGraph<FilterType>(newID, m_filterIDs)});
71  B2DEBUG(20, "SectorGraph::add: new subgraph added: " << pos.first->second.print());
72  return pos.first;
73  }
74 
76  std::string print(bool fullPrint = true) const
77  {
78  unsigned nSubgraphs = m_subgraphs.size();
79  std::string out = "graph has got " + std::to_string(nSubgraphs) + " entries:\n";
80  out += "now printing " + (fullPrint ? std::string("full") : std::string("short version of the")) + " graph:\n";
81  for (const auto& entry : m_subgraphs) {
82  if (!fullPrint and nSubgraphs % 100 != 0) continue; // printing only 100 subgraphs of mainGraph for the short version.
83  out += entry.second.print() + "\n";
84  }
85  return out;
86  }
87 
89  unsigned pruneGraph(double rarenessCut)
90  {
91  //sanity checks:
92  if (rarenessCut < 0 or rarenessCut >= 1)
93  { B2WARNING("pruneGraph: rarenessCut is rubbish: " << rarenessCut << ", stopping prune-process."); return 0; }
94  if (rarenessCut == 0) { B2DEBUG(20, "pruneGraph: nothing to be done, stopping prune-process."); return 0; }
95 
97  // .first counts total number of occurances of branches of this trunk (= outer sector(s))
98  // .second is a vector of pointers to the subgraphs of that trunk.
99  std::vector< std::pair<unsigned, std::vector<SubGraph<FilterType>*> >> trunks;
100 
101  // find those sharing a trunk (trunkTotal) and cluster them in these trunks:
102  for (auto& subGraphEntry : m_subgraphs) {
103  SubGraph<FilterType>& graph = subGraphEntry.second;
104  bool found = false;
105  for (auto& trunk : trunks) {
106  if (graph.checkSharesTrunk(*(trunk.second.at(0)))) {
107  trunk.first += graph.getFound();
108  trunk.second.push_back(&graph);
109  found = true;
110  continue;
111  }
112 
113  if (found) continue;
114  // this should really be avoided but it in this case it seems to be on purpose (push_back to container that is iterated)
115  // tell cppcheck it is fine..
116  // cppcheck-suppress invalidContainerLoop
117  trunks.push_back({graph.getFound(), {&graph} });
118  }
119  }
120 
121  unsigned long nFoundB4 = nFoundTotal(), nKilled = 0;
122  unsigned sizeb4 = size();
123  B2DEBUG(20, "pruneGraph - before pruning: graph of size " << sizeb4 << " has " << trunks.size() << " trunks with " << nFoundB4 <<
124  " total found.");
125 
126  // collect subGraphs (=branches) to be deleted:
127  std::vector<SubGraph<FilterType>*> deadBranches;
128  for (auto& trunk : trunks) {
129  double trunkCut = rarenessCut * double(trunk.first);
130 
131  // sort branches of trunk by rareness (rarest one first):
132  std::sort(trunk.second.begin(),
133  trunk.second.end(),
134  [](const SubGraph<FilterType>* a, const SubGraph<FilterType>* b)
135  -> bool { return a->getFound() < b->getFound(); });
136 
137  // skip trunk, if there are no rare branches.
138  auto pos = trunk.second.begin();
139  if (double((**pos).getFound()) >= trunkCut) continue;
140 
141  // collect branches to be killed starting with the smallest one and stop when reaching those which have been slipping above the threshold in the process:
142  while (pos != trunk.second.end()) {
143  // mark the most rarest entry:
144  deadBranches.push_back(*pos);
145  trunkCut -= double((**pos).getFound()) * rarenessCut;
146 
147  // reached the point when all graphs left are now good enough for us: -> stopping loop.
148  if (double((**pos).getFound()) >= trunkCut) break;
149  ++pos;
150  }
151  } // looping over trunks
152 
153  if (deadBranches.empty()) { B2DEBUG(20, "pruneGraph: no rare branches found - stopping pruning process."); return 0; }
154 
155  // kill selected ones:
156  for (auto* graph : deadBranches) {
157  nKilled += graph->getFound();
158  m_subgraphs.erase(graph->getID());
159  }
160 
161  B2DEBUG(20, "pruneGraph - after pruning graph with size (before/after " << sizeb4 << "/" << size() <<
162  ") and nFound (before/after/killed " << nFoundB4 << "/" << nFoundTotal() << "/" << nKilled);
163 
164  return nKilled;
165  }
166 
168  int getAbsThreshold(int relThreshold)
169  {
170  if (relThreshold == 0) {return 0;}
171  B2INFO("Relative threshold : " << relThreshold << " %");
172  int xmax = 100000;
173 
174  TH1D* h_nfound = new TH1D("h", "# times that subgraphs were found n_found times", xmax, 0, xmax);
175 
176  for (auto& subGraphEntry : m_subgraphs) {
177  SubGraph<FilterType>& graph = subGraphEntry.second;
178  h_nfound->Fill(graph.getFound());
179  }
180 
181  if (h_nfound->GetEntries() == 0) {
182  B2ERROR("nfound histogram empty.");
183  delete h_nfound;
184  return 0;
185  }
186 
187  TH1* hc_nfound = h_nfound->GetCumulative();
188  hc_nfound->Scale(1 / h_nfound->GetEntries());
189 
190  for (int nfound = 1; nfound < hc_nfound->GetNbinsX(); nfound++) {
191  if (hc_nfound->GetBinContent(nfound) > relThreshold / 100.) {
192  B2INFO("Absolute threshold : remove every graph with nfound < " << nfound);
193  delete h_nfound;
194  delete hc_nfound;
195  return nfound;
196  }
197  }
198 
199  // In case no value for nfound is found
200  B2ERROR("No nfound value found.");
201  delete h_nfound;
202  delete hc_nfound;
203  return 0;
204  }
205 
207  unsigned pruneGraphBeforeTraining(int absThreshold)
208  {
209  if (absThreshold == 0) {return 0;}
210 
211  int killed = 0;
212 
213  std::vector<SubGraph<FilterType>*> deadBranches;
214 
215  for (auto& subGraphEntry : m_subgraphs) {
216  SubGraph<FilterType>& graph = subGraphEntry.second;
217  if (int(graph.getFound()) <= absThreshold) {
218  deadBranches.push_back(&graph);
219  }
220  }
221 
222  for (auto& graph : deadBranches) {
223  m_subgraphs.erase(graph->getID());
224  killed ++;
225  }
226 
227  return killed;
228  }
229 
232  {
233  std::ofstream out;
234  out.open("output_nfound.txt");
235  for (auto& subGraphEntry : m_subgraphs) {
236  SubGraph<FilterType>& graph = subGraphEntry.second;
237  out << graph.print() << std::endl;
238  }
239  out.close();
240  }
241 
246  {
247  unsigned nUpdated = 0, // counts sectors which shall be updated
248  nFound = 0, // counts sectors which were found (without double entry removal)
249  nGraphsUpdated = 0; // counts graphs which were updated
250 
251  // collects the secIDs which have got inner sectors on same sensor:
252  std::vector<unsigned> idsFound;
253  std::string idsPrinted;
254 
255  // collect all SecIDs where SubLayer has to be updated.
256  for (auto& subGraphEntry : m_subgraphs) {
257  SubGraphID graphID = subGraphEntry.second.getID();
258  std::vector<unsigned> found = graphID.hasSharedLayer();
259  if (found.empty()) continue;
260  idsFound.insert(idsFound.end(), found.begin(), found.end());
261  }
262  for (unsigned id : idsFound) { idsPrinted += FullSecID(id).getFullSecString() + " "; }
263  B2DEBUG(20, "updateSubLayerIDs: before unique of found ids, following IDs are recorded: \n" << idsPrinted);
264  nFound += idsFound.size();
265  std::sort(idsFound.begin(), idsFound.end());
266  idsFound.erase(std::unique(idsFound.begin(), idsFound.end()), idsFound.end());
267  nUpdated += idsFound.size();
268 
269  idsPrinted = "";
270  for (unsigned id : idsFound) { idsPrinted += FullSecID(id).getFullSecString() + " "; }
271  B2DEBUG(20, "updateSubLayerIDs: before updating Subgraphs, following IDs have to be updated: \n" << idsPrinted);
272 
273 
274  // update all subGraphIDs where subLayerID has to be increased:
275  for (auto& subGraphEntry : m_subgraphs) {
276  SubGraph<FilterType>& graph = subGraphEntry.second;
277  unsigned nSecsUpdated = graph.idCheckAndUpdate(idsFound);
278  if (nSecsUpdated == 0) {
279  B2DEBUG(25, "updateSubLayerIDs: was _not_ updated: " << graph.getID().print());
280  continue;
281  }
282  nGraphsUpdated++;
283  B2DEBUG(25, "updateSubLayerIDs: was updated " << nSecsUpdated << " times: " << graph.getID().print());
284  }
285 
286  B2DEBUG(20, "updateSubLayerIDs: nSectors found/updated: " << nFound << "/" << nUpdated << ", nSubgraphs updated: " <<
287  nGraphsUpdated);
288 
289  // create new map of Subgraphs with updated LayerIDs
290  // subGraph: copy with updated iD.
291  // SubGraphID: a.isElementOf(SubGraphID& b) <- checks if given sectorPack ( >= 1 sector) is part of a, ignores subLayerID.
292  // SubGraphID: a.replaceElement(SubGraphID& b) <- checks if given sectorPack ( >= 1 sector) is part of a, ignores subLayerID. if yes, replaces element(s). WARNING only works with complete replacement of SubGraphID (entries are const).
293  // SubGraphID: a.areTheSameSectors(SubGraphID& b) <- checks if sectors are identical (while ignoring the subLayerID)
294  // SubGraphID: a.sharesLayer() <- returns IDs of entries being inner friend of sectors on same layer.
295 
296  // return new map of Subgraphs.
297  }
298 
300  std::vector<FullSecID> getAllFullSecIDsOfSensor(VxdID sensor)
301  {
302  std::vector<FullSecID> foundIDs;
303 
304  for (auto& subGraph : m_subgraphs) {
305  std::vector<FullSecID> sectorsFound = subGraph.second.getSectorsOfSensor(sensor);
306  if (sectorsFound.empty()) continue;
307  foundIDs.insert(foundIDs.end(), sectorsFound.begin(), sectorsFound.end());
308  }
309  B2DEBUG(20, "getAllFullSecIDsOfSensor: VxdID " << sensor << " has " << foundIDs.size() << " sectors in this graph");
310  return foundIDs;
311  }
312 
314  const std::vector<FilterType>& getFilterTypes() const { return m_filterIDs; }
315  };
317 }
318 
Class to identify a sector inside of the VXD.
Definition: FullSecID.h:33
std::string getFullSecString() const
returns the FullSecID coded as string compatible to secIDs stored in the xml-sectormaps
Definition: FullSecID.cc:116
contains all subgraphs.
Definition: SectorGraph.h:31
unsigned size() const
returns number of collected subgraphs so far.
Definition: SectorGraph.h:55
SectorGraph(const std::vector< FilterType > &fIDs)
constructor expects filterIDs.
Definition: SectorGraph.h:39
Iterator begin()
returns begin of subGraphs.
Definition: SectorGraph.h:49
Iterator find(SubGraphID idChain)
find entry.
Definition: SectorGraph.h:46
Iterator add(SubGraphID &newID)
add new subgraph if not added already.
Definition: SectorGraph.h:66
const std::vector< FilterType > & getFilterTypes() const
returns a const reference to the filterTypes stored in this graph
Definition: SectorGraph.h:314
void updateSubLayerIDs()
finds sectors having inner sectors in same layer and update them in the subGraph-ID.
Definition: SectorGraph.h:245
std::string print(bool fullPrint=true) const
returns a string giving an overview of the graph.
Definition: SectorGraph.h:76
std::vector< FilterType > m_filterIDs
ids of all filterTypes to be stored by subGraphs.
Definition: SectorGraph.h:35
Iterator end()
returns end of subGraphs.
Definition: SectorGraph.h:52
typename std::unordered_map< SubGraphID, SubGraph< FilterType > >::iterator Iterator
for better readability.
Definition: SectorGraph.h:43
std::vector< FullSecID > getAllFullSecIDsOfSensor(VxdID sensor)
returns a Vector containing all FullSecIDs found for given sensor.
Definition: SectorGraph.h:300
unsigned pruneGraphBeforeTraining(int absThreshold)
returns removed occurances.
Definition: SectorGraph.h:207
int getAbsThreshold(int relThreshold)
Get the absolute treshold (# nfound) given a relative threshold.
Definition: SectorGraph.h:168
void output_nfound()
Output in a txt file id & nfound of subgraphs.
Definition: SectorGraph.h:231
std::unordered_map< SubGraphID, SubGraph< FilterType > > m_subgraphs
contains all subgraphs.
Definition: SectorGraph.h:33
unsigned pruneGraph(double rarenessCut)
returns removed occurances.
Definition: SectorGraph.h:89
unsigned long nFoundTotal() const
returns number of occurances for all subGraphs found together.
Definition: SectorGraph.h:58
stores the ID of a subgraph, which is basically a chain of FullSecID coded as unsigned ints.
Definition: SubGraphID.h:24
std::vector< unsigned > hasSharedLayer() const
returns raw IDs of entries being outer friend of sectors on same layer.
Definition: SubGraphID.h:153
std::string print() const
returns string of entries.
Definition: SubGraphID.h:101
contains all relevant stuff needed for dealing with a subGraph.
Definition: SubGraph.h:30
bool checkSharesTrunk(const SubGraph< FilterType > &b) const
if both graphs have got the same IDs except the last one, they share a trunk.
Definition: SubGraph.h:80
unsigned getFound() const
returns found-counter.
Definition: SubGraph.h:77
const SubGraphID & getID() const
returns iD of this graph
Definition: SubGraph.h:93
unsigned idCheckAndUpdate(const std::vector< unsigned > &ids)
for given vector of ids check if any of them is part of subGraphID. If yes, update their SubLayerID....
Definition: SubGraph.h:137
std::string print() const
"print" debugging information to a string
Definition: SubGraph.h:83
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:33
Abstract base class for different kinds of events.