AmpTools
FitResults.cc
Go to the documentation of this file.
1 //******************************************************************************
2 // This file is part of AmpTools, a package for performing Amplitude Analysis
3 //
4 // Copyright Trustees of Indiana University 2010, all rights reserved
5 //
6 // This software written by Matthew Shepherd, Ryan Mitchell, and
7 // Hrayr Matevosyan at Indiana University, Bloomington
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions
11 // are met:
12 // 1. Redistributions of source code must retain the above copyright
13 // notice and author attribution, this list of conditions and the
14 // following disclaimer.
15 // 2. Redistributions in binary form must reproduce the above copyright
16 // notice and author attribution, this list of conditions and the
17 // following disclaimer in the documentation and/or other materials
18 // provided with the distribution.
19 // 3. Neither the name of the University nor the names of its contributors
20 // may be used to endorse or promote products derived from this software
21 // without specific prior written permission.
22 //
23 // Creation of derivative forms of this software for commercial
24 // utilization may be subject to restriction; written permission may be
25 // obtained from the Trustees of Indiana University.
26 //
27 // INDIANA UNIVERSITY AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES,
28 // EXPRESS OR IMPLIED. By way of example, but not limitation, INDIANA
29 // UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCANTABILITY OR
30 // FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THIS SOFTWARE OR
31 // DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS,
32 // OR OTHER RIGHTS. Neither Indiana University nor the authors shall be
33 // held liable for any liability with respect to any claim by the user or
34 // any other party arising from use of the program.
35 //******************************************************************************
36 
37 #include <iostream>
38 #include <algorithm>
39 #include <cmath>
40 #include <iomanip>
41 #include <cassert>
42 
43 #include "IUAmpTools/FitResults.h"
51 
53  vector< IntensityManager* > intenManVec,
54  map< string, LikelihoodCalculator* > likCalcMap,
55  map< string, NormIntInterface* > normIntMap,
56  MinuitMinimizationManager* minManager,
57  ParameterManager* parManager) :
58 m_likelihoodTotal( 0 ),
59 m_cfgInfo( cfgInfo ),
60 m_intenManVec( intenManVec ),
61 m_likCalcMap( likCalcMap ),
62 m_normIntMap( normIntMap ),
63 m_minManager( minManager ),
64 m_parManager( parManager ),
65 m_createdFromFile( false ),
66 m_warnedAboutFreeParams( false ),
67 m_isValid( true ){
68 
69 }
70 
71 FitResults::FitResults( const string& inFile ) :
72 m_createdFromFile( true ),
73 m_warnedAboutFreeParams( false ),
74 m_isValid( false ){
75 
76  loadResults( inFile );
77 }
78 
80 
81  if( m_createdFromFile ) {
82 
83  for( map< string, NormIntInterface* >::iterator mapItr = m_normIntMap.begin();
84  mapItr != m_normIntMap.end();
85  ++mapItr ){
86 
87  delete mapItr->second;
88  }
89  }
90 }
91 
92 double
93 FitResults::likelihood( const string& reaction ) const {
94 
95  map< string, double >::const_iterator reac = m_likelihoodMap.find( reaction );
96 
97  if( reac == m_likelihoodMap.end () ){
98 
99  cout << "FitResults ERROR: request for likelihood of unknown reaction: " << reaction << endl;
100  return sqrt( -1 );
101  }
102 
103  return reac->second;
104 }
105 
106 pair< double, double >
107 FitResults::intensity( bool accCorrected ) const {
108 
109  // return the intensity for all amplitudes
110  return intensity( ampList(), accCorrected );
111 }
112 
113 pair< double, double >
114 FitResults::intensity( const vector< string >& amplitudes, bool accCorrected ) const {
115 
116  // first make sure we know about all the amplitudes:
117  vector< string > knownAmps = ampList();
118  for( vector< string >::const_iterator amp = amplitudes.begin();
119  amp != amplitudes.end(); ++amp ){
120 
121  if( find( knownAmps.begin(), knownAmps.end(), *amp ) == knownAmps.end() ){
122 
123  cout << "FitResults ERROR: request to compute intensity for unknown amplitude:\n\t"
124  << *amp << endl;
125  assert( false );
126  }
127  }
128 
129  // intensity = sum_a sum_a' s_a s_a' V_a V*_a' NI( a, a' )
130 
131  // a subset of the larger error matrix
132  vector< vector< double > > errorMatrix;
133 
134  // a vector for the derivatives of the intensity with respect to the
135  // real and imaginary parts of the production amplitudes and the
136  // scale parameter for the amplitude
137  vector< double > deriv( 3 * amplitudes.size() );
138  vector< double > parName( 3 * amplitudes.size() );
139 
140  double intensity = 0;
141 
142  // check for free parameters and print an appropriate warning message
143  // about the accuracy of the intensity errors since we don't yet have
144  // the ability to numerically compute the derivatives of the
145  // normalization integrals with respect to the free parameters
146 
147  map< string, double > ampParameters = ampParMap();
148  for( map< string, double >::iterator par = ampParameters.begin();
149  par != ampParameters.end();
150  ++par ){
151 
152  // there are parameters -- check errors to see if they
153  // were floating in the fit
154  int parIndex = m_parIndex.find( par->first )->second;
155  if( fabs( m_covMatrix[parIndex][parIndex] ) > 1E-20 ){
156 
157  if( !m_warnedAboutFreeParams )
158 
159  cout
160  << "***************************************************************" << endl
161  << "* WARNING!: You are calculating an intensity that depends on *" << endl
162  << "* parameters that were floating in the fit. Unless the par-*" << endl
163  << "* ameters are amplitude scale factors only, THE ERROR ON *" << endl
164  << "* THE INTENSITY SHOULD BE CONSIDERED UNRELIABLE because the *" << endl
165  << "* software is assuming that the derivatives of the normali- *" << endl
166  << "* zation integrals with respect to the parameters are equal *" << endl
167  << "* to zero. (Fixing this involves numercially computing the *" << endl
168  << "* derivatives, which will be implemented in future versions *" << endl
169  << "* of AmpTools.) For now it is recommended that you repeat *" << endl
170  << "* the fit fixing the free parameter(s) at +- 1 sigma of the *" << endl
171  << "* parameter uncertainty to systematically probe how the *" << endl
172  << "* uncertainty on the intensity depends on the uncertainty *" << endl
173  << "* of the parameter. *" << endl
174  << "***************************************************************" << endl
175  << endl;
176 
177  m_warnedAboutFreeParams = true;
178  }
179  }
180 
181  // now calculate the vector of partial derivatives of the intensity
182  // with respect to the real, imaginary, and scale factors for each
183  // production amplitude
184 
185  for( vector< string >::const_iterator amp = amplitudes.begin();
186  amp != amplitudes.end(); ++amp ){
187 
188  // the vector of amplitudes should be "full" amplitude names
189  // that include the reaction, sum, and amplitude name
190  vector<string> ampNameParts = stringSplit( *amp, "::" );
191  assert( ampNameParts.size() == 3 );
192  string reaction = ampNameParts[0];
193 
194  // we need to build a small covriance matrix for the calculation
195  // use lower case to denote the index in the small matrix while
196  // upper case denotes the index in the full matrix
197 
198  int iRe = 3 * ( amp - amplitudes.begin() );
199  int iIm = iRe + 1;
200  int iScale = iRe + 2;
201 
202  int IRe = m_parIndex.find( realProdParName( *amp ) )->second;
203  int IIm = m_parIndex.find( imagProdParName( *amp ) )->second;
204 
205  // if the name of the scale parameter doesn't appear in the list of
206  // free parameters set the index to -1 and watch for this below
207  map< string, int >::const_iterator idx1 = m_parIndex.find( ampScaleName( *amp ) );
208  int IScale = ( idx1 == m_parIndex.end() ? -1 : idx1->second );
209 
210  errorMatrix.push_back( vector< double >( 3 * amplitudes.size() ) );
211  errorMatrix.push_back( vector< double >( 3 * amplitudes.size() ) );
212  errorMatrix.push_back( vector< double >( 3 * amplitudes.size() ) );
213 
214  deriv[iRe] = 0;
215  deriv[iIm] = 0;
216  deriv[iScale] = 0;
217 
218  for( vector< string >::const_iterator conjAmp = amplitudes.begin();
219  conjAmp != amplitudes.end(); ++conjAmp ) {
220 
221  vector<string> conjAmpNameParts = stringSplit( *conjAmp, "::" );
222  assert( conjAmpNameParts.size() == 3 );
223  string conjReaction = ampNameParts[0];
224 
225  int jRe = 3 * ( conjAmp - amplitudes.begin() );
226  int jIm = jRe + 1;
227  int jScale = jRe + 2;
228 
229  int JRe = m_parIndex.find( realProdParName( *conjAmp ) )->second;
230  int JIm = m_parIndex.find( imagProdParName( *conjAmp ) )->second;
231 
232  // if the name of the scale parameter doesn't appear in the list of
233  // free parameters set the index to -1 and watch for this below
234  map< string, int >::const_iterator idx2 = m_parIndex.find( ampScaleName( *conjAmp ) );
235  int JScale = ( idx2 == m_parIndex.end() ? -1 : idx2->second );
236 
237  // if the two amplitudes are from different reactions then they do not add coherently
238  // and we should set the integral of A A* to zero
239  // for amplitudes from different sums within the same reaction, this happens
240  // automatically in the normalization integral interface
241  complex< double > ampInt;
242  if( reaction == conjReaction ){
243 
244  if (accCorrected) ampInt = m_normIntMap.find(reaction)->second->ampInt( *amp, *conjAmp );
245  else ampInt = m_normIntMap.find(reaction)->second->normInt( *amp, *conjAmp );
246  }
247  else{
248 
249  ampInt = complex< double >( 0 , 0 );
250  }
251 
252  // copy a 3 x 3 block into the small error matrix
253 
254  errorMatrix[iRe][jRe] = m_covMatrix[IRe][JRe];
255  errorMatrix[iRe][jIm] = m_covMatrix[IRe][JIm];
256  errorMatrix[iRe][jScale] =
257  ( JScale == -1 ? 0 : m_covMatrix[IRe][JScale] );
258  errorMatrix[iIm][jRe] = m_covMatrix[IIm][JRe];
259  errorMatrix[iIm][jIm] = m_covMatrix[IIm][JIm];
260  errorMatrix[iIm][jScale] =
261  ( JScale == -1 ? 0 : m_covMatrix[IIm][JScale] );
262  errorMatrix[iScale][jRe] =
263  ( IScale == -1 ? 0 : m_covMatrix[IScale][JRe] );
264  errorMatrix[iScale][jIm] =
265  ( IScale == -1 ? 0 : m_covMatrix[IScale][JIm] );
266  errorMatrix[iScale][jScale] =
267  ( IScale == -1 || JScale == -1 ? 0 : m_covMatrix[IScale][JScale] );
268 
269  deriv[iRe] += 2 * ampScale( *amp ) * ampScale( *conjAmp ) *
270  ( m_parValues[JRe] * real( ampInt ) + m_parValues[JIm] * imag( ampInt ) );
271  deriv[iIm] += 2 * ampScale( *amp ) * ampScale( *conjAmp ) *
272  ( m_parValues[JIm] * real( ampInt ) - m_parValues[JRe] * imag( ampInt ) );
273 
274  double intensityContrib = ampScale( *amp ) * ampScale( *conjAmp ) *
275  ( ( m_parValues[IRe] * m_parValues[JRe] + m_parValues[IIm] * m_parValues[JIm] ) * real( ampInt ) -
276  ( m_parValues[IIm] * m_parValues[JRe] - m_parValues[IRe] * m_parValues[JIm] ) * imag( ampInt ) );
277 
278  deriv[iScale] += 2. * ampScale( *conjAmp ) * (
279  ( m_parValues[IRe] * m_parValues[JRe] + m_parValues[IIm] * m_parValues[JIm]) * real( ampInt ) +
280  ( m_parValues[IRe] * m_parValues[JIm] - m_parValues[IIm] * m_parValues[JRe]) * imag( ampInt ));
281 
282  intensity += intensityContrib;
283  }
284  }
285 
286  // now compute the error
287  double variance = 0;
288  for( unsigned int i = 0; i < deriv.size(); ++i ){
289  for( unsigned int j = 0; j < deriv.size(); ++j ){
290 
291  variance += deriv[i] * deriv[j] * errorMatrix[i][j];
292  }
293  }
294 
295  return pair< double, double >( intensity, sqrt( variance ) );
296 }
297 
298 pair< double, double >
299 FitResults::phaseDiff( const string& amp1, const string& amp2 ) const {
300 
301  vector< string > knownAmps = ampList();
302  if( ( find( knownAmps.begin(), knownAmps.end(), amp1 ) == knownAmps.end() ) ||
303  ( find( knownAmps.begin(), knownAmps.end(), amp2 ) == knownAmps.end() ) ){
304 
305  cout << "FitResults ERROR: unkown amplitude(s) in phase difference calculation\n\t"
306  << amp1 << " and/or " << amp2 << endl;
307  assert( false );
308  }
309 
310  vector<string> ampNameParts = stringSplit( amp1, "::" );
311  assert( ampNameParts.size() == 3 );
312  string reaction1 = ampNameParts[0];
313  string sum1 = ampNameParts[1];
314 
315  ampNameParts = stringSplit( amp2, "::" );
316  assert( ampNameParts.size() == 3 );
317  string reaction2 = ampNameParts[0];
318  string sum2 = ampNameParts[1];
319 
320  if( ( reaction1 != reaction2 ) || ( sum1 != sum2 ) ){
321 
322  cout << "FitResults WARNING:: request to compute phase difference of " << endl
323  << " amplitudes from different sums or different" << endl
324  << " reactions which is not meaningful, returning 0. " << endl
325  << " amp1: " << amp1 << endl
326  << " amp2: " << amp2 << endl;
327 
328  return pair< double, double >( 0, 0 );
329  }
330 
331  // The phase difference depends only on two parameters, the real and imaginary
332  // components of the two amplitudes. It is independent of the scale of the
333  // amplitudes.
334  vector< int > idx( 4 );
335  idx[0] = m_parIndex.find( realProdParName( amp1 ) )->second;
336  idx[1] = m_parIndex.find( imagProdParName( amp1 ) )->second;
337  idx[2] = m_parIndex.find( realProdParName( amp2 ) )->second;
338  idx[3] = m_parIndex.find( imagProdParName( amp2 ) )->second;
339 
340  // this makes the code a little easier to read
341  double a1Re = m_parValues[idx[0]];
342  double a1Im = m_parValues[idx[1]];
343  double a2Re = m_parValues[idx[2]];
344  double a2Im = m_parValues[idx[3]];
345 
346  vector< double > pDeriv( 4 );
347  pDeriv[0] = ( -a1Im / ( a1Re * a1Re + a1Im * a1Im ) );
348  pDeriv[1] = ( a1Re / ( a1Re * a1Re + a1Im * a1Im ) );
349  pDeriv[2] = ( a2Im / ( a2Re * a2Re + a2Im * a2Im ) );
350  pDeriv[3] = ( -a2Re / ( a2Re * a2Re + a2Im * a2Im ) );
351 
352  double pVar = 0;
353  for( unsigned int i = 0; i < pDeriv.size(); ++i ){
354  for( unsigned int j = 0; j < pDeriv.size(); ++j ){
355 
356  pVar += pDeriv[i] * pDeriv[j] * m_covMatrix[idx[i]][idx[j]];
357  }
358  }
359 
360  return pair< double, double >( arg( complex< double > ( a1Re, a1Im ) ) -
361  arg( complex< double > ( a2Re, a2Im ) ),
362  sqrt(pVar) );
363 }
364 
365 const NormIntInterface*
366 FitResults::normInt( const string& reactionName ) const {
367 
368  map< string, NormIntInterface* >::const_iterator nameNormInt =
369  m_normIntMap.find( reactionName );
370 
371  if( nameNormInt == m_normIntMap.end() ){
372 
373  cout << "FitResults ERROR: requesting NormIntInterface for reaction "
374  << "that does not exist: " << reactionName << endl;
375 
376  cout << " Returning a NULL pointer that may result in a segfault."
377  << endl;
378 
379  return NULL;
380  }
381 
382  return nameNormInt->second;
383 }
384 
385 string
386 FitResults::realProdParName( const string& amplitude ) const {
387 
388  string parName = amplitude + "_re";
389 
390  // be sure the parameter actually exists before returning its name
391  // if this fails, then a bogus amplitude name was passed in
392  assert( m_parIndex.find( parName ) != m_parIndex.end() );
393 
394  return parName;
395 }
396 
397 string
398 FitResults::imagProdParName( const string& amplitude ) const {
399 
400  string parName = amplitude + "_im";
401 
402  // be sure the parameter actually exists before returning its name
403  // if this fails, then a bogus amplitude name was passed in
404  assert( m_parIndex.find( parName ) != m_parIndex.end() );
405 
406  return parName;
407 }
408 
409 string
410 FitResults::ampScaleName( const string& amplitude ) const {
411 
412  // the vector of amplitudes should be "full" amplitude names
413  // that include the reaction, sum, and amplitude name
414 
415  vector<string> ampNameParts = stringSplit( amplitude, "::" );
416  assert( ampNameParts.size() == 3 );
417  string reaction = ampNameParts[0];
418 
419  map< string, int >::const_iterator reactIndexPair = m_reacIndex.find( reaction );
420 
421  if( reactIndexPair == m_reacIndex.end() ){
422 
423  cout << "FitResults::ampScaleName ERROR:: no such reaction: " << reaction << endl;
424  assert( false );
425  }
426 
427  map< string, int >::const_iterator ampIndexPair =
428  m_ampIndex.at(reactIndexPair->second).find( amplitude );
429 
430  if( ampIndexPair == m_ampIndex.at(reactIndexPair->second).end() ){
431 
432  cout << "FitResults::ampScaleName ERROR:: no such amplitude: " << amplitude << endl;
433  assert( false );
434  }
435 
436  return m_ampScaleNames.at( reactIndexPair->second ).at( ampIndexPair->second );
437 }
438 
439 map< string, complex< double > >
441 
442  map< string, complex< double > > ampMap;
443 
444  vector< string > amps = ampList();
445  for( vector< string >::iterator amp = amps.begin();
446  amp != amps.end();
447  ++amp ){
448 
449  ampMap[*amp] = productionParameter( *amp );
450  }
451 
452  return ampMap;
453 }
454 
455 map< string, double >
457 
458  map< string, double > ampMap;
459 
460  vector< string > amps = ampList();
461  for( vector< string >::iterator amp = amps.begin();
462  amp != amps.end();
463  ++amp ){
464 
465  ampMap[*amp] = ampScale( *amp );
466  }
467 
468  return ampMap;
469 }
470 
471 map< string, double >
473 
474  map< string, double > parMap;
475 
476  vector< ParameterInfo* > parList = m_cfgInfo->parameterList();
477 
478  for( vector< ParameterInfo* >::iterator par = parList.begin();
479  par != parList.end(); ++par ){
480 
481  if( (**par).fixed() ) continue;
482 
483  parMap[(**par).parName()] = parValue( (**par).parName() );
484  }
485 
486  return parMap;
487 }
488 
489 complex< double >
490 FitResults::productionParameter( const string& ampName ) const {
491 
492  int iRe = m_parIndex.find( realProdParName( ampName ) )->second;
493  int iIm = m_parIndex.find( imagProdParName( ampName ) )->second;
494 
495  return complex< double >( m_parValues[iRe], m_parValues[iIm] );
496 }
497 
498 
499 complex< double >
500 FitResults::scaledProductionParameter( const string& ampName ) const {
501 
502  return productionParameter( ampName ) * ampScale( ampName );
503 }
504 
505 double
506 FitResults::parValue( const string& parName ) const {
507 
508  map< string, int >::const_iterator parIndexPair = m_parIndex.find( parName );
509 
510  if( parIndexPair == m_parIndex.end() ){
511 
512  cout << "FitResults:: ERROR: request for unknown parameter " << parName << endl
513  << " returning nan." << endl;
514 
515  return sqrt( -1 );
516  }
517 
518  return m_parValues[parIndexPair->second];
519 }
520 
521 double
522 FitResults::parError( const string& parName ) const {
523 
524  return sqrt( covariance( parName, parName ) );
525 }
526 
527 double
528 FitResults::covariance( const string& par1, const string& par2 ) const {
529 
530  map< string, int >::const_iterator par1Pair = m_parIndex.find( par1 );
531  map< string, int >::const_iterator par2Pair = m_parIndex.find( par2 );
532 
533  if( par1Pair == m_parIndex.end() || par2Pair == m_parIndex.end() ){
534 
535  cout << "FitResults:: ERROR: request for covaraince of unkown parameters "
536  << par1 << ", " << par2 << endl
537  << " returning nan" << endl;
538  return sqrt( -1 );
539  }
540 
541  return m_covMatrix[par1Pair->second][par2Pair->second];
542 }
543 
544 double
545 FitResults::ampScale( const string& amplitude ) const {
546 
547  // this needs a full amplitude name: react::sum::amp
548 
549  vector<string> ampNameParts = stringSplit( amplitude, "::" );
550  assert( ampNameParts.size() == 3 );
551  string reaction = ampNameParts[0];
552 
553  map< string, int >::const_iterator reactIndexPair = m_reacIndex.find( reaction );
554 
555  if( reactIndexPair == m_reacIndex.end() ){
556 
557  cout << "FitResults::ampScaleName ERROR:: no such reaction: " << reaction << endl;
558  assert( false );
559  }
560 
561  map< string, int >::const_iterator ampIndexPair =
562  m_ampIndex.at(reactIndexPair->second).find( amplitude );
563 
564  if( ampIndexPair == m_ampIndex.at(reactIndexPair->second).end() ){
565 
566  cout << "FitResults::ampScaleName ERROR:: no such amplitude: " << amplitude << endl;
567  assert( false );
568  }
569 
570  return m_ampScaleValues.at( reactIndexPair->second ).at( ampIndexPair->second );
571 }
572 
573 vector< string >
575 
576  vector< string > list;
577 
578  for( vector< string >::const_iterator reacItr = m_reactionNames.begin();
579  reacItr != m_reactionNames.end();
580  ++reacItr ){
581 
582  vector< string > thisReacList = ampList( *reacItr );
583 
584  for( vector< string >::iterator ampItr = thisReacList.begin();
585  ampItr != thisReacList.end();
586  ++ampItr ){
587 
588  list.push_back( *ampItr );
589  }
590  }
591 
592  return list;
593 }
594 
595 vector< string >
596 FitResults::ampList( const string& reaction ) const {
597 
598  map< string, int >::const_iterator reacIndex = m_reacIndex.find( reaction );
599 
600  if( reacIndex == m_reacIndex.end() ){
601 
602  cerr << "FitResults ERROR:: unkown reaction: " << reaction << endl;
603  assert( false );
604  }
605 
606  return m_ampNames[reacIndex->second];
607 }
608 
609 void
611 
612  if( !m_createdFromFile ){
613 
614  recordAmpSetup();
615  recordLikelihood();
616  recordParameters();
617  recordFitStats();
618  }
619 }
620 
621 void
622 FitResults::writeResults( const string& outFile ) const {
623 
624  ofstream output( outFile.c_str() );
625 
626  output.precision( 15 );
627 
628  output << "*** DO NOT EDIT THIS FILE - IT IS FORMATTED FOR INPUT ***" << endl;
629  output << "+++ Reactions, Amplitudes, and Scale Parameters +++" << endl;
630  output << " " << m_numReactions << endl;
631  for( int i = 0; i < m_numReactions; ++i ){
632 
633  output << " " <<m_reactionNames[i] << "\t" << m_numAmps[i] << endl;
634 
635  for( int j = 0; j < m_ampNames[i].size(); ++j ) {
636 
637  output << " " <<m_ampNames[i][j] << "\t"
638  << m_ampScaleNames[i][j] << "\t"
639  << m_ampScaleValues[i][j] << endl;
640  }
641  }
642 
643  output << "+++ Likelihood Total and Partial Sums +++" << endl;
644  output << " " <<m_likelihoodTotal << endl;
645  for( int i = 0; i < m_numReactions; ++i ){
646 
647  output << " " <<m_reactionNames[i] << "\t"
648  << m_likelihoodMap.find(m_reactionNames[i])->second << endl;
649  }
650 
651  output << "+++ Fitter Information +++" << endl;
652  output << " " << "lastMinuitCommand\t" << m_lastCommand << endl;
653  output << " " << "lastMinuitCommandStatus\t" << m_lastCommandStatus << endl;
654  output << " " << "eMatrixStatus\t" << m_eMatrixStatus << endl;
655  output << " " << "minuitPrecision\t" << m_precision << endl;
656  output << " " << "minuitStrategy\t" << m_strategy << endl;
657  output << " " << "estDistToMinimum\t" << m_estDistToMin << endl;
658  output << " " << "bestMinimum\t" << m_bestMin << endl;
659 
660  output << "+++ Parameter Values and Errors +++" << endl;
661  output << " " << m_parNames.size() << endl;
662  for( int i = 0; i < m_parNames.size(); ++i ){
663 
664  output << " " <<m_parNames[i] << "\t" << m_parValues[i] << endl;
665  }
666 
667  for( int i = 0; i < m_parNames.size(); ++i ){
668  for( int j = 0; j < m_parNames.size(); ++j ){
669 
670  output << " " << m_covMatrix[i][j] << "\t";
671  }
672 
673  output << endl;
674  }
675 
676  // here we will use the NormIntInterface rather than replicating the
677  // functionality that is already found there
678 
679  output << "+++ Normalization Integrals +++" << endl;
680 
681  for( int i = 0; i < m_reactionNames.size(); ++i ){
682 
683  string reac = m_reactionNames[i];
684  output << " " << reac << endl;
685 
686  const NormIntInterface* ni = m_normIntMap.find(reac)->second;
687 
688  if( m_createdFromFile || !ni->hasAccessToMC() ){
689 
690  ni->exportNormIntCache( output );
691  }
692  else{
693  ni->forceCacheUpdate();
694  ni->exportNormIntCache( output,
695  m_intenManVec[i]->termsAreRenormalized() );
696  }
697  }
698 
699  output << "+++ Below these two lines is a config file that is +++" << endl;
700  output << "+++ functionally equivalent to that used in the fit. +++" << endl;
701  output << *m_cfgInfo;
702 
703  output.close();
704 }
705 
706 void
707 FitResults::writeSeed( const string& outFile ) const {
708 
709  ofstream output( outFile.c_str() );
710  output.precision( 15 );
711 
712  vector< string > amps = ampList();
713  for( vector< string >::const_iterator amp = amps.begin();
714  amp != amps.end();
715  ++amp ){
716 
717  vector<string> parts = stringSplit( *amp, "::" );
718  assert( parts.size() == 3 );
719  AmplitudeInfo* ampInfo =
720  m_cfgInfo->amplitude( parts[0], parts[1], parts[2] );
721 
722  output << "initialize " << *amp << " cartesian "
723  << parValue( realProdParName( *amp ) ) << " "
724  << parValue( imagProdParName( *amp ) );
725 
726  if( ampInfo->fixed() )
727  output << " fixed";
728 
729  if( ampInfo->real() )
730  output << " real";
731 
732  output << endl;
733  }
734 
735  map< string, double > ampPars = ampParMap();
736  for( map< string, double >::const_iterator par = ampPars.begin();
737  par != ampPars.end();
738  ++par ){
739 
740  output << "parameter " << par->first << " " << par->second;
741 
742  ParameterInfo* parInfo = m_cfgInfo->parameter( par->first );
743 
744  if( parInfo->fixed() )
745  output << " fixed";
746 
747  if( parInfo->bounded() )
748  output << " bounded " << parInfo->lowerBound()
749  << " " << parInfo->upperBound();
750 
751  if( parInfo->gaussianBounded() )
752  output << " gaussian " << parInfo->centralValue()
753  << " " << parInfo->gaussianError();
754  }
755 }
756 
757 void
758 FitResults::loadResults( const string& inFile ){
759 
760  enum { kMaxLine = 256 };
761  char line[kMaxLine];
762  string tmp;
763 
764  ifstream input( inFile.c_str() );
765 
766  if( input.fail() ){
767 
768  cerr << "ERROR:: FitResults file does not exist: " << inFile << endl;
769  return;
770  }
771 
772  input.getline( line, kMaxLine ); // top message
773  input.getline( line, kMaxLine ); // amp manager heading
774 
775  input >> m_numReactions;
776 
777  m_reactionNames.resize( m_numReactions );
778  m_numAmps.resize( m_numReactions );
779  m_ampNames.resize( m_numReactions );
780  m_ampScaleNames.resize( m_numReactions );
781  m_ampScaleValues.resize( m_numReactions );
782  m_ampIndex.resize( m_numReactions );
783 
784  for( int i = 0; i < m_numReactions; ++i ){
785 
786  input >> m_reactionNames[i] >> m_numAmps[i];
787 
788  m_reacIndex[m_reactionNames[i]] = i;
789 
790  m_ampNames[i].resize( m_numAmps[i] );
791  m_ampScaleNames[i].resize( m_numAmps[i] );
792  m_ampScaleValues[i].resize( m_numAmps[i] );
793 
794  for( int j = 0; j < m_ampNames[i].size(); ++j ) {
795 
796  input >> m_ampNames[i][j]
797  >> m_ampScaleNames[i][j]
798  >> m_ampScaleValues[i][j];
799 
800  m_ampIndex[i][m_ampNames[i][j]] = j;
801  }
802  }
803 
804  // one getline clears the newline waiting in the buffer
805  input.getline( line, kMaxLine ); // likelihood heading
806  input.getline( line, kMaxLine ); // likelihood heading
807 
808  input >> m_likelihoodTotal;
809 
810  double val;
811  for( int i = 0; i < m_numReactions; ++i ){
812 
813  input >> tmp >> val;
814  m_likelihoodMap[tmp] = val;
815  }
816 
817  input.getline( line, kMaxLine ); // fit info heading
818  input.getline( line, kMaxLine ); // fit info heading
819 
820  input >> tmp >> m_lastCommand;
821  input >> tmp >> m_lastCommandStatus;
822  input >> tmp >> m_eMatrixStatus;
823  input >> tmp >> m_precision;
824  input >> tmp >> m_strategy;
825  input >> tmp >> m_estDistToMin;
826  input >> tmp >> m_bestMin;
827 
828  input.getline( line, kMaxLine ); // parameters heading
829  input.getline( line, kMaxLine ); // parameters heading
830 
831  int nPar;
832  input >> nPar;
833  m_parNames.resize( nPar );
834  m_parValues.resize( nPar );
835  m_covMatrix.resize( nPar );
836 
837  for( int i = 0; i < m_parNames.size(); ++i ){
838 
839  input >> m_parNames[i] >> m_parValues[i];
840  m_parIndex[m_parNames[i]] = i;
841  }
842 
843  for( int i = 0; i < m_parNames.size(); ++i ){
844 
845  m_covMatrix[i].resize( nPar );
846  for( int j = 0; j < m_parNames.size(); ++j ){
847 
848  input >> m_covMatrix[i][j];
849  }
850  }
851 
852  // here we will use the NormIntInterface rather than replicating the
853  // functionality that is already found there
854 
855  input.getline( line, kMaxLine ); // norm int heading
856  input.getline( line, kMaxLine ); // norm int heading
857 
858  for( int i = 0; i < m_numReactions; ++i ){
859 
860  string reac;
861  input >> reac;
862  m_normIntMap[reac] = new NormIntInterface();
863  input >> (*m_normIntMap[reac]);
864  }
865 
866  // now read back in the ConfigurationInfo using the ConfigFileParser
867  input.getline( line, kMaxLine ); // cfg info heading
868  input.getline( line, kMaxLine ); // cfg info heading
869  input.getline( line, kMaxLine ); // cfg info heading
870 
871  ConfigFileParser cfgParser( input );
872  m_cfgInfo = cfgParser.getConfigurationInfo();
873 
874  input.close();
875 
876  // set this to true after the load completes - this allows testing
877  // of validity when reading results from a file
878 
879  m_isValid = true;
880 }
881 
882 void
883 FitResults::recordAmpSetup(){
884 
885  m_numReactions = m_intenManVec.size();
886 
887  m_numAmps.clear();
888  m_reactionNames.clear();
889  m_ampNames.clear();
890  m_ampScaleNames.clear();
891  m_ampScaleValues.clear();
892 
893  m_reacIndex.clear();
894  m_ampIndex.clear();
895 
896  for( int i = 0; i < m_intenManVec.size(); ++i ){
897 
898  IntensityManager* intenMan = m_intenManVec[i];
899 
900  m_reacIndex[intenMan->reactionName()] = i;
901  m_reactionNames.push_back( intenMan->reactionName() );
902 
903  vector< string > ampNames = intenMan->getTermNames();
904 
905  m_ampNames.push_back( ampNames );
906  m_ampIndex.push_back( map< string, int >() );
907  m_numAmps.push_back( ampNames.size() );
908 
909  vector< string > ampScaleNames( 0 );
910  vector< double > ampScaleValues( 0 );
911 
912  for( int j = 0; j < ampNames.size(); ++j ){
913 
914  ampScaleNames.push_back( intenMan->getScale( ampNames[j] ).name() );
915  ampScaleValues.push_back( intenMan->getScale( ampNames[j] ) );
916 
917  m_ampIndex[i][ampNames[j]] = j;
918  }
919 
920  m_ampScaleNames.push_back( ampScaleNames );
921  m_ampScaleValues.push_back( ampScaleValues );
922  }
923 }
924 
925 void
926 FitResults::recordLikelihood(){
927 
928  m_likelihoodTotal = 0;
929 
930  for( map< string, LikelihoodCalculator* >::iterator
931  mapItr = m_likCalcMap.begin();
932  mapItr != m_likCalcMap.end();
933  ++mapItr ){
934 
935  double thisLikVal = (*(mapItr->second))();
936 
937  m_likelihoodTotal += thisLikVal;
938  m_likelihoodMap[mapItr->first] = thisLikVal;
939  }
940 }
941 
942 void
943 FitResults::recordParameters(){
944 
945  m_parNames = m_parManager->parameterList();
946  m_parValues = m_parManager->parameterValues();
947  m_covMatrix = m_parManager->covarianceMatrix();
948 
949  for( int i = 0; i < m_parNames.size(); ++i ){
950 
951  m_parIndex[m_parNames[i]] = i;
952  }
953 
954 }
955 
956 void
957 FitResults::recordFitStats(){
958 
959  m_eMatrixStatus = m_minManager->eMatrixStatus();
960  m_lastCommandStatus = m_minManager->status();
961  m_lastCommand = m_minManager->lastCommand();
962  m_precision = m_minManager->precision();
963  m_strategy = m_minManager->strategy();
964  m_estDistToMin = m_minManager->estDistToMinimum();
965  m_bestMin = m_minManager->bestMinimum();
966 }
967 
968 void
970 {
971 
972  string reactionName;
973 
974  // loop over the reactions
975  vector< ReactionInfo* > reactionInfo = m_cfgInfo->reactionList();
976  for( vector< ReactionInfo* >::const_iterator reactionInfoItr = reactionInfo.begin(); reactionInfoItr != reactionInfo.end(); ++reactionInfoItr ){
977 
978  reactionName = (**reactionInfoItr).reactionName();
979 
980  // get a list of the coherent sums
981  vector< string > sumNames;
982  vector< CoherentSumInfo* > sumInfo = m_cfgInfo->coherentSumList( reactionName );
983  for( vector< CoherentSumInfo* >::const_iterator sumInfoItr = sumInfo.begin(); sumInfoItr != sumInfo.end(); ++sumInfoItr ){
984  sumNames.push_back( (**sumInfoItr).sumName() );
985  }
986 
987  // Get all of the amplitudes, independent of sums
988  vector< string > allAmpNames;
989  vector< AmplitudeInfo* > ampInfoEachSum;
990  for( unsigned int sum = 0; sum < sumNames.size(); sum++ ){
991  ampInfoEachSum = m_cfgInfo->amplitudeList( reactionName, sumNames[sum] );
992  for( vector< AmplitudeInfo* >::const_iterator ampInfoItr = ampInfoEachSum.begin(); ampInfoItr != ampInfoEachSum.end(); ++ampInfoItr ){
993  allAmpNames.push_back( (**ampInfoItr).fullName() );
994  }
995  }
996 
997  // loop over the coherent sums
998  for( unsigned int sum = 0; sum < sumNames.size(); sum++ ){
999 
1000  // flags to determine whether a rotation of reflection is necessary
1001  bool rotate = false;
1002  bool foundRealAmp = false;
1003  bool reflect = false;
1004  double totalIm = 0.0;
1005 
1006  // make a list of the amplitudes
1007  vector< string > ampNames;
1008  vector< AmplitudeInfo* > ampInfo = m_cfgInfo->amplitudeList( reactionName, sumNames[sum] );
1009  for( vector< AmplitudeInfo* >::const_iterator ampInfoItr = ampInfo.begin(); ampInfoItr != ampInfo.end(); ++ampInfoItr ){
1010 
1011  ampNames.push_back( (**ampInfoItr).fullName() );
1012 
1013  string reParName = realProdParName( (**ampInfoItr).fullName() );
1014  string imParName = imagProdParName( (**ampInfoItr).fullName() );
1015 
1016  int reIndex = m_parIndex.find( reParName )->second;
1017  int imIndex = m_parIndex.find( imParName )->second;
1018 
1019  // Index of scale and scale itself are
1020  // initialized to -1 and 1, respectively.
1021  // The index acts as a flag of whether the scale exists.
1022  int scIndex = -1;
1023  double scale = 1.0;
1024 
1025  // check if scale parameter exists
1026  if(ampScaleName(ampNames[ampNames.size()-1]) != "-"){
1027  // if it exists, set the index and scale value
1028  scIndex = m_parIndex.find( ampScaleName( ampNames[ampNames.size()-1] ))->second;
1029  scale = m_parValues[scIndex];
1030  }
1031 
1032  // check if a rotation is necessary
1033  if( (**ampInfoItr).real() == true && foundRealAmp == false ){
1034  foundRealAmp = true;
1035  if( m_parValues[reIndex] * scale < 0 )
1036  rotate = true;
1037  }
1038 
1039  // if the amplitude is not constrained to be real, check if
1040  // it is constrained to be the same as any real amplitudes
1041  if( foundRealAmp == false ){
1042  const vector< AmplitudeInfo* > constraints = (**ampInfoItr).constraints();
1043  for( vector< AmplitudeInfo* >::const_iterator conInfoItr = constraints.begin(); conInfoItr != constraints.end(); ++conInfoItr ){
1044  if( (**conInfoItr).real() == true && foundRealAmp == false ){
1045  foundRealAmp = true;
1046  if( m_parValues[reIndex] * scale < 0 )
1047  rotate = true;
1048  }
1049  }
1050  }
1051 
1052  totalIm += scale * m_parValues[imIndex];
1053  }
1054 
1055  // check if a reflection is necessary
1056  if( totalIm < 0 ) reflect = true;
1057 
1058  // if not, move on to the next sum
1059  if( rotate == false && reflect == false ) continue;
1060 
1061  // loop over amplitudes and make any necessary changes
1062  for( unsigned int amp = 0; amp < ampNames.size(); amp++ ){
1063 
1064  string reParName = realProdParName( ampNames[amp] );
1065  string imParName = imagProdParName( ampNames[amp] );
1066 
1067  int reIndex = m_parIndex.find( reParName )->second;
1068  int imIndex = m_parIndex.find( imParName )->second;
1069 
1070  if( rotate == true )
1071  m_parValues[reIndex] *= -1.0;
1072 
1073  if( reflect == true && m_parValues[imIndex] != 0.0 )
1074  m_parValues[imIndex] *= -1.0;
1075 
1076  // Get the sum name for this amp.
1077  // This is used when flipping the scale elements of
1078  // the ovariance matrix.
1079  vector<string> ampNameParts = stringSplit( ampNames[amp], "::" );
1080  string sumAmp = ampNameParts[1];
1081 
1082  // also make the necessary changes to the covariance matrix
1083  for( unsigned int conjAmp = 0; conjAmp < allAmpNames.size(); conjAmp++ ){
1084 
1085  string imConjParName = imagProdParName( allAmpNames[conjAmp] );
1086  int imConjIndex = m_parIndex.find( imConjParName )->second;
1087 
1088  string scConjParName = ampScaleName( allAmpNames[conjAmp] );
1089  int scConjIndex = -1;
1090  if(scConjParName != "-") scConjIndex = m_parIndex.find( scConjParName )->second;
1091 
1092  if( rotate == true ){
1093  m_covMatrix[reIndex][imConjIndex] *= -1.0;
1094  m_covMatrix[imConjIndex][reIndex] *= -1.0;
1095 
1096  // For scale parameters, each scale parameter is saved as
1097  // one entry in the covariance matrix, in contrast with
1098  // each production amplitude appearing once for each sum.
1099  // Therefore, we need to flip the sign only when the sums
1100  // of the amp and conjAmp are the same.
1101  // Otherwise, we will flip the covariance matrix n times,
1102  // where n is the number of sums.
1103  if(scConjIndex!=-1){
1104 
1105  vector<string> conjAmpNameParts = stringSplit( allAmpNames[conjAmp], "::" );
1106  string sumConjAmp = conjAmpNameParts[1];
1107  cout << "sum name of conjAmp = " << sumConjAmp << endl;
1108  if(sumAmp == sumConjAmp){
1109  // cout << "rotate: flipping sign for scConjIndex = " << scConjIndex << endl;
1110  m_covMatrix[reIndex][scConjIndex] *= -1.0;
1111  m_covMatrix[scConjIndex][reIndex] *= -1.0;
1112  }
1113  }
1114 
1115  }
1116 
1117  string reConjParName = realProdParName( allAmpNames[conjAmp] );
1118  int reConjIndex = m_parIndex.find( reConjParName )->second;
1119 
1120  if( reflect == true ){
1121  m_covMatrix[imIndex][reConjIndex] *= -1.0;
1122  m_covMatrix[reConjIndex][imIndex] *= -1.0;
1123 
1124  // For scale parameters, each scale parameter is saved as
1125  // one entry in the covariance matrix, in contrast with
1126  // each production amplitude appearing once for each sum.
1127  // Therefore, we need to flip the sign only when the sums
1128  // of the amp and conjAmp are the same.
1129  // Otherwise, we will flip the covariance matrix n times,
1130  // where n is the number of sums.
1131  if(scConjIndex!=-1){
1132 
1133  vector<string> conjAmpNameParts = stringSplit( allAmpNames[conjAmp], "::" );
1134  string sumConjAmp = conjAmpNameParts[1];
1135  if(sumAmp == sumConjAmp){
1136  m_covMatrix[imIndex][scConjIndex] *= -1.0;
1137  m_covMatrix[scConjIndex][imIndex] *= -1.0;
1138  }
1139  } // found scConjIndex
1140 
1141  }
1142  }
1143  } // end of nested loop over amplitudes
1144  } // end of loop over sums
1145  } // end of loop over reactions
1146 }
1147 
1148 void
1149 FitResults::writeFitResults( const string& outFile ){
1150 
1151  ofstream output( outFile.c_str() );
1152 
1153  output << m_numAmps[0]/4. << "\t0" << endl;
1154 
1155  for( unsigned int i = 0; i < m_parNames.size()-1; i++ ){
1156  const char* reactName = m_parNames[i].substr( 8, 4 ).c_str();
1157  if( strcmp( reactName, "amp1" ) != 0 ) continue;
1158  const char* lastChars = m_parNames[i].substr( m_parNames[i].size() - 2, 2 ).c_str();
1159  if( strcmp( lastChars, "im" ) == 0 ){
1160  output << m_parNames[i].substr( 0, m_parNames[i].size() - 3 );
1161  if( m_parValues[i] == 0 && m_covMatrix[i][i] == 0 ) output << "+";
1162  output << "\t(" << m_parValues[i-1] << "," << m_parValues[i] << ")" << endl;
1163  }
1164  }
1165 
1166  for( unsigned int i = 0; i < m_parNames.size()-1; i++ ){
1167  const char* reactNamei = m_parNames[i].substr( 8, 4 ).c_str();
1168  if( strcmp( reactNamei, "amp1" ) != 0 ) continue;
1169  const char* lastCharsi = m_parNames[i].substr( m_parNames[i].size() - 2, 2 ).c_str();
1170  if( strcmp( lastCharsi, "im" ) == 0 && m_parValues[i] == 0 && m_covMatrix[i][i] == 0 ) continue;
1171  for( unsigned int j = 0; j < m_parNames.size()-1; j++ ){
1172  const char* reactNamej = m_parNames[j].substr( 8, 4 ).c_str();
1173  if( strcmp( reactNamej, "amp1" ) == 0 ){
1174  const char* lastCharsj = m_parNames[j].substr( m_parNames[j].size() - 2, 2 ).c_str();
1175  if( strcmp( lastCharsj, "im" ) == 0 && m_parValues[j] == 0 && m_covMatrix[j][j] == 0 ) continue;
1176  output << m_covMatrix[i][j] << "\t";
1177  }
1178  }
1179  output << endl;
1180  }
1181 
1182  output.close();
1183 }
1184 
1185 vector< string >
1186 FitResults::stringSplit(const string& str, const string& delimiters ) const
1187 {
1188 
1189  vector< string > tokens;
1190 
1191  string::size_type lastPos = str.find_first_not_of(delimiters, 0);
1192  string::size_type pos = str.find_first_of(delimiters, lastPos);
1193 
1194  while (string::npos != pos || string::npos != lastPos)
1195  {
1196  tokens.push_back(str.substr(lastPos, pos - lastPos));
1197  lastPos = str.find_first_not_of(delimiters, pos);
1198  pos = str.find_first_of(delimiters, lastPos);
1199  }
1200 
1201  return tokens;
1202 }
complex< double > productionParameter(const string &ampName) const
Definition: FitResults.cc:490
void rotateResults()
Definition: FitResults.cc:969
bool fixed() const
ConfigurationInfo * getConfigurationInfo()
string reactionName() const
vector< CoherentSumInfo * > coherentSumList(const string &reactionName="", const string &sumName="") const
void exportNormIntCache(const string &fileName, bool renormalize=false) const
void writeSeed(const string &fileName) const
Definition: FitResults.cc:707
double gaussianError() const
double covariance(const string &par1, const string &par2) const
Definition: FitResults.cc:528
bool gaussianBounded() const
string name() const
Definition: AmpParameter.h:94
vector< vector< double > > covarianceMatrix() const
ParameterInfo * parameter(const string &parName) const
complex< double > scaledProductionParameter(const string &ampName) const
Definition: FitResults.cc:500
double ampScale(const string &ampName) const
Definition: FitResults.cc:545
double parValue(const string &parName) const
Definition: FitResults.cc:506
bool bounded() const
double upperBound() const
void writeResults(const string &fileName) const
Definition: FitResults.cc:622
virtual void forceCacheUpdate(bool normIntOnly=false) const
const NormIntInterface * normInt(const string &reactionName) const
Definition: FitResults.cc:366
vector< double > parameterValues() const
void loadResults(const string &fileName)
Definition: FitResults.cc:758
pair< double, double > phaseDiff(const string &amp1, const string &amp2) const
Definition: FitResults.cc:299
const vector< string > & getTermNames() const
#define NULL
Definition: URtypes.h:72
map< string, complex< double > > ampProdParMap() const
Definition: FitResults.cc:440
double sqrt(double)
double parError(const string &parName) const
Definition: FitResults.cc:522
bool hasAccessToMC() const
AmplitudeInfo * amplitude(const string &reactionName, const string &sumName, const string &ampName) const
double likelihood() const
Definition: FitResults.h:145
pair< double, double > intensity(bool accCorrected=true) const
Definition: FitResults.cc:107
map< string, double > ampScaleParMap() const
Definition: FitResults.cc:456
const AmpParameter & getScale(const string &name) const
const vector< vector< double > > & errorMatrix() const
Definition: FitResults.h:381
void writeFitResults(const string &fileName)
Definition: FitResults.cc:1149
double lowerBound() const
string realProdParName(const string &amplitude) const
Definition: FitResults.cc:386
vector< ParameterInfo * > parameterList(const string &reactionName="", const string &sumName="", const string &ampName="", const string &parName="") const
string ampScaleName(const string &amplitude) const
Definition: FitResults.cc:410
vector< AmplitudeInfo * > amplitudeList(const string &reactionName="", const string &sumName="", const string &ampName="") const
map< string, double > ampParMap() const
Definition: FitResults.cc:472
vector< string > ampList() const
Definition: FitResults.cc:574
double centralValue() const
void saveResults()
Definition: FitResults.cc:610
vector< ReactionInfo * > reactionList(const string &reactionName="") const
vector< string > parameterList() const
string imagProdParName(const string &amplitude) const
Definition: FitResults.cc:398