Jpp 19.3.0-rc.2
the software that should make you happy
Loading...
Searching...
No Matches
JFitL1dtSlices.cc
Go to the documentation of this file.
4#include "Jeep/JParser.hh"
5
6#include "TF2.h"
7#include "TFile.h"
8#include "TH1D.h"
9#include "TH2D.h"
10#include "TMath.h"
11
12#include "JROOT/JMinimizer.hh"
13
14#include <iostream>
15#include <string>
16
17
18namespace FITL1DTSLICES {
19
20 /* Calculate the log-poisson
21 *
22 * This function has some assumptions: since the input data from JMonitorL1dt use SN datastream
23 * most background is strongly suppressed. This means many bins on both data and model will
24 * have no entries: n = 0 or nhat = 0. This will result in infinities when calculating the
25 * log-poisson. To avoid the infities the options below are used.
26 * This has been crosschecked with L1 datastream which gives a significant background and the
27 * shapes of the likelihood distributions are similar.
28 */
29 double logPoison(double n, double nhat, double logP_min = -999999.9) {
30 if (nhat < 0.0 || n < 0.0) {
31 FATAL("logPoisson: n (" << n <<") or nhat (" << nhat << ") is < 0.0" << std::endl);
32 }
33 if (n == 0.0 && nhat == 0.0) {
34 return 0.0; // ok.
35 }
36 if (n == 0.0 && nhat > 0.0) {
37 return -1*nhat; // log( lab^0 * e^-lab / 0! ) = log( e^-lab ) = -lab, ok.
38 }
39 if (n >= 0.0 && nhat == 0.0) {
40 return 0.0; // should be -inf, we only consider bins where we expect non-zero entries: no expected entries we throw away.
41 }
42 Double_t poisson = TMath::Poisson(n, nhat);
43 if (poisson == 0) return 0.0; // only when model and data are close enough do we care about their values, so if P=0, do nothing, since we are not in the region we care about.
44 else return TMath::Log(poisson);
45 }
46
47 double getLogQuality(const TH1D* data, const TH1D* model, int di, double data_bkg = 0.0001, double model_bkg = 0.0001) {
48
49 double q = 0.0;
50
51 // If you calculate over the whole histogram you lose bins at edges: only when dt=0 are all N bins considered, everywhere else
52 // either data or model bins get lost at the edge. So integrate over a smaller range:
53 int i_low = data->GetNbinsX() / 4; // Start at a quarter of the hist
54 int i_hgh = data->GetNbinsX() / 4 * 3; // End at three quarters
55 for (int i = i_low; i <= i_hgh; ++i) {
56 double n = data_bkg;
57 double nhat = model_bkg;
58 if (i >= 1 && i <= data->GetNbinsX()) {
59 // Count in bin i for the data
60 n = data->GetBinContent(i);
61 }
62 if (i+di >= 1 && i+di <= model->GetNbinsX()) {
63 // Count in bin i+di for the model
64 nhat = model->GetBinContent(i+di);
65 }
66 double logP = logPoison(n, nhat);
67 q += logP; // Added 0 for when the background is zero in model and data, but then P(n|0) gives inf! So removed overwritten logPmin
68 }
69 return q;
70 }
71}
72
73
74/**
75 * \file
76 *
77 * Auxiliary program to fit L1dt output data to an L1dt model, both created with JMonitorL1dt
78 *
79 * \author kmelis, lnauta
80 */
81int main(int argc, char **argv)
82{
83 using namespace std;
84 using namespace FITL1DTSLICES;
85 using namespace JPP;
86
87 string inputFile;
88 string modelFile;
89 string outputFile;
90 string detectorFile;
91 double dt_fitrange;
92 int rebin;
93 double TMax_ns;
94 bool normaliseMC;
95 int debug;
96
97 try {
98
99 JParser<> zap("Program to calculate log-likelihood distributions between DOM pairs and fit a poly2 to find the shape, used in FitL1dt to find time offsets");
100
101 zap['f'] = make_field(inputFile, "input file") = "monitor.root";
102 zap['m'] = make_field(modelFile, "model file");
103 zap['o'] = make_field(outputFile, "output file") = "fitslices.root";
104 zap['a'] = make_field(detectorFile, "detector file");
105 zap['T'] = make_field(TMax_ns, "scan range around 0 in data-model comparison [ns]") = 50.0;
106 zap['t'] = make_field(dt_fitrange, "fitrange of polynomial to quality [ns]") = 5.0;
107 zap['r'] = make_field(rebin, "rebin the histograms") = 1;
108 zap['N'] = make_field(normaliseMC, "normalize the MC histogram");
109 zap['d'] = make_field(debug) = 0;
110
111 if (zap.read(argc, argv) != 0) {
112 return 1;
113 }
114 }
115 catch(const exception &error) {
116 FATAL(error.what() << endl);
117 }
118
119
120 const double TSignal_ns = 750.0; // The width of the signal for integrating out the background
121
123
124 try {
125 load(detectorFile, detector);
126 }
127 catch(const JException& error) {
128 FATAL(error);
129 }
130
131
132 TFile* in = TFile::Open(inputFile.c_str(), "exist");
133 TFile* in_model = TFile::Open(modelFile.c_str(), "exist");
134
135 if (in == NULL || !in->IsOpen()) {
136 FATAL("File: " << inputFile << " not opened." << endl);
137 }
138 if (in_model == NULL || !in_model->IsOpen()) {
139 FATAL("File: " << modelFile << " not opened." << endl);
140 }
141
142 TFile out(outputFile.c_str(), "recreate");
143
144 TH2D h2A("Aij", "Aij", detector.size(), -0.5, detector.size()-0.5, detector.size(), -0.5, detector.size()-0.5);
145 TH2D h2B("Bij", "Bij", detector.size(), -0.5, detector.size()-0.5, detector.size(), -0.5, detector.size()-0.5);
146 TH2D h2C("Cij", "Cij", detector.size(), -0.5, detector.size()-0.5, detector.size(), -0.5, detector.size()-0.5);
147
148 // The bare histogram can be used for debugging, it contains the actual time offsets.
149 // Histogram Bij contains Bij/2Aij due to a different representation used in the code compared to the mathematical formulation.
150 TH2D h2Bbare("Bij_bare", "Bij_bare", detector.size(), -0.5, detector.size()-0.5, detector.size(), -0.5, detector.size()-0.5);
151 for (JDetector::iterator moduleA = detector.begin(); moduleA != detector.end(); ++moduleA) {
152 const int idom = distance(detector.begin(), moduleA);
153 TString label = Form("%i", moduleA->getID());
154 h2A.GetXaxis()->SetBinLabel(idom+1, label);
155 h2A.GetYaxis()->SetBinLabel(idom+1, label);
156 h2B.GetXaxis()->SetBinLabel(idom+1, label);
157 h2B.GetYaxis()->SetBinLabel(idom+1, label);
158 h2C.GetXaxis()->SetBinLabel(idom+1, label);
159 h2C.GetYaxis()->SetBinLabel(idom+1, label);
160
161 h2Bbare.GetXaxis()->SetBinLabel(idom+1, label);
162 h2Bbare.GetYaxis()->SetBinLabel(idom+1, label);
163 }
164
165 for (JDetector::iterator moduleA = detector.begin(); moduleA != detector.end(); ++moduleA) {
166
167 DEBUG("Module " << moduleA->getID() << endl);
168 const JString title = JString(moduleA->getID());
169 const int idom = distance(detector.begin(), moduleA);
170
171 // data
172 TH2D* d2s = (TH2D*) in->Get((title + ".2S").c_str());
173 TH1D* d1l = (TH1D*) in->Get((title + ".1L").c_str());
174
175 if (d2s == NULL || d1l == NULL) {
176 WARNING("No data in data histogram " << title << endl);
177 continue;
178 }
179
180 // model
181 TH2D* m2s = (TH2D*) in_model->Get((title + ".2S").c_str());
182 TH1D* m1l = (TH1D*) in_model->Get((title + ".1L").c_str());
183
184 if (m2s == NULL || m1l == NULL) {
185 WARNING("No mata in model histogram " << title << endl);
186 continue;
187 }
188
189
190 for (JDetector::iterator moduleB = moduleA; moduleB != detector.end(); ++moduleB) {
191 const int jdom = distance(detector.begin(), moduleB);
192
193 if (moduleB->getID() == moduleA->getID()) {
194 continue;
195 }
196 if (moduleB->getString() != moduleA->getString()) {
197 continue;
198 }
199
200 TH1D* d1s = d2s->ProjectionY((title + Form(".%i.d1S", moduleB->getID())).c_str(),
201 d2s->GetXaxis()->FindBin(TString(Form("%i", moduleB->getID()))),
202 d2s->GetXaxis()->FindBin(TString(Form("%i", moduleB->getID()))), "e");
203 TH1D* m1s = m2s->ProjectionY((title + Form(".%i.m1S", moduleB->getID())).c_str(),
204 m2s->GetXaxis()->FindBin(TString(Form("%i", moduleB->getID()))),
205 m2s->GetXaxis()->FindBin(TString(Form("%i", moduleB->getID()))), "e");
206
207 if (d1s->Integral() <= 0.0 || m1s->Integral() <= 0.0) {
208 continue;
209 }
210
211 // background fit: data
212 double binCenterMaxBin = d1s->GetXaxis()->GetBinCenter(d1s->GetMaximumBin());
213 double backgroundrate_s = 0.0;
214 int nbins = 0;
215 for (int j = 1; j <= d1s->GetXaxis()->GetNbins(); ++j) {
216 if (fabs(d1s->GetXaxis()->GetBinCenter(j) - binCenterMaxBin) > TSignal_ns ) {
217 backgroundrate_s += d1s->GetBinContent(j);
218 nbins++;
219 }
220 }
221 backgroundrate_s /= nbins;
222
223 // background fit: model
224 binCenterMaxBin = m1s->GetXaxis()->GetBinCenter(m1s->GetMaximumBin());
225 double backgroundrate_m = 0.0;
226 nbins = 0;
227 for (int j = 1; j <= m1s->GetXaxis()->GetNbins(); ++j) {
228 if (fabs(m1s->GetXaxis()->GetBinCenter(j) - binCenterMaxBin) > TSignal_ns ) {
229 backgroundrate_m += m1s->GetBinContent(j);
230 nbins++;
231 }
232 }
233 backgroundrate_m /= nbins;
234
235 // scale livetimes and remove background
236 const double Ld = d1l->GetBinContent(d1l->GetXaxis()->FindBin(TString(Form("%i", moduleB->getID()))));
237 const double Lm = m1l->GetBinContent(m1l->GetXaxis()->FindBin(TString(Form("%i", moduleB->getID()))));
238
239 for (int j = 1; j <= d1s->GetXaxis()->GetNbins(); ++j) {
240 const double y = d1s->GetBinContent(j);
241 const double dy = d1s->GetBinError(j);
242
243 d1s->SetBinContent(j, y);
244 d1s->SetBinError(j, dy);
245 }
246
247 // scale the livetime of the model
248 for (int j = 1; j <= m1s->GetXaxis()->GetNbins(); ++j) {
249 const double y = m1s->GetBinContent(j);
250 const double dy = m1s->GetBinError(j);
251
252 m1s->SetBinContent(j, y * Ld/Lm);
253 m1s->SetBinError(j, dy*Ld/Lm);
254 }
255
256
257 if (normaliseMC) {
258 const double scalefactor = d1s->Integral()/m1s->Integral();
259 m1s->Scale(scalefactor);
260 }
261
262 // rebin
263 d1s->Rebin(rebin);
264 m1s->Rebin(rebin);
265
266 // write background subtracted, normalised slices
267 d1s->Write();
268 m1s->Write();
269
270 // get quality
271 int ddt_min = -0.5*TMax_ns; // maximum time shift [ns]
272 int ddt_max = 0.5*TMax_ns; // maximum time shift [ns]
273
274 TH1D q1((title + Form(".%i.q1", moduleB->getID())).c_str(), (title + Form(".%i.q1", moduleB->getID())).c_str(), (ddt_max-ddt_min)/rebin+1, ddt_min-0.5*rebin, ddt_max+0.5*rebin);
275
276 for (int di = 1; di <= q1.GetNbinsX(); di++) {
277 q1.SetBinContent(di, getLogQuality(d1s, m1s, (int)(q1.GetBinCenter(di)/rebin), 0.0, 0.0));
278 }
279
280 // Fit peak with parabola
281 const double dt_fitmid = q1.GetBinCenter(q1.GetMaximumBin());
282
283 TF1 q1f((title + Form(".%i.q1f", moduleB->getID())).c_str(), "[0]*x*x + [1]*x + [2]", dt_fitmid - dt_fitrange, dt_fitmid + dt_fitrange);
284 q1f.SetParLimits(0, -1e5, 0.0); // Added as to improve fits. Aij should always be l.t. 0 to fit a maximum to the LLH
285
286 string fitoptions = "R";
287 if (debug < JEEP::debug_t) {
288 fitoptions += " Q";
289 }
290 q1.Fit(&q1f, fitoptions.c_str());
291
292 // write quality and fit
293 q1.Write();
294
295 // Fit results to global fit matrix
296 const double Aij = q1f.GetParameter(0);
297 const double Bij = q1f.GetParameter(1);
298 const double Cij = q1f.GetParameter(2);
299
300 double bareBij = Bij / Aij;
301 if (Aij == 0) bareBij = 0;
302
303 if (fabs(-0.5*Bij/Aij - dt_fitmid) > 3 || fabs(-0.5*Bij/Aij) > dt_fitrange) {
304 WARNING(" Please check fit of pair " << idom << ", " << jdom << " : " << moduleA->getID() << ", " << moduleB->getID() << endl);
305 WARNING(" DOMpair " << idom << "; " << jdom << " A=" << Aij << " B=" << Bij << " , max at: " << dt_fitmid << " [ns], best fit at " << -0.5*Bij/Aij << " ns " << endl);
306 }
307 DEBUG("DOMpair " << idom << "; " << jdom << " A=" << Aij << " B=" << Bij << " , max at: " << dt_fitmid << " [ns], best fit at " << -0.5*Bij/Aij << " ns " << endl);
308
309 h2A.SetBinContent(idom+1, jdom+1, Aij);
310 h2A.SetBinContent(jdom+1, idom+1, Aij);
311 h2B.SetBinContent(idom+1, jdom+1, Bij);
312 h2B.SetBinContent(jdom+1, idom+1,-Bij);
313 h2C.SetBinContent(idom+1, jdom+1, Cij);
314 h2C.SetBinContent(jdom+1, idom+1, Cij);
315
316 h2Bbare.SetBinContent(idom+1, jdom+1, bareBij);
317 h2Bbare.SetBinContent(jdom+1, idom+1, 0);
318 }
319 }
320
321 out.cd();
322
323 h2A.Write();
324 h2B.Write();
325 h2C.Write();
326
327 h2Bbare.Write();
328
329 out.Close();
330}
string outputFile
KM3NeT DAQ constants, bit handling, etc.
Data structure for detector geometry and calibration.
int main(int argc, char **argv)
#define DEBUG(A)
Message macros.
Definition JMessage.hh:62
#define FATAL(A)
Definition JMessage.hh:67
int debug
debug level
Definition JSirene.cc:72
#define WARNING(A)
Definition JMessage.hh:65
Utility class to parse command line options.
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Definition JParser.hh:2142
std::vector< T >::difference_type distance(typename std::vector< T >::const_iterator first, typename PhysicsEvent::const_iterator< T > second)
Specialisation of STL distance.
Detector data structure.
Definition JDetector.hh:96
General exception.
Definition JException.hh:24
Wrapper class around STL string class.
Definition JString.hh:29
Utility class to parse command line options.
Definition JParser.hh:1698
int read(const int argc, const char *const argv[])
Parse the program's command line options.
Definition JParser.hh:1992
double getLogQuality(const TH1D *data, const TH1D *model, int di, double data_bkg=0.0001, double model_bkg=0.0001)
double logPoison(double n, double nhat, double logP_min=-999999.9)
@ debug_t
debug
Definition JMessage.hh:29
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
Detector file.
Definition JHead.hh:227