Belle II Software development
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
24namespace 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
std::vector< FullSecID > getAllFullSecIDsOfSensor(VxdID sensor)
returns a Vector containing all FullSecIDs found for given sensor.
Definition: SectorGraph.h:300
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
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
const std::vector< FilterType > & getFilterTypes() const
returns a const reference to the filterTypes stored in this graph
Definition: SectorGraph.h:314
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.