Belle II Software  release-05-02-19
WireEfficiencyAlgorithm.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Henrikas Svidras, Makoto Uchida *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <cdc/calibration/WireEfficiencyAlgorithm.h>
12 
13 #include <calibration/CalibrationAlgorithm.h>
14 
15 #include <tracking/trackFindingCDC/topology/CDCWireTopology.h>
16 #include <tracking/trackFindingCDC/topology/CDCWireLayer.h>
17 
18 #include <cdc/geometry/CDCGeometryPar.h>
19 #include <cdc/dbobjects/CDCBadWires.h>
20 
21 #include <framework/database/IntervalOfValidity.h>
22 #include <framework/logging/Logger.h>
23 
24 #include <TH2F.h>
25 #include <TFitResult.h>
26 #include <TH1F.h>
27 #include <TF1.h>
28 #include <TGraphAsymmErrors.h>
29 #include <TMath.h>
30 #include <math.h>
31 
32 using namespace Belle2;
33 using namespace CDC;
34 using namespace TrackFindingCDC;
36 {
37 
39  " -------------------------- Wire Efficiency Estimation Algorithm -------------------------\n"
40  );
41 }
42 
44 {
45  B2INFO("Creating efficiencies for every layer");
46 
47  unsigned short wireID;
48  unsigned short layerID;
49  float z;
50  bool isFound;
51 
52  auto efftree = getObjectPtr<TTree>("efftree");
53  efftree->SetBranchAddress("wireID", &wireID);
54  efftree->SetBranchAddress("layerID", &layerID);
55  efftree->SetBranchAddress("z", &z);
56  efftree->SetBranchAddress("isFound", &isFound);
57 
58  // Set ranges and names for the TEfficiency objects
59  B2INFO("Building empty efficiency objects");
60  static const CDCWireTopology& wireTopology = CDCWireTopology::getInstance();
61  B2INFO("Wire Topology found");
62  static const CDCGeometryPar& cdcgeo = CDCGeometryPar::Instance();
63  B2INFO("CDC Geometry found");
64 
65  for (const CDCWireLayer& wireLayer : wireTopology.getWireLayers()) {
66  unsigned short layerNo = wireLayer.getICLayer();
67  B2INFO("Got layer " << layerNo);
68  std::string m_nameOfLayer = std::string("effLayer_").append(std::to_string(layerNo));
69  std::string m_titleOfLayer = std::string("Efficiency of wires in layer ").append(std::to_string(layerNo));
70  B2INFO("Built names for " << layerNo);
71 
72  unsigned short nzbins = 30 - layerNo / 7;
73  unsigned short nwidbins = cdcgeo.nWiresInLayer(layerNo);
74  double widbins[2] = { -0.5, cdcgeo.nWiresInLayer(layerNo) - 0.5};
75  double zbins[2] = {wireLayer.getBackwardZ(), wireLayer.getForwardZ()};
76 
77  B2INFO("Built bins for " << layerNo);
78 
79  TEfficiency* effInLayer = new TEfficiency(m_nameOfLayer.c_str(), m_titleOfLayer.c_str(), nzbins, zbins[0], zbins[1], nwidbins,
80  widbins[0], widbins[1]);
81  B2INFO("TEfficiency for " << layerNo << "successfully built");
82 
83  m_efficiencyList->Add(effInLayer);
84  B2INFO("Teff for layer " << layerNo << " was sucessfully listed.");
85  }
86  TFile* outputCollection = new TFile("LayerEfficiencies.root", "RECREATE");
87 
88  // loop over entries in the tree and build the TEfficiencies
89  B2INFO("Filling the efficiencies");
90  const Long64_t nEntries = efftree->GetEntries();
91  B2INFO("Number of entries in tree: " << nEntries;);
92  for (Long64_t i = 0; i < nEntries; i++) {
93  efftree->GetEntry(i);
94  TEfficiency* efficiencyInLayer = (TEfficiency*)m_efficiencyList->At(layerID);
95  efficiencyInLayer->Fill(isFound, z, wireID);
96  }
97  m_efficiencyList->Write();
98  B2INFO("TEfficiencies successfully filled.");
99  outputCollection->Close();
100  B2INFO("TEfficiencies successfully saved");
101  // setting 1000 entries as the minimum value to consider "enough data", but this might need to be tailored in the future.
102  if (nEntries > 1000) return true;
103  else return false;
104 }
105 
107 {
108  B2INFO("Beginning detection of bad wires");
109  static const CDCWireTopology& wireTopology = CDCWireTopology::getInstance();
110  B2INFO("Wire Topology found");
111 
112  for (const CDCWireLayer& wireLayer : wireTopology.getWireLayers()) {
113  unsigned short layerNo = wireLayer.getICLayer();
114  B2INFO("Checking layer " << layerNo);
115 
116  // need to use casting here because GetPassedHistogram assumes it returns TH1
117  auto efficiencyInLayer = (TEfficiency*)m_efficiencyList->At(layerNo);
118  auto passed = (TH2F*)efficiencyInLayer->GetPassedHistogram();
119  auto total = (TH2F*)efficiencyInLayer->GetTotalHistogram();
120 
121  // Ignoring layers that have no hits at all
122  if (!total->GetEntries()) continue;
123 
124  // prepare fitting functions
125  double minFitRange = wireLayer.getBackwardZ() + 30;
126  double maxFitRange = wireLayer.getForwardZ() - 30;
127  TF1* constantFunction = new TF1("constantFunction", "pol0", minFitRange, maxFitRange);
128 
129  // Estimate average efficiency of the layer as function of z
130  auto passedProjectedX = passed->ProjectionX("projectionx1");
131  auto totalProjectedX = total->ProjectionX("projectionx2");
132  TEfficiency* efficiencyProjectedX = new TEfficiency(*passedProjectedX, *totalProjectedX);
133 
134  unsigned short minFitBin = passedProjectedX->FindBin(minFitRange) + 1;
135  unsigned short maxFitBin = passedProjectedX->FindBin(maxFitRange) - 1;
136 
137  // Estimate average efficiency of each wire in the layer
138  auto passedProjectedY = passed->ProjectionY("projectiony1", minFitRange, maxFitRange);
139  auto totalProjectedY = total->ProjectionY("projectiony2", minFitRange, maxFitRange);
140  TEfficiency* efficiencyProjectedY = new TEfficiency(*passedProjectedY, *totalProjectedY);
141 
142  // Estimate average efficiency of the whole layer by summing up averages of individual wires
143  float totalAverage = 0;
144  int nonZeroWires = 0;
145  for (int i = 0; i <= passedProjectedY->GetNbinsX(); ++i) {
146  float efficiencyAtBin = efficiencyProjectedY->GetEfficiency(i);
147  if (efficiencyAtBin > 0.4) {
148  totalAverage += efficiencyAtBin;
149  nonZeroWires++;
150  }
151  }
152  // safeguard in case all wires are 0
153  nonZeroWires > 0 ? totalAverage /= nonZeroWires : totalAverage == 0;
154 
155  TGraphAsymmErrors* graphEfficiencyProjected = efficiencyProjectedX->CreateGraph();
156 
157  B2INFO("Successfully determined average properties of layer " << layerNo);
158  B2INFO("Looping over wires");
159 
160  // Due to the way histograms are binned, every bin center should correspond a wire ID.
161  for (int i = 0; i <= passed->GetNbinsY(); ++i) {
162 
163  // project out 1 wire
164  auto singleWirePassed = passed->ProjectionX("single wire projection passed", i, i);
165  auto singleWireTotal = total->ProjectionX("single wire projection total", i, i);
166 
167  // if not a single hit within the central area of wire then mark it as bad
168  if (!singleWirePassed->Integral(minFitBin, maxFitBin)) {
169  double wireID = passed->GetYaxis()->GetBinCenter(i);
170  m_badWireList->setWire(layerNo, round(wireID), 0);
171  continue;
172  }
173  // constructs efficiency of one wire
174  TEfficiency* singleWireEfficiency = new TEfficiency(*singleWirePassed, *singleWireTotal);
175  TGraphAsymmErrors* graphSingleWireEfficiency = singleWireEfficiency->CreateGraph();
176 
177  // fits the efficiency with a constant
178  TFitResultPtr singleWireFitResults = graphSingleWireEfficiency->Fit(constantFunction, "SQR");
179  double singleWireEfficiencyFromFit = (singleWireFitResults.Get())->Value(0);
180  double singleWireUpErrorFromFit = (singleWireFitResults.Get())->UpperError(0);
181 
182  // applies a chi test on the wire
183  float p_value = chiTest(graphSingleWireEfficiency, graphEfficiencyProjected, minFitRange, maxFitRange);
184  // check three conditions and decide if wire should be marked as bad
185  bool averageCondition = (0.95 * totalAverage) > (singleWireEfficiencyFromFit + 5 * singleWireUpErrorFromFit);
186  bool pvalueCondition = p_value < 0.01;
187  bool generalCondition = singleWireEfficiencyFromFit < 0.4;
188  if (generalCondition || (averageCondition && pvalueCondition)) {
189  double wireID = passed->GetYaxis()->GetBinCenter(i);
190  m_badWireList->setWire(layerNo, round(wireID), singleWireEfficiencyFromFit);
191  }
192  }
193  B2INFO("Bad wires for " << layerNo << " recorded");
194  }
195  m_badWireList->outputToFile("wireFile.txt");
196  saveCalibration(m_badWireList, "CDCBadWires");
197  B2INFO("Bad wire list sucessfully saved.");
198 }
199 
200 double WireEfficiencyAlgorithm::chiTest(TGraphAsymmErrors* graph1, TGraphAsymmErrors* graph2, double minValue, double maxValue)
201 {
202 
203  // Vars to perform the chi test
204  double chi = 0;
205  unsigned short ndof = 0;
206 
207 
208  int numOfEntries1 = graph1->GetN();
209  int numOfEntries2 = graph2->GetN();
210 
211  // loop over entries in both graphs, index by index.
212 
213  for (int index1 = 0; index1 < numOfEntries1; ++index1) {
214  // TGraph values are usually not listed in increasing order. Need to check that they are within min/max range for comparison.
215  if (graph1->GetX()[index1] < minValue) continue;
216  if (graph1->GetX()[index1] > maxValue) continue;
217  for (int index2 = 0; index2 < numOfEntries2; ++index2) {
218  if (graph1->GetX()[index1] == graph2->GetX()[index2]) {
219  // this is broken up just for readability
220  double chiNumerator = pow(graph1->GetY()[index1] - graph2->GetY()[index2], 2);
221  double chiDenominator = pow(graph1->GetErrorYhigh(index1), 2) + pow(graph1->GetErrorYlow(index1), 2);
222  chi += chiNumerator / chiDenominator;
223  ndof++;
224  continue;
225  }
226  }
227  }
228  return TMath::Prob(chi, ndof);
229 }
230 
232 {
233  const auto exprun = getRunList()[0];
234  B2INFO("ExpRun used for DB Geometry : " << exprun.first << " " << exprun.second;);
235  updateDBObjPtrs(1, exprun.second, exprun.first);
236 
237  B2INFO("Creating CDCGeometryPar object");
239 
240  bool enoughEventsInInput;
241  enoughEventsInInput = buildEfficiencies();
242 
243  detectBadWires();
244 
245  if (enoughEventsInInput) return c_OK;
246  else return c_NotEnoughData;
247 }
Belle2::CDC::WireEfficiencyAlgorithm::WireEfficiencyAlgorithm
WireEfficiencyAlgorithm()
Constructor.
Definition: WireEfficiencyAlgorithm.cc:35
Belle2::CalibrationAlgorithm::saveCalibration
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
Definition: CalibrationAlgorithm.cc:290
Belle2::CDC::WireEfficiencyAlgorithm::calibrate
EResult calibrate() override
Run algo on data.
Definition: WireEfficiencyAlgorithm.cc:231
Belle2::CDC::WireEfficiencyAlgorithm::buildEfficiencies
bool buildEfficiencies()
create 2D TEfficiency for each wire and return True if more than 1000 entries
Definition: WireEfficiencyAlgorithm.cc:43
Belle2::CalibrationAlgorithm::c_OK
@ c_OK
Finished successfuly =0 in Python.
Definition: CalibrationAlgorithm.h:51
Belle2::CDC::WireEfficiencyAlgorithm::m_badWireList
CDCBadWires * m_badWireList
BadWireList that willbe built.
Definition: WireEfficiencyAlgorithm.h:61
Belle2::CalibrationAlgorithm::setDescription
void setDescription(const std::string &description)
Set algorithm description (in constructor)
Definition: CalibrationAlgorithm.h:331
Belle2::CalibrationAlgorithm::updateDBObjPtrs
void updateDBObjPtrs(const unsigned int event, const int run, const int experiment)
Updates any DBObjPtrs by calling update(event) for DBStore.
Definition: CalibrationAlgorithm.cc:398
Belle2::CDC::CDCGeometryPar
The Class for CDC Geometry Parameters.
Definition: CDCGeometryPar.h:75
Belle2::CDCBadWires::outputToFile
void outputToFile(std::string fileName) const
Output the contents in text file format.
Definition: CDCBadWires.h:146
Belle2::CDC::WireEfficiencyAlgorithm::m_cdcGeo
DBObjPtr< CDCGeometry > m_cdcGeo
Geometry of CDC.
Definition: WireEfficiencyAlgorithm.h:60
Belle2::CDC::CDCGeometryPar::Instance
static CDCGeometryPar & Instance(const CDCGeometry *=nullptr)
Static method to get a reference to the CDCGeometryPar instance.
Definition: CDCGeometryPar.cc:41
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::CDCBadWires::setWire
void setWire(const WireID &wid, double eff=0)
Set the wire in the list.
Definition: CDCBadWires.h:50
Belle2::CalibrationAlgorithm::EResult
EResult
The result of calibration.
Definition: CalibrationAlgorithm.h:50
Belle2::CalibrationAlgorithm::getRunList
const std::vector< Calibration::ExpRun > & getRunList() const
Get the list of runs for which calibration is called.
Definition: CalibrationAlgorithm.h:276
Belle2::CDC::WireEfficiencyAlgorithm::chiTest
double chiTest(TGraphAsymmErrors *graph1, TGraphAsymmErrors *graph2, double minVale, double maxValue)
chitest
Definition: WireEfficiencyAlgorithm.cc:200
Belle2::CalibrationAlgorithm::c_NotEnoughData
@ c_NotEnoughData
Needs more data =2 in Python.
Definition: CalibrationAlgorithm.h:53
Belle2::CDC::CDCGeometryPar::nWiresInLayer
unsigned nWiresInLayer(int layerId) const
Returns wire numbers in a layer.
Definition: CDCGeometryPar.h:1211
Belle2::CDC::WireEfficiencyAlgorithm::detectBadWires
void detectBadWires()
detects bad wires.
Definition: WireEfficiencyAlgorithm.cc:106
Belle2::CalibrationAlgorithm
Base class for calibration algorithms.
Definition: CalibrationAlgorithm.h:47