GamR  0.0.0
GammaROOT
Loading...
Searching...
No Matches
LevelSchemeFitter.cc
Go to the documentation of this file.
1#include <string>
2#include <algorithm>
3#include <iostream>
4
5#include <TStyle.h>
6#include <TH2F.h>
7#include <TGaxis.h>
8#include <TCanvas.h>
9#include <TLine.h>
10#include <TText.h>
11#include <TArrow.h>
12#include <TMinuit.h>
13
14#include "LevelSchemeFitter.hh"
15#include <utils/Utilities.hh>
16
17// ignoring npar, gin, iflag in GlobalChiSquare::doit
18// TMinuit expects these extra variables that we don't use
19#pragma GCC diagnostic ignored "-Wunused-parameter"
20
21namespace GamR {
22 namespace Nucleus {
23 namespace LevelSchemeFitter {
24
25 void State::Paint(Option_t *option) {
26 TAttLine::Modify();
27
28 double x[2];
29 double y[2];
30 x[0] = 0.1;
31 x[1] = 0.9;
32 y[0] = fDrawPos;
33 y[1] = fDrawPos;
34 gPad->PaintPolyLine(2, &x[0], &y[0], option);
35
36 x[0] = 0.9;
37 x[1] = 0.93;
38 y[0] = fDrawPos;
39 y[1] = fLabelPos;
40 gPad->PaintPolyLine(2, &x[0], &y[0], option);
41
42 x[0] = 0.93;
43 x[1] = 0.97;
44 y[0] = fLabelPos;
45 y[1] = fLabelPos;
46 gPad->PaintPolyLine(2, &x[0], &y[0], option);
47
48 std::string energy_string = GamR::Utils::wrresult(fEnergy, fUncertainty);
49 int py0 = gPad->YtoPixel(0);
50 fLabel->SetText(0.93, gPad->PixeltoY((gPad->YtoPixel(fLabelPos)-2)) - gPad->PixeltoY(py0), energy_string.c_str());
51 fLabel->SetTextFont(4);
52 fLabel->SetTextSize(15);
53 fLabel->SetTextColor(GetLineColor());
54 fLabel->Paint();
55
56 }
57
58 Int_t State::DistancetoPrimitive(Int_t px, Int_t py) {
59 //distance to main line
60 double dx = 0;
61 if (px > gPad->XtoAbsPixel(0.9)) { dx = px - gPad->XtoAbsPixel(0.9); }
62 else if (px < gPad->XtoAbsPixel(0.1)) { dx = gPad->XtoAbsPixel(0.1) - px; }
63 double dy = gPad->YtoAbsPixel(fDrawPos) - py;
64 double main_dist = sqrt(dx*dx + dy*dy);
65
66 //distance to label line
67 if (px > gPad->XtoAbsPixel(0.97)) { dx = px - gPad->XtoAbsPixel(0.97); }
68 else if (px < gPad->XtoAbsPixel(0.93)) { dx = gPad->XtoAbsPixel(0.93) - px; }
69 dy = gPad->YtoAbsPixel(fLabelPos) - py;
70 double label_dist = sqrt(dx*dx + dy*dy);
71
72 //distance to connecting line
73 double connecting_dist = DistancetoLine(px, py,
74 gPad->XtoAbsPixel(0.93),
75 gPad->YtoAbsPixel(fDrawPos),
76 gPad->XtoAbsPixel(0.97),
77 gPad->YtoAbsPixel(fLabelPos));
78
79 return std::min(std::min(main_dist, label_dist), connecting_dist);
80 }
81
82 void State::ExecuteEvent(Int_t event, Int_t px, Int_t py)
83 {
84 if (!gPad)
85 return;
86 int kMaxDiff = 20;
87
88 if (!gPad->IsEditable())
89 return;
90
91 switch (event) {
92 case kMouseMotion:
93 if (DistancetoPrimitive(px, py) < kMaxDiff) {
94 gPad->SetCursor(kPointer);
95 return;
96 }
97 break;
98 }
99 }
100
101 void Transition::Paint(Option_t *option) {
102 TAttLine::Modify();
103 TAttFill::Modify();
104
105 PaintArrow(GetX1(), GetY1(), GetX2(), GetY2(), GetArrowSize(), TArrow::GetOption());
106
107 //paint transition label
108 std::string transition_string = GamR::Utils::wrresult(fEnergy, fUncertainty);
109 fLabel->SetText(GetX1(), GetY1(), transition_string.c_str());
110 fLabel->SetTextFont(4);
111 fLabel->SetTextAngle(45);
112 fLabel->SetTextSize(15);
113 fLabel->SetTextColor(GetLineColor());
114 fLabel->Paint();
115
116 }
117
119 //assumes vertical
120
121 int xp1 = gPad->XtoAbsPixel(GetX1());
122 int yp1 = gPad->YtoAbsPixel(GetY1());
123 int xp2 = gPad->XtoAbsPixel(GetX2());
124 int yp2 = gPad->YtoAbsPixel(GetY2());
125
126 int dx = abs(xp1 - px);
127 int dy = 9999;
128
129 double dist = 9999;
130
131 if (py < yp1) { dy = abs(py - yp1); }
132 else if (py > yp2) { dy = abs(py - yp2); }
133 else { dy = 0; }
134
135 dist = dx*dx + dy*dy;
136
137 return sqrt(dist);
138
139 }
140
141 void Transition::ExecuteEvent(Int_t event, Int_t px, Int_t py)
142 {
143 if (!gPad)
144 return;
145 int kMaxDiff = 20;
146
147 if (!gPad->IsEditable())
148 return;
149
150 switch (event) {
151 case kMouseMotion:
152 if (DistancetoPrimitive(px, py) < kMaxDiff) {
153 gPad->SetCursor(kPointer);
154 return;
155 }
156 break;
157 }
158 }
159
161 std::vector<State*> states;
162 for (auto &state : fStates) {
163 states.push_back(&state.second);
164 }
165
166 std::sort(states.begin(), states.end(),
167 [](const State *a, const State *b)
168 {
169 return *a < *b;
170 });
171
172 for (int i=0; i<(int)states.size(); ++i) {
173 fStates[states[i]->GetName()].index = i;
174 }
175 }
176
178 for (auto &state : fStates) {
179 if (state.second.index==i) {
180 return &state.second;
181 }
182 }
183 return NULL;
184 }
185
187 double chi2 = 0;
188 for (auto &transition : fTransitions) {
189 //std::cout << "comparing " << transition.fEnergy << " with " << transition.fInitial->fEnergy - transition.fFinal->fEnergy << std::endl;
190 chi2 += pow((transition.fEnergy - (transition.fInitial->fEnergy - transition.fFinal->fEnergy))/transition.fUncertainty, 2);
191 }
192 return chi2;
193 }
194
196 private:
197 static Scheme *p;
198
199 public:
200 GlobalChiSquare(Scheme *parent) { p = parent; }
201
202 static void minuit(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
203 {
204 //std::cout << "function call with " << npar << " parameters" << std::endl;
205 f = 0;
206 //loop through states to set energies
207 for (auto &state : p->fStates) {
208 if (state.second.index == 0) { continue; }
209 state.second.fEnergy = par[state.second.index-1];
210 //std::cout << "state " << state.second.index << " " << state.second.fEnergy << std::endl;
211 }
212 f = p->GetChiSquared();
213 }
214
215 };
216
217 Scheme *Scheme::GlobalChiSquare::p = nullptr;
218
219 void Scheme::Fit() {
220 Int_t npars = (int)fStates.size() - 1;
221 std::cout << npars << std::endl;
222 auto gMinuit = new TMinuit(npars);
223
224 GlobalChiSquare func(this);
225 gMinuit->SetFCN(func.minuit);
226
227 Double_t arglist[10];
228 arglist[0] = 1;
229
230 Int_t ierflg = 0; // some error flag ???
231
232 gMinuit->mnexcm("SET ERR", arglist, 1, ierflg);
233 arglist[0] = 2;
234 gMinuit->mnexcm("SET STR", arglist, 1, ierflg);
235
236 Int_t parnum = 0;
237
238 for ( int i=1; i<=npars; ++i ) {
239 std::cout << "Setting up level " << i << std::endl;
240 double energy = GetStateByIndex(i)->fEnergy;
241 gMinuit->mnparm(parnum, ("Level "+std::to_string(i)).c_str(), energy, GetStateByIndex(i)->fUncertainty, 0.8*energy, 1.2*energy, ierflg);
242 ++parnum;
243 }
244
245 /* MINIMIZE */
246 //std::cout << gMinuit->GetNumPars() << " parameters in total" << std::endl;
247 arglist[0] = 100000; // Max Iterations
248 arglist[1] = 1; // Number of sigma max step
249 gMinuit->mnexcm("MINIGRAD", arglist, 2, ierflg);
250 //std::cout << gMinuit->GetNumPars() << " parameters in total" << std::endl;
251 gMinuit->mnimpr(); // Improve fit by searching for other minima
252 //std::cout << gMinuit->GetNumPars() << " parameters " << std::endl;
253 gMinuit->mnexcm("HESSE", arglist, 2, ierflg);
254 //std::cout << gMinuit->GetNumPars() << " parameters " << std::endl;
255
256 //printf("Level %d : %8.4f %7.5f\n", 0, GetStateByIndex(0)->fEnergy, 0.0);
257 for (int i=1; i<=gMinuit->GetNumPars(); ++i) {
258 double parVal, parErr;
259 gMinuit->GetParameter(i-1, parVal, parErr);
260 GetStateByIndex(i)->fEnergy = parVal;
261 GetStateByIndex(i)->fUncertainty = parErr;
262 //printf("Level %d : %8.4f %7.5f\n", i, parVal, parErr);
263 }
264
265 delete gMinuit;
266
267 }
268
270 std::vector<State*> states;
271 for (auto &state : fStates) {
272 states.push_back(&state.second);
273 }
274
275 std::sort(states.begin(), states.end(),
276 [](const State *a, const State *b)
277 {
278 return *a < *b;
279 });
280
281
282 printf("Printing state energies for %i states\n", (int)states.size());
283 for (int i=0; i<(int)states.size(); ++i) {
284 printf("Level %d : %10s : %8.4f %7.5f\n", states[i]->index, states[i]->GetName(), states[i]->fEnergy, states[i]->fUncertainty);
285 }
286 }
287
289 printf("Printing %i transitions\n", (int)fTransitions.size());
290 for (auto &transition : fTransitions) {
291 printf("Transition : %10.4f(%5.3f) vs %8.4f : %5.2f sigma difference\n", transition.fEnergy, transition.fUncertainty, transition.fInitial->fEnergy - transition.fFinal->fEnergy, (transition.fEnergy - (transition.fInitial->fEnergy - transition.fFinal->fEnergy))/transition.fUncertainty);
292 }
293 }
294
296 PrintStates();
297 printf("\n");
299 double chi2 = GetChiSquared();
300 int ndf = (int)fTransitions.size() - (int)fStates.size();
301 printf("\n");
302 printf("Total states : %i\n", (int)fStates.size());
303 printf("Total transitions : %i\n", (int)fTransitions.size());
304 printf("Chi^2 : %10.5f\n", chi2);
305 printf("ndf : %i\n", ndf);
306 printf("Chi^2/ndf : %10.5f\n", chi2/(double)ndf);
307 }
308
309 void Scheme::PrintState(std::string name) {
310 printf("========================================\n");
311 printf("State %s, Index : %d, Energy : % 5.2f\n", name.c_str(), fStates[name].index, fStates[name].fEnergy);
312 std::vector<Transition*> inTransitions;
313 std::vector<Transition*> outTransitions;
314 for (auto &transition : fTransitions) {
315 if (*transition.fInitial == fStates[name]) { outTransitions.push_back(&transition); }
316 if (*transition.fFinal == fStates[name]) { inTransitions.push_back(&transition); }
317 }
318 printf("Transitions in : \n");
319 for (auto &transition : inTransitions) {
320 printf(" % 5.2f\n", transition->fEnergy);
321 }
322 printf("Transitions out : \n");
323 for (auto &transition : outTransitions) {
324 printf(" % 5.2f\n", transition->fEnergy);
325 }
326 }
327
328 void Scheme::Paint(Option_t *option) {
329
330 gPad->SetFrameLineColor(0);
331
332 double eLow = drawLow;
333 double eHigh = drawHigh;
334 SetIndices();
335 //get max energy
336 std::map<int, State*> range_states; //states in the energy range, indexed by (global) index
337 std::map<int, State*> extra_states; //extra states that still need to be drawn, indexed by (global) index
338 std::vector<int> drawn_indexes;
339 double max_energy = 0;
340 for (auto &state : fStates) {
341 if (state.second.fEnergy < eLow || state.second.fEnergy > eHigh) { continue; }
342 else { range_states[state.second.index] = &state.second; drawn_indexes.push_back(state.second.index); }
343 if (state.second.fEnergy > max_energy) {
344 max_energy = state.second.fEnergy;
345 }
346 }
347
348 //figure out extra states
349 int nTransitions = 0;
350 for (auto &state : range_states) {
351 for (auto &transition : fTransitions) {
352 if (transition.fInitial->index == state.second->index) {
353 nTransitions++;
354 if (range_states.find(transition.fFinal->index)==range_states.end() && extra_states.find(transition.fFinal->index)==extra_states.end()) {
355 extra_states[transition.fFinal->index] = transition.fFinal;
356 drawn_indexes.push_back(transition.fFinal->index);
357 }
358 }
359 }
360 }
361
362 std::sort(drawn_indexes.begin(), drawn_indexes.end());
363
364 if (drawn_indexes[0] != 0) { drawn_indexes.insert(drawn_indexes.begin(), 0); }
365
366 fDrawHist->SetBins(100, 0.0, 1.0, 100, 0.0, (int)((1.1*max_energy)/10)*10);
367 gStyle->SetOptStat(0);
368 fDrawHist->Paint("A");
369
370 if (!fAxis) {
371 fAxis = new TGaxis(0, 0, 0, (int)((1.1*max_energy)/10)*10 , 0, (int)((1.1*max_energy)/10)*10, 510, "");
372 fAxis->AppendPad();
373 }
374
375 double transition_spacing = 0.8/(double)nTransitions;
376 int count = 0;
377
378 for (int i=0; i<(int)drawn_indexes.size(); ++i) {
379 int index = drawn_indexes[i];
380 State *state = GetStateByIndex(drawn_indexes[i]);
381 state->fLabelPos = state->fEnergy;
382 state->fDrawPos = state->fEnergy;
383 }
384
385 int conflicts = 1;
386 TText *test = new TText();
387 test->SetTextSize(15);
388 int py0 = gPad->YtoPixel(0);
389 double label_threshold = gPad->PixeltoY(py0-(test->GetTextSize()+3)) - gPad->PixeltoY(py0);
390 delete test;
391 label_threshold = fabs(label_threshold);
392 double state_threshold = 40;
393 while (conflicts) {
394 conflicts = 0;
395 //std::cout << "New attempt" << std::endl;
396 for (int i = 0; i < (int)drawn_indexes.size()-1; ++i) {
397 State *state1 = GetStateByIndex(drawn_indexes[i]);
398 State *state2 = GetStateByIndex(drawn_indexes[i+1]);
399 if ((state2->fLabelPos - state1->fLabelPos) < label_threshold) {
400 //std::cout << "States " << drawn_states[drawn_indexes[i]]->fEnergy << " and " << drawn_states[drawn_indexes[i+1]]->fEnergy << " with positions " << drawn_states[drawn_indexes[i+1]]->fLabelPos << " and " << drawn_states[drawn_indexes[i]]->fLabelPos << std::endl;
401 conflicts++;
402 double av = (state2->fLabelPos + state1->fLabelPos)/2.0;
403 state1->fLabelPos = av-1.001*label_threshold/2.0;
404 state2->fLabelPos = av+1.001*label_threshold/2.0;
405 //std::cout << "New positions " << drawn_states[drawn_indexes[i+1]]->fLabelPos << " and " << drawn_states[drawn_indexes[i]]->fLabelPos << std::endl;
406 }
407 if ((state2->fDrawPos - state1->fDrawPos) < state_threshold) {
408 //std::cout << "States with positions " << state_pos[i+1] << " and " << state_pos[i] << std::endl;
409 conflicts++;
410 double av = (state2->fDrawPos + state1->fDrawPos)/2.0;
411 state1->fDrawPos = av-1.001*state_threshold/2.0;
412 state2->fDrawPos = av+1.001*state_threshold/2.0;
413 //std::cout << "New positions " << state_pos[i+1] << " and " << state_pos[i] << std::endl;
414 }
415 }
416 }
417
418 std::vector<Transition*> draw_transitions;
419
420 for (int i=0; i<(int)drawn_indexes.size(); ++i) {
421 int index = drawn_indexes[i];
422 State *state = GetStateByIndex(drawn_indexes[i]);
423
424 //state->Paint(option);
425 if (!gPad->GetListOfPrimitives()->Contains(state)) {
426 state->AppendPad();
427 }
428
429 std::vector<Transition*> state_transitions;
430 for (auto &transition : fTransitions) {
431 if (transition.fInitial->index == state->index && range_states.find(state->index) != range_states.end()) {
432 state_transitions.push_back(&transition);
433 draw_transitions.push_back(&transition);
434 }
435 }
436
437 std::sort(state_transitions.begin(), state_transitions.end(),
438 [](const Transition *a, const Transition *b)
439 {
440 return *a < *b;
441 });
442
443 for (auto &transition : state_transitions) {
444 State* finalState = GetStateByIndex(transition->fFinal->index);
445
446 transition->SetX1(0.9-(double)count*transition_spacing-0.5*transition_spacing);
447 transition->SetY1(state->fDrawPos);
448 transition->SetX2(0.9-(double)count*transition_spacing-0.5*transition_spacing);
449 transition->SetY2(finalState->fDrawPos);
450
451 ++count;
452 }
453
454 }
455
456 for (auto &transition : draw_transitions) {
457 //transition->Paint();
458 if (!gPad->GetListOfPrimitives()->Contains(transition)) {
459 transition->AppendPad();
460 }
461 }
462
463 //gPad->GetListOfPrimitives()->Remove(fDrawHist);
464
465 }
466
467 void Scheme::SaveTable(std::string filename) {
468 std::ofstream outfile(filename);
469
470 SetIndices();
471
472 for (int i=0; i<fStates.size(); ++i) {
473 auto state = GetStateByIndex(i);
474
475 std::vector<Transition> transitions;
476 for (auto transition : fTransitions) {
477 if (state == transition.fInitial) {
478 transitions.push_back(transition);
479 std::cout << state->fEnergy << " " << transition.fInitial->fEnergy << " " << transition.fEnergy << std::endl;
480 }
481 }
482
483 for (int j=0; j<transitions.size(); ++j) {
484 if (j==0) {
485 outfile << GamR::Utils::wrresult(state->fEnergy, state->fUncertainty) << " & ";
486 }
487 else {
488 outfile << " & ";
489 }
490 outfile << GamR::Utils::wrresult(transitions[j].fEnergy, transitions[j].fUncertainty) << " & " << GamR::Utils::wrresult(transitions[j].fFinal->fEnergy, transitions[j].fFinal->fUncertainty) << "\\\\" << std::endl;
491 }
492 }
493 outfile.close();
494 }
495
496 }
497 }
498}
void py(TVirtualPad *canvas)
void px(TVirtualPad *canvas)
static void minuit(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
std::map< std::string, State > fStates
Int_t DistancetoPrimitive(Int_t px, Int_t py)
void ExecuteEvent(Int_t event, Int_t px, Int_t py)
void ExecuteEvent(Int_t event, Int_t px, Int_t py)
int wrresult(char *out, float value, float err, int minlen)
Definition Utilities.cc:241
Definition Gain.cc:19