ROOTPWA
isobarAmplitude.cc
Go to the documentation of this file.
1 
2 //
3 // Copyright 2010
4 //
5 // This file is part of rootpwa
6 //
7 // rootpwa is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // rootpwa is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with rootpwa. If not, see <http://www.gnu.org/licenses/>.
19 //
21 //-------------------------------------------------------------------------
22 // File and Version Information:
23 // $Rev:: $: revision of last commit
24 // $Author:: $: author of last commit
25 // $Date:: $: date of last commit
26 //
27 // Description:
28 // virtual base class for isobar decay amplitude independent of formalism
29 //
30 //
31 // Author List:
32 // Boris Grube TUM (original author)
33 //
34 //
35 //-------------------------------------------------------------------------
36 
37 
38 #include <algorithm>
39 #include <cassert>
40 
41 #include "TLorentzRotation.h"
42 #include "TMath.h"
43 
44 #include "conversionUtils.hpp"
45 #include "factorial.hpp"
46 #include "isobarAmplitude.h"
47 
48 
49 using namespace std;
50 using namespace boost;
51 using namespace rpwa;
52 
53 
54 bool isobarAmplitude::_debug = false;
55 
56 
57 isobarAmplitude::isobarAmplitude()
58  : _decay (),
59  _useReflectivityBasis(true),
60  _boseSymmetrize (true),
61  _isospinSymmetrize (true),
62  _doSpaceInversion (false),
63  _doReflection (false)
64 { }
65 
66 
68  : _useReflectivityBasis(true),
69  _boseSymmetrize (true),
70  _isospinSymmetrize (true),
71  _doSpaceInversion (false),
72  _doReflection (false)
73 {
74  setDecayTopology(decay);
75 }
76 
77 
79 { }
80 
81 
82 void
84 {
85  if (not decay) {
86  printErr << "null pointer to decay topology. aborting." << endl;
87  throw;
88  }
89  if (not decay->checkTopology()) {
90  printErr << "decay does not have the correct topology. aborting." << endl;
91  throw;
92  }
93  if (not decay->checkConsistency()) {
94  printErr << "decay is not consistent. aborting." << endl;
95  throw;
96  }
97  _decay = decay;
98 }
99 
100 
101 void
103 {
104  _symTermMaps.clear();
105  // create first symmetrization entry with identity permutation map
106  vector<unsigned int> identityPermMap;
107  for (unsigned int i = 0; i < _decay->nmbFsParticles() ; ++i)
108  identityPermMap.push_back(i);
109  _symTermMaps.push_back(symTermMap(1, identityPermMap));
110  // create final-state symmetriztion terms
111  if(not initSymTermMaps()) {
112  printErr << "Could not initialize amplitude symetrization maps." << endl;
113  throw;
114  }
115 }
116 
117 
118 // at the moment it is not possible to fix the helicity state of
119 // final state particles for cases where the amplitudes for the
120 // different helicity states have to be added incoherently
121 complex<double>
123 {
124  const unsigned int nmbSymTerms = _symTermMaps.size();
125  if (nmbSymTerms < 1) {
126  printErr << "array of symmetrization terms is empty. make sure isobarAmplitude::init() "
127  << "was called. cannot calculate amplitude. returning 0." << endl;
128  return 0;
129  }
130  // loop over all symmetrization terms; assumes that init() was called before
131  complex<double> amp = 0;
132  for (unsigned int i = 0; i < nmbSymTerms; ++i)
133  amp += _symTermMaps[i].factor * symTermAmp(_symTermMaps[i].fsPartPermMap);
134  return amp;
135 }
136 
137 
138 TLorentzRotation
139 isobarAmplitude::gjTransform(const TLorentzVector& beamLv, // beam Lorentz-vector
140  const TLorentzVector& XLv) // X Lorentz-vector
141 {
142  TLorentzVector beam = beamLv;
143  TLorentzVector X = XLv;
144  const TVector3 yGjAxis = beam.Vect().Cross(X.Vect()); // y-axis of Gottfried-Jackson frame
145  // rotate so that yGjAxis becomes parallel to y-axis and beam momentum ends up in (x, z)-plane
146  TRotation rot1;
147  rot1.RotateZ(piHalf - yGjAxis.Phi());
148  rot1.RotateX(yGjAxis.Theta() - piHalf);
149  beam *= rot1;
150  X *= rot1;
151  // boost to X RF
152  TLorentzRotation boost;
153  boost.Boost(-X.BoostVector());
154  beam *= boost;
155  // rotate about yGjAxis so that beam momentum is along z-axis
156  TRotation rot2;
157  rot2.RotateY(-signum(beam.X()) * beam.Theta());
158  // construct total transformation
159  TLorentzRotation gjTransform(rot1);
160  gjTransform.Transform(boost);
161  gjTransform.Transform(rot2);
162  return gjTransform;
163 }
164 
165 
166 void
168 {
169  if (_debug)
170  printDebug << "space inverting final state momenta." << endl;
171  // transform final state particles into X rest frame
172  const TLorentzVector& beamLv = _decay->productionVertex()->referenceLzVec();
173  const TLorentzVector& XLv = _decay->XParticle()->lzVec();
174  const TLorentzRotation gjTrans = gjTransform(beamLv, XLv);
175  _decay->transformFsParticles(gjTrans);
176  // perform parity transformation on final state particles in X rest frame
177  for (unsigned int i = 0; i < _decay->nmbFsParticles(); ++i) {
178  const particlePtr& part = _decay->fsParticles()[i];
179  const TLorentzVector& fsPartLv = part->lzVec();
180  part->setLzVec(TLorentzVector(-fsPartLv.Vect(), fsPartLv.E()));
181  }
182  // transform final state particles back to lab frame
183  _decay->transformFsParticles(gjTrans.Inverse());
184 }
185 
186 
187 void
189 {
190  if (_debug)
191  printDebug << "reflecting final state momenta through production plane." << endl;
192  // transform final state particles into X rest frame
193  const TLorentzVector& beamLv = _decay->productionVertex()->referenceLzVec();
194  const TLorentzVector& XLv = _decay->XParticle()->lzVec();
195  const TLorentzRotation gjTrans = gjTransform(beamLv, XLv);
196  _decay->transformFsParticles(gjTrans);
197  // reflect final state particles through production plane
198  for (unsigned int i = 0; i < _decay->nmbFsParticles(); ++i) {
199  const particlePtr& part = _decay->fsParticles()[i];
200  const TLorentzVector& fsPartLv = part->lzVec();
201  part->setLzVec(TLorentzVector(fsPartLv.X(), -fsPartLv.Y(), fsPartLv.Z(), fsPartLv.E()));
202  }
203  // transform final state particles back to lab frame
204  _decay->transformFsParticles(gjTrans.Inverse());
205 }
206 
207 
208 // assumes that all particles in the decay are mesons
209 // !!! in this primitive recursion scheme daughter amplitudes might be
210 // called multiple times; for amplitudes with high-spin isobars a
211 // large speed gain might be achievable by precalculating the
212 // amplitudes at each vertex for all possible helicity values;
213 // additional speed can be gained by checking that daughter
214 // amplitudes are not zero before calculating the remaining parts
215 // of the amplitude
216 complex<double>
218  const bool topVertex) const // switches special treatment of X decay vertex; needed for reflectivity basis
219 {
220  const particlePtr& parent = vertex->parent();
221  const particlePtr& daughter1 = vertex->daughter1();
222  const particlePtr& daughter2 = vertex->daughter2();
223  complex<double> ampSum = 0;
224  for (int lambda1 = -daughter1->J(); lambda1 <= +daughter1->J(); lambda1 += 2) {
225  // calculate decay amplitude for daughter 1
226  daughter1->setSpinProj(lambda1);
227  const isobarDecayVertexPtr& daughter1Vertex =
228  dynamic_pointer_cast<isobarDecayVertex>(_decay->toVertex(daughter1));
229  complex<double> daughter1Amp = 0;
230  if (daughter1Vertex) {
231  daughter1Amp = twoBodyDecayAmplitudeSum(daughter1Vertex, false);
232  } else
233  daughter1Amp = 1;
234  for (int lambda2 = -daughter2->J(); lambda2 <= +daughter2->J(); lambda2 += 2) {
235  // calculate decay amplitude for daughter 2
236  daughter2->setSpinProj(lambda2);
237  const isobarDecayVertexPtr& daughter2Vertex =
238  dynamic_pointer_cast<isobarDecayVertex>(_decay->toVertex(daughter2));
239  complex<double> daughter2Amp = 0;
240  if (daughter2Vertex) {
241  daughter2Amp = twoBodyDecayAmplitudeSum(daughter2Vertex, false);
242  } else
243  daughter2Amp = 1;
244  complex<double> parentAmp = twoBodyDecayAmplitude(vertex, topVertex);
245  complex<double> amp = parentAmp * daughter1Amp * daughter2Amp;
246  if (_debug)
247  printDebug << "amplitude term for : "
248  << parent->name() << " [lambda = " << spinQn(parent->spinProj()) << "] -> "
249  << daughter1->name() << " [lambda = " << spinQn(lambda1 ) << "] + "
250  << daughter2->name() << " [lambda = " << spinQn(lambda2 ) << "] = "
251  << "parent amp. = " << maxPrecisionDouble(parentAmp)
252  << " * daughter_1 amp = " << maxPrecisionDouble(daughter1Amp)
253  << " * daughter_2 amp = " << maxPrecisionDouble(daughter2Amp) << " = "
254  << maxPrecisionDouble(amp) << endl;
255  ampSum += amp;
256  }
257  }
258  if (_debug)
259  printDebug << "decay amplitude for " << *vertex << " = " << maxPrecisionDouble(ampSum) << endl;
260  return ampSum;
261 }
262 
263 
264 complex<double>
265 isobarAmplitude::symTermAmp(const vector<unsigned int>& fsPartPermMap) const
266 {
267  // (re)set final state momenta
268  if (not _decay->revertMomenta(fsPartPermMap)) {
269  printErr << "problems reverting momenta in decay topology. cannot calculate amplitude. "
270  << "returning 0." << endl;
271  return 0;
272  }
273  // transform daughters into their respective RFs
275  // calculate amplitude
276  return twoBodyDecayAmplitudeSum(_decay->XIsobarDecayVertex(), true);
277 }
278 
279 
280 bool
282 {
283 
284  vector<symTermMap> isoSymTermMaps;
285  vector<symTermMap> boseSymTermMaps;
286  unsigned int nmbIsoSymTerms = 0;
287  unsigned int nmbBoseSymTerms = 0;
288  if(_isospinSymmetrize) {
289  // get isospin permutation maps
290  isoSymTermMaps = _decay->getIsospinSymmetrization();
291  nmbIsoSymTerms = isoSymTermMaps.size();
292  if (nmbIsoSymTerms < 1) {
293  printErr << "array of isospin-symmetrization terms is empty. "
294  << "cannot isospin-symmetrize amplitude." << endl;
295  return false;
296  }
297  if (nmbIsoSymTerms == 1) {
298  printInfo << "no isospin symmetrization needed for this amplitude." << endl;
299  isoSymTermMaps[0].factor = 1;
300  } else {
301  // check isospin permutation maps
302  bool isoPermMapsOkay = true;
303  for (unsigned int i = 0; i < nmbIsoSymTerms; ++i)
304  if (isoSymTermMaps[i].fsPartPermMap.size() != _decay->nmbFsParticles()) {
305  printErr << "final-state permutation map for isospin symmetrization has wrong size = "
306  << isoSymTermMaps[i].fsPartPermMap.size() << " expected "
307  << _decay->nmbFsParticles() << " . cannot isospin-symmetrize amplitude." << endl;
308  isoPermMapsOkay = false;
309  }
310  if (not isoPermMapsOkay)
311  return false;
312  printInfo << "Found " << nmbIsoSymTerms << " isospin symmetrization terms." << endl;
313  }
314  }
315  if(_boseSymmetrize) {
316  boseSymTermMaps = _decay->getBoseSymmetrization();
317  nmbBoseSymTerms = boseSymTermMaps.size();
318  if (nmbBoseSymTerms < 1) {
319  printErr << "array of Bose-symmetrization terms is empty. "
320  << "cannot Bose-symmetrize amplitude." << endl;
321  return false;
322  }
323  if (nmbBoseSymTerms == 1) {
324  printInfo << "no Bose symmetrization needed for this amplitude." << endl;
325  } else {
326  printInfo << "Found " << nmbBoseSymTerms << " Bose symmetrization terms." << endl;
327  }
328  }
329  if(nmbIsoSymTerms + nmbBoseSymTerms > 0) {
330  _symTermMaps.clear();
331  }
332  for(unsigned int iso_i = 0; iso_i < nmbIsoSymTerms; ++iso_i) {
333  complex<double> isoFactor = isoSymTermMaps[iso_i].factor;
334  vector<unsigned int> isoSymTermMap = isoSymTermMaps[iso_i].fsPartPermMap;
335  for(unsigned int bose_i = 0; bose_i < nmbBoseSymTerms; ++bose_i) {
336  complex<double> boseFactor = boseSymTermMaps[bose_i].factor;
337  vector<unsigned int> boseSymTermMap = boseSymTermMaps[bose_i].fsPartPermMap;
338  vector<unsigned int> newSymTermMap(isoSymTermMap.size(), 0);
339  assert(isoSymTermMap.size() == boseSymTermMap.size());
340  for(unsigned int i = 0; i < boseSymTermMap.size(); ++i) {
341  newSymTermMap[i] = boseSymTermMap[isoSymTermMap[i]];
342  }
343  complex<double> newFactor = isoFactor * boseFactor;
344  _symTermMaps.push_back(symTermMap(newFactor, newSymTermMap));
345  }
346  }
347 
348  if(_debug) {
349  printDebug << "Found the folloing symmetrization parametrization:" << endl;
350  cout << "isospin terms: " << endl;
351  for(unsigned int i = 0; i < nmbIsoSymTerms; ++i) {
352  vector<unsigned int> map = isoSymTermMaps[i].fsPartPermMap;
353  cout << isoSymTermMaps[i].factor << ": [" << map[0];
354  for(unsigned int j = 1; j < map.size(); ++j) {
355  cout << ", " << map[j];
356  }
357  cout << "]" << endl;
358  }
359  cout << "Bose terms: " << endl;
360  for(unsigned int i = 0; i < nmbBoseSymTerms; ++i) {
361  vector<unsigned int> map = boseSymTermMaps[i].fsPartPermMap;
362  cout << boseSymTermMaps[i].factor << ": [" << map[0];
363  for(unsigned int j = 1; j < map.size(); ++j) {
364  cout << ", " << map[j];
365  }
366  cout << "]" << endl;
367  }
368  cout << "combined terms: " << endl;
369  for(unsigned int i = 0; i < _symTermMaps.size(); ++i) {
370  vector<unsigned int> map = _symTermMaps[i].fsPartPermMap;
371  cout << _symTermMaps[i].factor << ": [" << map[0];
372  for(unsigned int j = 1; j < map.size(); ++j) {
373  cout << ", " << map[j];
374  }
375  cout << "]" << endl;
376  }
377  }
378 
379  return true;
380 
381 };
382 
383 
384 ostream&
386 {
387  out << name() << ": " << endl
388  << " reflectivity basis ............... " << enDisabled(_useReflectivityBasis) << endl
389  << " Bose symmetrization .............. " << enDisabled(_boseSymmetrize ) << endl
390  << " isospin symmetrization ........... " << enDisabled(_isospinSymmetrize ) << endl
391  << " space inversion of FS momenta .... " << enDisabled(_doSpaceInversion ) << endl
392  << " reflection through prod. plane ... " << enDisabled(_doReflection ) << endl;
393  return out;
394 }
395 
396 
397 ostream&
398 isobarAmplitude::print(ostream& out) const
399 {
400  printParameters(out);
401  out << *_decay;
402  return out;
403 }