51 #include "Math/Minimizer.h"
52 #include "Math/Factory.h"
53 #include "TStopwatch.h"
55 #include "conversionUtils.hpp"
60 #include "complex.cuh"
61 #include "likelihoodInterface.cuh"
67 using namespace ROOT::Math;
73 const int errCode = 0)
76 cerr <<
"performs PWA fit for given mass bin and list of waves" << endl
80 <<
" -l # -u # -w wavelist [-d amplitude directory -R -o outfile -S start value file -N -n normfile"
81 <<
" [-a normfile] -r rank -M minimizer [-m algorithm -g strategy -t #] -q -h]" << endl
83 <<
" -l # lower edge of mass bin [MeV/c^2]" << endl
84 <<
" -u # upper edge of mass bin [MeV/c^2]" << endl
85 <<
" -w file path to wavelist file" << endl
86 <<
" -d dir path to directory with decay amplitude files (default: '.')" << endl
87 #ifdef USE_STD_COMPLEX_TREE_LEAFS
88 <<
" -R use .root amplitude files (default: false)" << endl
90 <<
" -R use .root amplitude files [not supported; ROOT version too low]" << endl
92 <<
" -o file path to output file (default: 'fitresult.root')" << endl
93 <<
" -S file path to file with start values (default: none; highest priority)" << endl
94 <<
" -s # seed for random start values (default: 1234567)" << endl
95 <<
" -x # use fixed instead of random start values (default: 0.01)" << endl
97 <<
" -N use normalization of decay amplitudes (default: false)" << endl
98 <<
" -n file path to normalization integral file (default: 'norm.int')" << endl
99 <<
" -a file path to acceptance integral file (default: 'norm.int')" << endl
100 <<
" -A # number of input events to normalize acceptance to" << endl
101 <<
" -r # rank of spin density matrix (default: 1)" << endl
102 <<
" -M name minimizer (default: Minuit2)" << endl
103 <<
" -m name minimization algorithm (optional, default: Migrad)" << endl
104 <<
" available minimizers: Minuit: Migrad, Simplex, Minimize, Migrad_imp" << endl
105 <<
" Minuit2: Migrad, Simplex, Combined, Scan, Fumili" << endl
106 <<
" GSLMultiMin: ConjugateFR, ConjugatePR, BFGS, BFGS2, SteepestDescent" << endl
107 <<
" GSLMultiFit: -" << endl
108 <<
" GSLSimAn: -" << endl
109 <<
" Linear: Robust" << endl
110 <<
" Fumili: -" << endl
111 <<
" -g # minimizer strategy: 0 = low, 1 = medium, 2 = high effort (default: 1)" << endl
112 <<
" -t # minimizer tolerance (default: 1e-10)" << endl
114 <<
" -c enable CUDA acceleration (default: off)" << endl
116 <<
" -c enable CUDA acceleration [not supported by your platform]" << endl
118 <<
" -q run quietly (default: false)" << endl
119 <<
" -h print help" << endl
127 Minimizer& minimizer)
129 out <<
"minimization stopped after " << minimizer.NCalls() <<
" function calls. "
130 <<
"minimizer status summary:" << endl
131 <<
" total number of parameters .......................... " << minimizer.NDim() << endl
132 <<
" number of free parameters ........................... " << minimizer.NFree() << endl
133 <<
" maximum allowed number of iterations ................ " << minimizer.MaxIterations() << endl
134 <<
" maximum allowed number of function calls ............ " << minimizer.MaxFunctionCalls() << endl
135 <<
" minimizer status .................................... " << minimizer.Status() << endl
136 <<
" minimizer provides error and error matrix ........... " << yesNo(minimizer.ProvidesError()) << endl
137 <<
" minimizer has performed detailed error validation ... " << yesNo(minimizer.IsValidError()) << endl
138 <<
" estimated distance to minimum ....................... " << minimizer.Edm() << endl
139 <<
" statistical scale used for error calculation ........ " << minimizer.ErrorDef() << endl
140 <<
" strategy ............................................ " << minimizer.Strategy() << endl
141 <<
" absolute tolerance .................................. " << minimizer.Tolerance() << endl
142 <<
" precision ........................................... " << minimizer.Precision() << endl;
149 Minimizer& minimizer)
166 gROOT->ProcessLine(
"#include <complex>");
170 const string valTreeName =
"pwa";
171 const string valBranchName =
"fitResult_v2";
172 double defaultStartValue = 0.01;
173 bool useFixedStartValues =
false;
174 double startValStep = 0.0005;
175 const unsigned int maxNmbOfIterations = 20000;
176 const unsigned int maxNmbOfFunctionCalls = 40000;
177 const bool runHesse =
true;
178 const bool runMinos =
false;
179 int startValSeed = 1234567;
183 const string progName = argv[0];
184 double massBinMin = 0;
185 double massBinMax = 0;
186 string waveListFileName =
"";
187 string ampDirName =
".";
188 bool useRootAmps =
false;
190 string outFileName =
"fitresult.root";
191 string startValFileName =
"";
192 bool useNormalizedAmps =
false;
193 string normIntFileName =
"";
194 string accIntFileName =
"";
195 unsigned int numbAccEvents = 0;
196 unsigned int rank = 1;
197 string minimizerType[2] = {
"Minuit2",
"Migrad"};
198 int minimizerStrategy = 1;
199 double minimizerTolerance = 1e-10;
200 bool cudaEnabled =
false;
205 while ((c = getopt(argc, argv,
"l:u:w:d:Ro:S:s:x::Nn:a:A:r:M:m:g:t:cqh")) != -1)
208 massBinMin = atof(optarg);
211 massBinMax = atof(optarg);
214 waveListFileName = optarg;
220 #ifdef USE_STD_COMPLEX_TREE_LEAFS
225 outFileName = optarg;
228 startValFileName = optarg;
231 startValSeed =
atoi(optarg);
235 defaultStartValue = atof(optarg);
236 useFixedStartValues =
true;
239 useNormalizedAmps =
true;
242 normIntFileName = optarg;
245 accIntFileName = optarg;
248 numbAccEvents =
atoi(optarg);
254 minimizerType[0] = optarg;
257 minimizerType[1] = optarg;
260 minimizerStrategy =
atoi(optarg);
263 minimizerTolerance = atof(optarg);
277 if (normIntFileName.length() <= 1) {
278 normIntFileName =
"norm.int";
279 printWarn <<
"using default normalization integral file '" << normIntFileName <<
"'" << endl;
281 if (accIntFileName.length() <= 1) {
282 accIntFileName =
"norm.int";
283 printWarn <<
"using default acceptance normalization integral file "
284 <<
"'" << accIntFileName <<
"'" << endl;
286 if (waveListFileName.length() <= 1) {
287 printErr <<
"no wavelist file specified. aborting." << endl;
291 printInfo <<
"running " << progName <<
" with the following parameters:" << endl;
292 cout <<
" mass bin [" << massBinMin <<
", " << massBinMax <<
"] MeV/c^2" << endl
293 <<
" path to wave list file ......................... '" << waveListFileName <<
"'" << endl
294 <<
" path to amplitude directory .................... '" << ampDirName <<
"'" << endl
295 <<
" use .root amplitude files ...................... " << yesNo(useRootAmps) << endl
296 <<
" path to output file ............................ '" << outFileName <<
"'" << endl
297 <<
" path to file with start values ................. '" << startValFileName <<
"'" << endl
298 <<
" seed for random start values ................... " << startValSeed << endl;
299 if (useFixedStartValues)
300 cout <<
" using fixed instead of random start values ..... " << defaultStartValue << endl;
301 cout <<
" use normalization .............................. " << yesNo(useNormalizedAmps) << endl
302 <<
" path to file with normalization integral ... '" << normIntFileName <<
"'" << endl
303 <<
" path to file with acceptance integral ...... '" << accIntFileName <<
"'" << endl
304 <<
" number of acceptance norm. events .......... " << numbAccEvents << endl
305 <<
" rank of spin density matrix .................... " << rank << endl
306 <<
" minimizer ...................................... " << minimizerType[0] <<
", " << minimizerType[1] << endl
307 <<
" minimizer strategy ............................. " << minimizerStrategy << endl
308 <<
" minimizer tolerance ............................ " << minimizerTolerance << endl
309 <<
" CUDA acceleration .............................. " << enDisabled(cudaEnabled) << endl
310 <<
" quiet .......................................... " << yesNo(quiet) << endl;
314 printInfo <<
"creating and setting up likelihood function" << endl;
322 L.
init(rank, waveListFileName, normIntFileName, accIntFileName,
323 ampDirName, numbAccEvents, useRootAmps);
326 const unsigned int nmbPar = L.
NDim();
327 const unsigned int nmbEvts = L.
nmbEvents();
331 printInfo <<
"creating and setting up minimizer '" << minimizerType[0] <<
"' "
332 <<
"using algorithm '" << minimizerType[1] <<
"'" << endl;
333 Minimizer* minimizer = Factory::CreateMinimizer(minimizerType[0], minimizerType[1]);
335 printErr <<
"could not create minimizer. exiting." << endl;
338 minimizer->SetFunction (L);
339 minimizer->SetStrategy (minimizerStrategy);
340 minimizer->SetTolerance (minimizerTolerance);
344 minimizer->SetErrorDef(1);
345 minimizer->SetPrintLevel ((quiet) ? 0 : 3);
346 minimizer->SetMaxIterations (maxNmbOfIterations);
347 minimizer->SetMaxFunctionCalls(maxNmbOfFunctionCalls);
351 printInfo <<
"reading start values from '" << startValFileName <<
"'" << endl;
352 const double massBinCenter = (massBinMin + massBinMax) / 2;
354 bool startValValid =
false;
355 TFile* startValFile = NULL;
356 if (startValFileName.length() <= 2)
357 printWarn <<
"start value file name '" << startValFileName <<
"' is invalid. "
358 <<
"using default start values." << endl;
361 startValFile = TFile::Open(startValFileName.c_str(),
"READ");
362 if (not startValFile or startValFile->IsZombie())
363 printWarn <<
"cannot open start value file '" << startValFileName <<
"'. "
364 <<
"using default start values." << endl;
368 startValFile->GetObject(valTreeName.c_str(), tree);
370 printWarn <<
"cannot find start value tree '"<< valTreeName <<
"' in file "
371 <<
"'" << startValFileName <<
"'" << endl;
376 tree->SetBranchAddress(valBranchName.c_str(), &startFitResult);
378 unsigned int bestIndex = 0;
380 for (
unsigned int i = 0;
i < tree->GetEntriesFast(); ++
i) {
382 if (fabs(massBinCenter - startFitResult->
massBinCenter()) <= fabs(massBinCenter - bestMass)) {
387 tree->GetEntry(bestIndex);
388 startValValid =
true;
395 printInfo <<
"setting start values for " << nmbPar <<
" parameters" << endl
396 <<
" parameter naming scheme is: V[rank index]_[IGJPCMR][isobar spec]" << endl;
397 unsigned int maxParNameLength = 0;
398 vector<bool> parIsFixed(nmbPar,
false);
403 TRandom3 random(startValSeed);
405 for (
unsigned int i = 0;
i < nmbPar; ++
i) {
406 const string parName = L.
parName(
i);
407 if (parName.length() > maxParNameLength)
408 maxParNameLength = parName.length();
413 if (not minimizer->SetVariable(
i, parName, 0, startValStep))
416 if (not minimizer->SetFixedVariable(
i, parName, 0.))
418 parIsFixed[
i] =
true;
421 const double sqrtNmbEvts = sqrt((
double)nmbEvts);
423 for (
unsigned int i = 0;
i < parIndices.size(); ++
i) {
424 const unsigned int parIndex = parIndices[
i];
426 const string parName = minimizer->VariableName(parIndex);
427 if (parName != L.
parName(parIndex)) {
428 printWarn <<
"parameter name in minimizer and likelihood is inconsistent "
429 <<
"(" << parName <<
" vs. " << L.
parName(parIndex) <<
")" << endl;
434 assert(startFitResult);
435 startVal = startFitResult->
fitParameter(parName.c_str());
437 startVal = (useFixedStartValues) ? defaultStartValue
438 : random.Uniform(defaultStartValue, sqrtNmbEvts);
442 cout <<
" read start value 0 for parameter " << parName <<
". "
443 <<
"using default start value." << endl;
444 startVal = (useFixedStartValues) ? defaultStartValue
445 : random.Uniform(defaultStartValue, sqrtNmbEvts);
447 cout <<
" setting parameter [" << setw(3) <<
i <<
"] "
448 << setw(maxParNameLength) << parName <<
" = " << maxPrecisionAlign(startVal) << endl;
449 if (not minimizer->SetVariableValue(parIndex, startVal))
452 cout <<
" fixing parameter [" << setw(3) <<
i <<
"] "
453 << setw(maxParNameLength) << parName <<
" = 0" << endl;
454 if (not minimizer->SetVariableValue(parIndex, 0.))
456 parIsFixed[parIndex] =
true;
459 printErr <<
"something went wrong when setting log likelihood parameters. aborting." << endl;
465 startValFile->Close();
473 bool converged =
false;
474 bool hasHesse =
false;
475 printInfo <<
"performing minimization" << endl;
479 bool success = minimizer->Minimize();
482 printInfo <<
"minimization finished successfully. " << flush;
484 printWarn <<
"minimization failed. " << flush;
485 cout <<
"used " << flush;
488 printInfo << *minimizer;
494 printInfo <<
"calculating Hessian matrix" << endl;
496 success = minimizer->Hesse();
499 printInfo <<
"successfully calculated Hessian matrix. " << flush;
501 printWarn <<
"calculation of Hessian matrix failed. " << flush;
502 cout <<
"used " << flush;
505 printInfo << *minimizer;
515 printInfo <<
"minimization result:" << endl;
517 for (
unsigned int i = 0;
i< parIndices.size(); ++
i) {
518 const unsigned int parIndex = parIndices[
i];
519 cout <<
" parameter [" << setw(3) <<
i <<
"] "
520 << setw(maxParNameLength) << L.
parName(parIndex) <<
" = ";
521 if (parIsFixed[parIndex])
522 cout << minimizer->X()[parIndex] <<
" (fixed)" << endl;
524 cout << setw(12) << maxPrecisionAlign(minimizer->X() [parIndex]) <<
" +- "
525 << setw(12) << maxPrecisionAlign(minimizer->Errors()[parIndex]);
527 double minosErrLow = 0;
528 double minosErrUp = 0;
529 const bool success = minimizer->GetMinosError(parIndex, minosErrLow, minosErrUp);
531 cout <<
" Minos: " <<
"[" << minosErrLow <<
", +" << minosErrUp <<
"]" << endl;
536 printInfo <<
"function call summary:" << endl;
539 printInfo <<
"total CUDA kernel time: "
540 << cuda::likelihoodInterface<cuda::complex<double> >::kernelTime() <<
" sec" << endl;
545 printInfo <<
"writing result to '" << outFileName <<
"'" << endl;
548 TFile* outFile =
new TFile(outFileName.c_str(),
"UPDATE");
549 if ((not outFile) or outFile->IsZombie())
550 printWarn <<
"cannot open output file '" << outFileName <<
"'. "
551 <<
"no results will be written." << endl;
557 outFile->GetObject(valTreeName.c_str(), tree);
559 printInfo <<
"file '" << outFileName <<
"' is empty. "
560 <<
"creating new tree '" << valTreeName <<
"' for PWA result." << endl;
561 tree =
new TTree(valTreeName.c_str(), valTreeName.c_str());
562 tree->Branch(
"fitbin", &fitBinResult);
563 tree->Branch(valBranchName.c_str(), &result);
565 tree->SetBranchAddress(
"fitbin", &fitBinResult);
566 tree->SetBranchAddress(valBranchName.c_str(), &result);
571 vector<std::complex<double> > prodAmps;
572 vector<string> prodAmpNames;
573 vector<pair<int,int> > fitParCovMatrixIndices;
574 L.
buildProdAmpArrays(minimizer->X(), prodAmps, fitParCovMatrixIndices, prodAmpNames,
true);
575 TMatrixT<double> fitParCovMatrix(nmbPar, nmbPar);
576 for(
unsigned int i = 0;
i < nmbPar; ++
i)
577 for(
unsigned int j = 0; j < nmbPar; ++j)
583 fitParCovMatrix[
i][j] = 0.5* minimizer->CovMatrix(
i, j);
584 const unsigned int nmbWaves = L.
nmbWaves() + 1;
585 TCMatrix normIntegral(nmbWaves, nmbWaves);
586 TCMatrix accIntegral (nmbWaves, nmbWaves);
587 vector<double> phaseSpaceIntegral;
589 const int normNmbEvents = (useNormalizedAmps) ? 1 : L.
nmbEvents();
591 cout <<
"filling fitResult:" << endl
592 <<
" number of fit parameters ............... " << nmbPar << endl
593 <<
" number of production amplitudes ........ " << prodAmps.size() << endl
594 <<
" number of production amplitude names ... " << prodAmpNames.size() << endl
595 <<
" number of wave names ................... " << nmbWaves << endl
596 <<
" number of cov. matrix indices .......... " << fitParCovMatrixIndices.size() << endl
597 <<
" dimension of covariance matrix ......... " << fitParCovMatrix.GetNrows() <<
" x " << fitParCovMatrix.GetNcols() << endl
598 <<
" dimension of normalization matrix ...... " << normIntegral.
nrows() <<
" x " << normIntegral.
ncols() << endl
599 <<
" dimension of acceptance matrix ......... " << accIntegral.
nrows() <<
" x " << accIntegral.
ncols() << endl;
603 minimizer->MinValue(),
608 fitParCovMatrixIndices,
617 vector<TComplex> prodAmplitudes;
618 vector<pair<int,int> > indices;
619 vector<TString> waveNames;
621 vector<std::complex<double> > V;
622 vector<string> names;
625 for (
unsigned int i = 0;
i < V.size(); ++
i)
626 prodAmplitudes.push_back(TComplex(V[
i].real(), V[
i].imag()));
627 assert(indices.size() == prodAmplitudes.size());
628 for(
unsigned int i = 0;
i < names.size(); ++
i)
629 waveNames.push_back(TString(names[
i].c_str()));
631 vector<TString> waveTitles;
633 const vector<string>& titles = L.
waveNames();
634 for(
unsigned int i = 0;
i < titles.size(); ++
i)
635 waveTitles.push_back(TString(titles[
i].c_str()));
636 waveTitles.push_back(
"flat");
639 TMatrixD errMatrix(nmbPar, nmbPar);
640 for(
unsigned int i = 0;
i < nmbPar; ++
i)
641 for(
unsigned int j = 0; j < nmbPar; ++j)
642 errMatrix[
i][j] = minimizer->CovMatrix(
i, j);
644 cout <<
" setting up integrals" << endl;
645 const unsigned int n = waveTitles.size();
648 vector<double> phaseSpaceIntegral;
652 const int nmbEvt = (useNormalizedAmps) ? 1 : L.
nmbEvents();
654 cout <<
"filling TFitBin:" << endl
655 <<
" number of fit parameters ........... " << nmbPar << endl
656 <<
" number of production amplitudes .... " << prodAmplitudes.size() << endl
657 <<
" number of indices .................. " << indices.size() << endl
658 <<
" number of wave names (with rank) ... " << waveNames.size() << endl
659 <<
" number of wave titles (w/o rank) ... " << waveTitles.size() << endl
660 <<
" dimension of error matrix .......... " << errMatrix.GetNrows() << endl
661 <<
" dimension of integral matrix ....... " << integralMatrix.
nrows() << endl
662 <<
" dimension of acceptance matrix ..... " << accMatrix.
nrows() << endl;
663 fitBinResult->
fill(prodAmplitudes,
671 minimizer->MinValue(),
678 tree->Write(
"", TObject::kOverwrite);