AmpTools
AmplitudeManager.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 <sstream>
39 #include <fstream>
40 
41 #include <string.h>
42 
45 
46 #ifdef VTRACE
47 #include "vt_user.h"
48 #endif
49 
50 AmplitudeManager::AmplitudeManager( const vector< string >& reaction,
51  const string& reactionName) :
52 IntensityManager( reaction, reactionName ),
53 m_optimizeParIteration( false )
54 {
55  cout << endl << "## AMPLITUDE MANAGER INITIALIZATION ##" << endl;
56  cout << " Creating amplitude manager for reaction: " << reactionName << endl;
57 
58  // a list of index switches needed to generate the symmetrized amplitude
59  // group the switches by particle type
60  // dump out some information
61  map< string, vector< pair< int, int > > > swapsByType;
62  for( unsigned int i = 0; i < reaction.size(); ++i ){
63 
64  cout << "\t particle index assignment: " << reaction[i] << " -->> " << i << endl;
65 
66  for( unsigned int j = i + 1; j < reaction.size(); ++j ){
67 
68  if( reaction[i] == reaction[j] ){
69 
70  swapsByType[reaction[i]].push_back( pair< int, int >( i, j ) );
71  }
72  }
73  }
74 
75  // determine how many combinations exist by taking the the product of the
76  // number of swaps for each unique final state particle
77  int numberOfCombos = 1;
78  for( map< string, vector< pair< int, int > > >::iterator partItr = swapsByType.begin();
79  partItr != swapsByType.end(); ++partItr ){
80 
81  // don't forget the option of leaving the particles unchanged
82  int partCombos = partItr->second.size() + 1;
83 
84  cout << "There are " << partCombos
85  << " ways of rearranging particles of type: "
86  << partItr->first << endl;
87 
88  numberOfCombos *= partCombos;
89  }
90 
91  // setup the vector of symmetric combinations -- first initialize
92  // it with numberOfCombos copies of the default ordering
93  // then go in and make the swaps
94  vector< int > defaultOrder( reaction.size() );
95  for( unsigned int i = 0; i < reaction.size(); ++i ){
96 
97  defaultOrder[i] = i;
98  }
99 
100  // strip away the particle names to build a vector of vector of swaps
101  // analagous to the map from particle -> vector of swaps
102  vector< vector< pair< int, int > > > swaps;
103  for( map< string, vector< pair< int, int > > >::iterator itr = swapsByType.begin();
104  itr != swapsByType.end(); ++itr ){
105 
106  swaps.push_back( itr->second );
107 
108  // for each type of particle, add a swap that leaves particles
109  // as they are in the default ordering
110  // (this switches particle 0 with 0 which leaves order unchanged
111  // for any particle in consideration)
112  swaps.back().push_back( pair< int, int >( 0, 0 ) );
113  }
114 
115  // now use a recursive algorithm to step through the list of swaps for
116  // each unique final state particle and add to the vector of symmetric
117  // combinations
118  generateSymmetricCombos( vector< pair< int, int > >( 0 ),
119  swaps, defaultOrder );
120 
121  if( m_symmCombos.size() > 1 ){
122 
123  cout << "The following " << numberOfCombos << " orderings of the particles are" << endl
124  << "indistinguishable and will be permuted when computing amplitudes." << endl;
125 
126  for( unsigned int i = 0; i < m_symmCombos.size(); ++i ){
127 
128  for( unsigned int j = 0; j < reaction.size(); ++j ){
129 
130  cout << "\t" << m_symmCombos[i][j];
131  }
132  cout << endl;
133  }
134  }
135 }
136 
138 
139  for( map< string, Amplitude* >::iterator mapItr = m_registeredFactors.begin();
140  mapItr != m_registeredFactors.end(); ++mapItr ){
141 
142  delete mapItr->second;
143  }
144 
145  for( map< string, vector< const Amplitude* > >::iterator mapItr = m_mapNameToAmps.begin();
146  mapItr != m_mapNameToAmps.end(); ++mapItr ){
147 
148  for( vector< const Amplitude* >::iterator vecItr = mapItr->second.begin();
149  vecItr != mapItr->second.end(); ++vecItr ){
150 
151  delete *vecItr;
152  }
153  }
154 
155 }
156 
157 unsigned int
159 
160  vector< string > ampNames = getTermNames();
161 
162  unsigned int nAmpFactorsAndPerms = 0;
163 
164  for( int i = 0; i < getTermNames().size(); i++ ) {
165 
166  unsigned int iNPermutations = getPermutations( ampNames[i] ).size();
167  unsigned int iNFactors = getFactors( ampNames[i] ).size();
168 
169  assert( iNPermutations*iNFactors );
170 
171  if( ( iNPermutations * iNFactors ) > nAmpFactorsAndPerms )
172  nAmpFactorsAndPerms = iNPermutations * iNFactors;
173  }
174 
175  // for each factor and permutation we need to store
176  // a complex number, which is two numbers
177 
178  return 2 * nAmpFactorsAndPerms;
179 }
180 
181 unsigned int
183 
184  // for each amplitude we need to store a complex
185  // number -- that is two numbers
186 
187  return 2 * getTermNames().size();
188 }
189 
190 
191 bool
193 
194  for( vector< bool >::const_iterator isFixed = m_vbIsAmpFixed.begin();
195  isFixed != m_vbIsAmpFixed.end();
196  ++isFixed ){
197 
198  if( !(*isFixed) ) return true;
199  }
200 
201  return false;
202 }
203 
204 bool
206 {
207 
208 #ifdef VTRACE
209  VT_TRACER( "AmplitudeManager::calcTerms" );
210 #endif
211 
212  bool modifiedTerm = false;
213 
214  const vector< string >& ampNames = getTermNames();
215 
216  int iNAmps = ampNames.size();
217 
218  assert( iNAmps && a.m_iNEvents && a.m_iNTrueEvents );
219 #ifndef GPU_ACCELERATION
220  assert( a.m_pdAmps && a.m_pdAmpFactors);
221 #endif
222 
223  int iAmpIndex;
224  for( iAmpIndex = 0; iAmpIndex < iNAmps; iAmpIndex++ )
225  {
226 
227  map< string, vector< vector< int > > >::const_iterator permItr =
228  m_ampPermutations.find( ampNames[iAmpIndex] );
229  assert( permItr != m_ampPermutations.end() );
230  const vector< vector< int > >& vvPermuations = permItr->second;
231  int iNPermutations = vvPermuations.size();
232 
233  vector< const Amplitude* > vAmps =
234  m_mapNameToAmps.find(ampNames.at(iAmpIndex))->second;
235 
236  int iFactor, iNFactors = vAmps.size();
237 
238  // if it is not the first pass through and this particular
239  // amplitude is fixed, then we can skip to the next amplitude
240  // and avoid all of the symmetrization computation as well
241  // as checking each individual factor for free parameters.
242  if( a.m_termsValid && m_vbIsAmpFixed[iAmpIndex] ) continue;
243 
244  // now figure out if we need to recalculate a factors for an amplitude
245  // in the case we have optimization turned on, we may not have changed
246  // a parameter in the last iteration that is related to a factor in
247  // this amplitude
248 
249  bool recalculateFactors = false;
250 
251  const Amplitude* pCurrAmp = 0;
252  for( iFactor=0; iFactor < iNFactors; iFactor++ ){
253 
254  pCurrAmp = vAmps.at( iFactor );
255 
256  // now check to see if the value of this amplitudes parameters
257  // are the same as they were the last time they were evaluated
258  // for this particular dataset -- if not, recalculate
259 
260  if( !( a.m_termsValid && m_optimizeParIteration &&
261  m_dataAmpIteration[&a][pCurrAmp] == m_ampIteration[pCurrAmp] ) ){
262 
263  recalculateFactors = true;
264  m_dataAmpIteration[&a][pCurrAmp] = m_ampIteration[pCurrAmp];
265  }
266  }
267 
268  if( !recalculateFactors ) continue;
269 
270  // if we get to here, we are changing the stored factors of the
271  // amplitude
272 
273  modifiedTerm = true;
274 
275  // calculate all the factors that make up an amplitude for
276  // for all events serially on CPU or in parallel on GPU
277  int iLocalOffset = 0;
278  for( iFactor=0; iFactor < iNFactors;
279  iFactor++, iLocalOffset += 2 * a.m_iNEvents * iNPermutations ){
280 
281  pCurrAmp = vAmps.at( iFactor );
282 
283 #ifndef GPU_ACCELERATION
284  pCurrAmp->
285  calcAmplitudeAll( a.m_pdData,
286  a.m_pdAmpFactors + iLocalOffset,
287  a.m_iNEvents, &vvPermuations );
288 #else
289  a.m_gpuMan.calcAmplitudeAll( pCurrAmp, iLocalOffset,
290  &vvPermuations );
291 #endif//GPU_ACCELERATION
292  }
293 
294 
295  // now assemble all the factors in an amplitude into a single
296  // symmetrized amplitude for each event
297 
298 #ifndef GPU_ACCELERATION
299 
300  GDouble dSymmFactor = 1.0f/sqrt( iNPermutations );
301  GDouble dAmpFacRe, dAmpFacIm, dTRe, dTIm;
302  int iEvent, iPerm;
303  unsigned long long iOffsetA, iOffsetP, iOffsetF;
304 
305  // re-ordering of data will be useful to not fall out of (CPU) memory cache!!!
306 
307  // zeroing out the entire range
308  memset( (void*)( a.m_pdAmps + 2 * a.m_iNEvents * iAmpIndex ), 0,
309  2 * a.m_iNEvents * sizeof(GDouble) );
310 
311  // only sum over the true events from data and skip paddings
312  for( iEvent=0; iEvent < a.m_iNTrueEvents; iEvent++ )
313  {
314  iOffsetA = 2 * a.m_iNEvents * iAmpIndex + 2 * iEvent;
315 
316  for( iPerm = 0; iPerm < iNPermutations; iPerm++ )
317  {
318  iOffsetP = 2 * a.m_iNEvents * iPerm + 2 * iEvent;
319 
320  dAmpFacRe = a.m_pdAmpFactors[iOffsetP];
321  dAmpFacIm = a.m_pdAmpFactors[iOffsetP+1];
322 
323  for( iFactor = 1; iFactor < iNFactors; iFactor++ )
324  {
325  iOffsetF = iOffsetP + 2 * a.m_iNEvents * iNPermutations * iFactor;
326 
327  dTRe = dAmpFacRe;
328  dTIm = dAmpFacIm;
329 
330  dAmpFacRe = dTRe * a.m_pdAmpFactors[iOffsetF] -
331  dTIm * a.m_pdAmpFactors[iOffsetF+1];
332  dAmpFacIm = dTRe * a.m_pdAmpFactors[iOffsetF+1] +
333  dTIm * a.m_pdAmpFactors[iOffsetF];
334  }
335 
336  a.m_pdAmps[iOffsetA] += dAmpFacRe;
337  a.m_pdAmps[iOffsetA+1] += dAmpFacIm;
338  }
339 
340  a.m_pdAmps[iOffsetA] *= dSymmFactor;
341  a.m_pdAmps[iOffsetA+1] *= dSymmFactor;
342  }
343 
344 #else
345  // on the GPU the terms are assembled and never copied out
346  // of GPU memory
347 
348  a.m_gpuMan.assembleTerms( iAmpIndex, iNFactors, iNPermutations );
349 #endif
350 
351  }
352 
353  a.m_termsValid = true;
354 
355  return modifiedTerm;
356 }
357 
358 double
360 {
361 
362 #ifdef VTRACE
363  VT_TRACER( "AmplitudeManager::calcIntensities" );
364 #endif
365 
366  // check to be sure destination memory has been allocated
367  assert( a.m_pdIntensity );
368 
369  double maxInten = 0;
370 
371  // first update the amplitudes
372  calcTerms( a );
373 
374  // In GPU running mode amplitudes are maintained on the GPU and
375  // the sum of the logs of intensities are calculated directly.
376  // This is a CPU calculation that was likely called from the
377  // parent IntensityManager with a single Kinematics object or
378  // perhaps during MC generation. Copy the amplitudes out of the
379  // GPU and compute the intensities (on the CPU). There is no
380  // GPU accelerated intensity calculation, just a GPU accelerated
381  // log( intensity ) calculation.
382 
383 #ifdef GPU_ACCELERATION
384  a.allocateCPUAmpStorage( *this );
385  a.m_gpuMan.copyAmpsFromGPU( a );
386 #endif
387 
388  const vector< string >& ampNames = getTermNames();
389 
390  int iNAmps = ampNames.size();
391 
392  //Now pre-calculate ViVj* and include factor of 2 for off-diagonal elements
393  double* pdViVjRe = new double[iNAmps*(iNAmps+1)/2];
394  double* pdViVjIm = new double[iNAmps*(iNAmps+1)/2];
395 
396  int i,j;
397  complex< double > cTmp;
398  for( i = 0; i < iNAmps; i++ ){
399  for( j = 0; j <= i; j++ ){
400 
401  cTmp = productionFactor( i ) * conj( productionFactor( j ) );
402 
403  if( termsAreRenormalized() ){
404 
405  cTmp /= sqrt( normInt()->ampInt( ampNames[i], ampNames[i] ) *
406  normInt()->ampInt( ampNames[j], ampNames[j] ) );
407  }
408 
409  pdViVjRe[i*(i+1)/2+j] = cTmp.real();
410  pdViVjIm[i*(i+1)/2+j] = cTmp.imag();
411 
412  if( i != j ) {
413 
414  pdViVjRe[i*(i+1)/2+j] *= 2;
415  pdViVjIm[i*(i+1)/2+j] *= 2;
416  }
417  }
418  }
419 
420  double dIntensity;
421  double cAiAjRe,cAiAjIm;
422 
423  //Re-ordering of data will be useful to not fall out of (CPU) memory cache!!!
424  //Only sum over the true events from data and skip paddings
425  int iEvent;
426  for( iEvent=0; iEvent < a.m_iNTrueEvents; iEvent++ )
427  {
428  dIntensity = 0;
429  for( i = 0; i < iNAmps; i++ ){
430  for( j = 0; j <= i; j++ ){
431 
432  // remove cross terms from incoherent amplitudes
433  if( !m_sumCoherently[i][j] ) continue;
434 
435  //AiAj*
436  cAiAjRe = a.m_pdAmps[2*a.m_iNEvents*i+2*iEvent] *
437  a.m_pdAmps[2*a.m_iNEvents*j+2*iEvent] +
438  a.m_pdAmps[2*a.m_iNEvents*i+2*iEvent+1] *
439  a.m_pdAmps[2*a.m_iNEvents*j+2*iEvent+1];
440 
441  cAiAjIm= -a.m_pdAmps[2*a.m_iNEvents*i+2*iEvent] *
442  a.m_pdAmps[2*a.m_iNEvents*j+2*iEvent+1] +
443  a.m_pdAmps[2*a.m_iNEvents*i+2*iEvent+1] *
444  a.m_pdAmps[2*a.m_iNEvents*j+2*iEvent];
445 
446  dIntensity += pdViVjRe[i*(i+1)/2+j] * cAiAjRe -
447  pdViVjIm[i*(i+1)/2+j] * cAiAjIm;
448  }
449  }
450 
451  dIntensity *= a.m_pdWeights[iEvent];
452 
453  a.m_pdIntensity[iEvent] = dIntensity;
454  if( dIntensity > maxInten ) maxInten = dIntensity;
455  }
456 
457  delete[] pdViVjRe;
458  delete[] pdViVjIm;
459 
460  return maxInten;
461 }
462 
463 
464 double
466 {
467 
468 #ifdef VTRACE
469  VT_TRACER( "AmplitudeManager::calcSumLogIntensity" );
470 #endif
471 
472  // this may be inefficienct since there are two
473  // loops over events, one here and one in the
474  // calculation of intensities -- however, this
475  // streamlines the code a little
476  // this may be a place for optimization later
477 
478  double dSumLogI = 0;
479 
480 #ifndef GPU_ACCELERATION
481 
482  calcIntensities( a );
483 
484  for( int iEvent=0; iEvent < a.m_iNTrueEvents; iEvent++ ){
485 
486  // here divide out the weight that was put into the intensity calculation
487  // and weight the log -- in practice this just contributes an extra constant
488  // term in the likelihood equal to sum -w_i * log( w_i ), but the division
489  // helps avoid problems with negative weights, which may be used
490  // in background subtraction
491  dSumLogI += a.m_pdWeights[iEvent] *
492  G_LOG( a.m_pdIntensity[iEvent] / a.m_pdWeights[iEvent] );
493  }
494 
495 #else
496 
497  // need to compute the production coefficients with all scale factors
498  // taken into account
499 
500  vector< string > ampNames = getTermNames();
501 
502  vector< complex< double > > gpuProdPars( ampNames.size() );
503 
504  for( int i = 0; i < ampNames.size(); ++i ){
505 
506  gpuProdPars[i] = productionFactor( ampNames[i] );
507 
508  if( termsAreRenormalized() ){
509 
510  gpuProdPars[i] /= sqrt( normInt()->ampInt( ampNames[i], ampNames[i] ) );
511  }
512  }
513 
514  // need to explicitly do amplitude calculation
515  // since intensity and sum is done directly on GPU
516 
517  if( !a.m_termsValid || hasTermWithFreeParam() ){
518 
519  calcTerms( a );
520  }
521 
522  dSumLogI = a.m_gpuMan.calcSumLogIntensity( gpuProdPars, m_sumCoherently );
523 
524 #endif
525 
526  return( dSumLogI );
527 }
528 
529 
530 void
531 AmplitudeManager::calcIntegrals( AmpVecs& a, int iNGenEvents ) const
532 {
533 
534 #ifdef VTRACE
535  VT_TRACER( "AmplitudeManager::calcIntegrals" );
536 #endif
537 
538  GDouble* integralMatrix = a.m_pdIntegralMatrix;
539 
540  // this method could be made more efficient by caching a table of
541  // integrals associated with each AmpVecs object and then, based on the
542  // variables bIsFirstPass and m_vbIsAmpFixed data compute only
543  // those terms that could have changed
544 
545  // amp -> amp* -> value
546  assert( iNGenEvents );
547  bool termChanged = calcTerms( a );
548 
549  // if nothing changed and it isn't the first pass, return
550  if( !termChanged && a.m_integralValid ) return;
551 
552  int iNAmps = a.m_iNTerms;
553 
554  int i, j, iEvent;
555  for( i = 0; i < iNAmps;i++ ) {
556  for( j = 0; j <= i; j++ ) {
557 
558  // if the amplitude isn't floating and it isn't the first pass
559  // through these data, then its integral can't change
560  if( a.m_integralValid && m_vbIsAmpFixed[i] && m_vbIsAmpFixed[j] ){
561 
562  // if the amplitude isn't floating and it isn't the first pass
563  // through these data, then its integral can't change
564 
565  continue;
566  }
567  else{
568 
569  // otherwise zero it out and recalculate it
570 
571  integralMatrix[2*i*iNAmps+2*j] = 0;
572  integralMatrix[2*i*iNAmps+2*j+1] = 0;
573  }
574 
575  // if two amps don't interfere the relevant integral is zero
576  if( m_sumCoherently[i][j] ){
577 
578 #ifndef GPU_ACCELERATION
579 
580  for( iEvent = 0; iEvent < a.m_iNTrueEvents; iEvent++ )
581  {
582  //AiAj*
583  integralMatrix[2*i*iNAmps+2*j] += a.m_pdWeights[iEvent] *
584  ( a.m_pdAmps[2*a.m_iNEvents*i+2*iEvent] *
585  a.m_pdAmps[2*a.m_iNEvents*j+2*iEvent] +
586  a.m_pdAmps[2*a.m_iNEvents*i+2*iEvent+1] *
587  a.m_pdAmps[2*a.m_iNEvents*j+2*iEvent+1] );
588 
589  integralMatrix[2*i*iNAmps+2*j+1] += a.m_pdWeights[iEvent] *
590  ( -a.m_pdAmps[2*a.m_iNEvents*i+2*iEvent] *
591  a.m_pdAmps[2*a.m_iNEvents*j+2*iEvent+1] +
592  a.m_pdAmps[2*a.m_iNEvents*i+2*iEvent+1] *
593  a.m_pdAmps[2*a.m_iNEvents*j+2*iEvent] );
594  }
595  // normalize
596  integralMatrix[2*i*iNAmps+2*j] /= static_cast< GDouble >( iNGenEvents );
597  integralMatrix[2*i*iNAmps+2*j+1] /= static_cast< GDouble >( iNGenEvents );
598 
599 #else
600  a.m_gpuMan.calcIntegral( &(integralMatrix[2*i*iNAmps+2*j]), i, j, iNGenEvents );
601 #endif
602  }
603 
604  // complex conjugate
605  if( i != j ) {
606 
607  integralMatrix[2*j*iNAmps+2*i] = integralMatrix[2*i*iNAmps+2*j];
608  integralMatrix[2*j*iNAmps+2*i+1] = -integralMatrix[2*i*iNAmps+2*j+1];
609  }
610  }
611  }
612 
613  a.m_integralValid = true;
614 }
615 
616 const vector< vector< int > >&
617 AmplitudeManager::getPermutations( const string& name ) const {
618 
619  map< string, vector< vector< int > > >::const_iterator mapItr =
620  m_ampPermutations.find( name );
621 
622  // check to be sure the amplitude is there:
623  assert( mapItr != m_ampPermutations.end() );
624 
625  return( mapItr->second );
626 }
627 
628 const vector< const Amplitude* >&
629 AmplitudeManager::getFactors( const string& name ) const {
630 
631  map< string, vector< const Amplitude* > >::const_iterator mapItr =
632  m_mapNameToAmps.find( name );
633 
634  // check to be sure the amplitude is there:
635  assert( mapItr != m_mapNameToAmps.end() );
636 
637  return( mapItr->second );
638 }
639 
640 void
641 AmplitudeManager::addAmpFactor( const string& name,
642  const string& factorName,
643  const vector< string >& args,
644  const string& sum,
645  const string& scale ){
646 
647  map< string, Amplitude* >::iterator defaultAmp =
648  m_registeredFactors.find( factorName );
649 
650  if( defaultAmp == m_registeredFactors.end() ){
651 
652  cout << "ERROR: amplitude factor with name " << factorName
653  << " has not been registered." << endl;
654  assert( false );
655  }
656 
657  Amplitude* newAmp = defaultAmp->second->newAmplitude( args );
658 
659  // check to see if this is a new term and do some setup if it is
660  if( !hasTerm( name ) ){
661 
662  addTerm( name, scale );
663 
664  m_ampSum.push_back( sum );
665  m_vbIsAmpFixed.push_back( true );
666 
667  m_mapNameToAmps[name] = vector< const Amplitude* >( 0 );
668 
669  // check to see if permutations have already been added for this
670  // amplitude (before the amplitude was added itself) if so, add
671  // the set of permutations that comes from permuting identical
672  // particles
673  if( m_ampPermutations.find( name ) != m_ampPermutations.end() )
674  {
675  // permutations have already been added
676  for( vector< vector< int > >::iterator vecItr = m_symmCombos.begin();
677  vecItr != m_symmCombos.end(); ++vecItr )
678  {
679  m_ampPermutations[name].push_back( *vecItr );
680  }
681  }
682  else
683  {
684  // start the set of permutations with those that include
685  // just identical particles
686  m_ampPermutations[name] = m_symmCombos;
687  }
688 
689  // adjust the matrix that determines which amplitudes add coherently
690  // by looking at this sum and other sums
691  int nAmps = m_ampSum.size();
692  vector< bool > lastRow;
693 
694  // simultaneously build the last column and last row
695  // (since matrix is symmetric)
696  for( int i = 0; i < nAmps; ++i ){
697 
698  bool coh = ( m_ampSum[i] == sum );
699 
700  if( i < nAmps - 1 ){
701 
702  m_sumCoherently[i].push_back( coh );
703  lastRow.push_back( coh );
704  }
705  }
706  // this is the lower right element on the diagonal -- always true
707  lastRow.push_back( true );
708  m_sumCoherently.push_back( lastRow );
709  }
710 
711  m_mapNameToAmps[name].push_back( newAmp );
712 
713  //Enable a short-cut if no factors are variable in the amplitude
714  m_vbIsAmpFixed[termIndex(name)] =
715  m_vbIsAmpFixed[termIndex(name)] && !newAmp->containsFreeParameters();
716 }
717 
718 void
719 AmplitudeManager::addAmpPermutation( const string& ampName, const vector< int >& permutation ){
720 
721  map< string, vector< vector< int > > >::iterator mapItr = m_ampPermutations.find( ampName );
722 
723  if( mapItr == m_ampPermutations.end() ){
724 
725  cout << "WARNING: adding permutation for nonexistent amplitude " << ampName
726  << endl;
727 
728  m_ampPermutations[ampName] = vector< vector< int > >( 0 );
729  m_ampPermutations[ampName].push_back( permutation );
730 
731  }
732  else{
733 
734  bool foundPermutation = false;
735 
736  for( vector< vector< int > >::const_iterator vecItr = mapItr->second.begin();
737  vecItr != mapItr->second.end();
738  ++vecItr ){
739 
740  if( permutation == *vecItr ) foundPermutation = true;
741  }
742 
743  if( !foundPermutation ){
744 
745  cout << "Adding a new permutation for " << ampName << ": ";
746  for( vector< int >::const_iterator itr = permutation.begin();
747  itr != permutation.end();
748  ++itr ){
749 
750  cout << *itr << " ";
751  }
752  cout << endl;
753 
754  mapItr->second.push_back( permutation );
755  }
756  else{
757 
758  cout << "The permutation ";
759  for( vector< int >::const_iterator itr = permutation.begin();
760  itr != permutation.end();
761  ++itr ){
762 
763  cout << *itr << " ";
764  }
765  cout << "already exists for " << ampName << endl;
766  }
767  }
768 }
769 
770 void
772 
773  vector< string > sumName;
774 
775  // loop over amplitudes in the ConfigurationInfo
776  vector<AmplitudeInfo*> ampInfoVector = configInfo->amplitudeList(reactionName());
777  for (unsigned int i = 0; i < ampInfoVector.size(); i++){
778 
779  string ampName = ampInfoVector[i]->fullName();
780  string sumName = ampInfoVector[i]->sumName();
781  string scale = ampInfoVector[i]->scale();
782 
783  // add amplitudes
784  vector< vector<string> > ampFactors = ampInfoVector[i]->factors();
785  for (unsigned int j = 0; j < ampFactors.size(); j++){
786  string factorName = ampFactors[j][0];
787  vector<string> ampParameters = ampFactors[j];
788  ampParameters.erase(ampParameters.begin());
789  addAmpFactor( ampName, factorName, ampParameters, sumName, scale );
790  }
791 
792  // add permutations
793  vector< vector<int> > permutations = ampInfoVector[i]->permutations();
794  for (unsigned int j = 0; j < permutations.size(); j++){
795  addAmpPermutation( ampName, permutations[j] );
796  }
797 
798  // add production amplitudes
799  setDefaultProductionFactor(ampName, ampInfoVector[i]->value());
800 
801  // if the amplitude has parameters we should go ahead and set their
802  // values, otherwise they will be set to the default value as defined
803  // by the AmpParameter class -- in a fit, the ParameterManager will
804  // later reset these pointers to point to floating parameters in MINUIT
805  vector< ParameterInfo* > pars = ampInfoVector[i]->parameters();
806  for( vector< ParameterInfo* >::iterator parItr = pars.begin();
807  parItr != pars.end();
808  ++parItr ){
809 
810  setParValue( ampName, (**parItr).parName(), (**parItr).value() );
811  }
812 
813  // finally initialize the amplitudes
814  vector< const Amplitude* > ampVec = m_mapNameToAmps[ampName];
815  for( vector< const Amplitude* >::iterator amp = ampVec.begin();
816  amp != ampVec.end();
817  ++amp ) {
818 
819  // init needs to be non-const or else the user has to deal with
820  // mutable data -- in reality we really want some aspects of the
821  // amplitude like the name, arguments, etc. to never change and
822  // other aspects to be mutable, but this seems to put an extra
823  // burden on the user
824 
825  const_cast< Amplitude* >(*amp)->init();
826  }
827  }
828 }
829 
830 void
831 AmplitudeManager::setParPtr( const string& name, const string& parName,
832  const double* ampParPtr ){
833 
834  IntensityManager::setParPtr( name, parName, ampParPtr );
835 
836  // now look for the parameter as part of the amplitude factors
837 
838  for( vector< const Amplitude* >::iterator factorItr = m_mapNameToAmps[name].begin();
839  factorItr != m_mapNameToAmps[name].end();
840  ++factorItr ){
841 
842  if( (**factorItr).setParPtr( parName, ampParPtr ) ){
843 
844  m_vbIsAmpFixed[termIndex(name)] = false;
845  }
846  }
847 }
848 
849 void
850 AmplitudeManager::setParValue( const string& name, const string& parName,
851  double val ){
852 
853  IntensityManager::setParValue( name, parName, val );
854 
855  // we will redetermine the status of this variable in the loop below
856 
857  m_vbIsAmpFixed[termIndex(name)] = true;
858 
859  // now loop through the amplitude factors looking for the parameter
860 
861  for( vector< const Amplitude* >::iterator factorItr = m_mapNameToAmps[name].begin();
862  factorItr != m_mapNameToAmps[name].end();
863  ++factorItr ){
864 
865  (**factorItr).setParValue( parName, val );
866 
867  m_vbIsAmpFixed[termIndex(name)] = m_vbIsAmpFixed[termIndex(name)] &&
868  !(**factorItr).containsFreeParameters();
869  }
870 }
871 
872 void
873 AmplitudeManager::updatePar( const string& parName ) const {
874 
875  for( map< string, vector< const Amplitude* > >::const_iterator mapItr = m_mapNameToAmps.begin();
876  mapItr != m_mapNameToAmps.end();
877  ++mapItr ){
878 
879  for( vector< const Amplitude* >::const_iterator ampItr = mapItr->second.begin();
880  ampItr != mapItr->second.end();
881  ++ampItr ){
882 
883  // if we find an amplitude with the parameter update the iteration
884  // counter; this may result in multiple increments over one fuction
885  // call but that is OK -- iteration numbers just need to be unique
886  if( (**ampItr).updatePar( parName ) ){
887 
888  ++m_ampIteration[*ampItr];
889  }
890  }
891  }
892 }
893 
894 void
896 
897  m_registeredFactors[amplitude.name()] = amplitude.clone();
898 }
899 
900 // private functions
901 
902 void
903 AmplitudeManager::generateSymmetricCombos( const vector< pair< int, int > >& prevSwaps,
904  vector< vector< pair< int, int > > > remainingSwaps,
905  const vector< int >& defaultOrder ){
906 
907  if( remainingSwaps.size() == 0 ){
908 
909  // we've reached the bottom of the list of swaps
910 
911  // make the swaps to the default ordering
912  vector< int > swappedOrder = defaultOrder;
913  for( vector< pair< int, int > >::const_iterator swapItr = prevSwaps.begin();
914  swapItr != prevSwaps.end(); ++swapItr ){
915 
916  int temp = swappedOrder[swapItr->first];
917  swappedOrder[swapItr->first] = swappedOrder[swapItr->second];
918  swappedOrder[swapItr->second] = temp;
919  }
920 
921  // and push the combination on the list
922  m_symmCombos.push_back( swappedOrder );
923  }
924  else{
925 
926  // pop off a set of remaining swaps
927  vector< pair< int, int > > currentSwaps = remainingSwaps.back();
928  remainingSwaps.pop_back();
929 
930  // loop through them pushing each swap onto the list of prevSwaps
931  for( vector< pair< int, int > >::iterator itr = currentSwaps.begin();
932  itr != currentSwaps.end(); ++itr ){
933 
934  vector< pair< int, int > > newPrevSwaps = prevSwaps;
935  newPrevSwaps.push_back( *itr );
936  generateSymmetricCombos( newPrevSwaps, remainingSwaps, defaultOrder );
937  }
938  }
939 }
940 
void setParValue(const string &termName, const string &parName, double ampParValue)
void calcAmplitudeAll(const Amplitude *amp, unsigned long long offset, const vector< vector< int > > *pvPermutations)
Definition: GPUManager.cc:263
unsigned long long m_iNEvents
Definition: AmpVecs.h:68
string reactionName() const
virtual Amplitude * clone() const =0
void calcIntegral(GDouble *result, int iAmp, int jAmp, int iNGenEvents)
Definition: GPUManager.cc:398
bool m_termsValid
Definition: AmpVecs.h:145
unsigned int termStoragePerEvent() const
GPUManager m_gpuMan
Definition: AmpVecs.h:159
bool calcTerms(AmpVecs &ampVecs) const
void allocateCPUAmpStorage(const IntensityManager &intenMan)
Definition: AmpVecs.cc:280
void registerAmplitudeFactor(const Amplitude &defaultAmplitude)
void assembleTerms(int iAmpInd, int nFact, int nPerm)
Definition: GPUManager.cc:314
virtual void setParValue(const string &termName, const string &parName, double ampParValue)
bool hasTerm(const string &termName) const
virtual Amplitude * newAmplitude(const vector< string > &args) const =0
double calcIntensities(AmpVecs &ampVecs) const
double GDouble
void copyAmpsFromGPU(AmpVecs &a)
Definition: GPUManager.cc:242
int termIndex(const string &termName) const
virtual void setParPtr(const string &termName, const string &parName, const double *ampParPtr)
bool m_integralValid
Definition: AmpVecs.h:153
GDouble * m_pdAmps
Definition: AmpVecs.h:117
const NormIntInterface * normInt() const
const vector< string > & getTermNames() const
const vector< const Amplitude *> & getFactors(const string &name) const
virtual string name() const =0
unsigned long long m_iNTrueEvents
Definition: AmpVecs.h:75
double sqrt(double)
#define G_LOG(a)
bool termsAreRenormalized() const
double calcSumLogIntensity(const vector< complex< double > > &prodCoef, const vector< vector< bool > > &cohMtx)
Definition: GPUManager.cc:331
void calcIntegrals(AmpVecs &ampVecs, int iNGenEvents) const
void updatePar(const string &parName) const
GDouble * m_pdWeights
Definition: AmpVecs.h:111
void setDefaultProductionFactor(const string &termName, complex< double > prodAmp)
void addAmpFactor(const string &ampName, const string &factorName, const vector< string > &args, const string &sum="", const string &scale="1.0")
bool hasTermWithFreeParam() const
int addTerm(const string &termName, const string &scale="1.0")
virtual void init()
Definition: Amplitude.h:167
void setupFromConfigurationInfo(const ConfigurationInfo *configInfo)
void setParPtr(const string &termName, const string &parName, const double *ampParPtr)
void addAmpPermutation(const string &ampName, const vector< int > &permutation)
GDouble * m_pdIntensity
Definition: AmpVecs.h:137
const vector< vector< int > > & getPermutations(const string &name) const
complex< double > productionFactor(const string &termName) const
vector< AmplitudeInfo * > amplitudeList(const string &reactionName="", const string &sumName="", const string &ampName="") const
double calcSumLogIntensity(AmpVecs &ampVecs) const
GDouble * m_pdData
Definition: AmpVecs.h:106
bool containsFreeParameters() const
Definition: Amplitude.cc:183
unsigned int maxFactorStoragePerEvent() const
GDouble * m_pdAmpFactors
Definition: AmpVecs.h:124
GDouble * m_pdIntegralMatrix
Definition: AmpVecs.h:132
AmplitudeManager(const vector< string > &finalState, const string &reactionName="")
unsigned int m_iNTerms
Definition: AmpVecs.h:94