ROOTPWA
ampIntegralMatrix.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 // container class for complex amplitude integral matrices
29 //
30 //
31 // Author List:
32 // Boris Grube TUM (original author)
33 //
34 //
35 //-------------------------------------------------------------------------
36 
37 
38 #include <boost/progress.hpp>
39 #include <boost/numeric/conversion/cast.hpp>
40 
41 #include "TClass.h"
42 #include "TFile.h"
43 #include "TKey.h"
44 #include "TTree.h"
45 #include "TROOT.h"
46 #include "TBuffer.h"
47 
48 #include "reportingUtils.hpp"
49 #include "fileUtils.hpp"
50 #include "sumAccumulators.hpp"
51 #include "amplitudeTreeLeaf.h"
52 #include "ampIntegralMatrix.h"
53 
54 
55 using namespace std;
56 using namespace boost;
57 using namespace boost::accumulators;
58 using namespace rpwa;
59 
60 
61 #ifdef USE_STD_COMPLEX_TREE_LEAFS
63 #endif
64 
65 
66 bool ampIntegralMatrix::_debug = false;
67 
68 
69 ampIntegralMatrix::ampIntegralMatrix()
70  : TObject (),
71  _nmbWaves (0),
72  _waveNameToIndexMap (),
73  _waveNames (),
74  _nmbEvents (0),
75  _integrals (),
76  _intStorageShape (),
77  _intStorageNmbElements(0),
78  _intStorageData (0),
79  _waveDescriptions ()
80 {
81  //ampIntegralMatrix::Class()->IgnoreTObjectStreamer(); // don't store TObject's fBits and fUniqueID
82 }
83 
84 
86 {
87  *this = integral;
88 }
89 
90 
92 { }
93 
94 
95 void
97 {
98  _nmbWaves = 0;
99  _nmbEvents = 0;
100  _waveNameToIndexMap.clear();
101  _waveNames.clear();
102  _integrals.resize(extents[0][0]);
103  _intStorageShape.clear();
105  _intStorageData = 0;
106  _waveDescriptions.clear();
107 }
108 
109 
112 {
113  if (this != &integral) {
114  TObject::operator =(integral);
115  _nmbWaves = integral._nmbWaves;
117  _waveNames = integral._waveNames;
118  _nmbEvents = integral._nmbEvents;
119  // multiarray's = operator does not seem to set shape correctly
120  // setting manually prevents crash in glibc
121  const sizeType* shape = integral._integrals.shape();
122  _integrals.resize(extents[shape[0]][shape[1]]);
123  _integrals = integral._integrals;
125  }
126  return *this;
127 }
128 
129 
132 {
133  if (not hasIdenticalWaveSet(integral)) {
134  printErr << "cannot add " << *this << endl
135  << "and " << integral << endl
136  << "because the two integral matrices have different wave sets. aborting." << endl;
137  throw;
138  }
139  for (unsigned int i = 0; i < _nmbWaves; ++i) {
140  const string waveNameI = waveName(i);
141  for (unsigned int j = 0; j < _nmbWaves; ++j)
142  _integrals[i][j] += integral.matrix()[waveIndex(waveNameI)][waveIndex(waveName(j))];
143  }
144  _nmbEvents += integral.nmbEvents();
146  return *this;
147 }
148 
149 
152 {
153  if (not hasIdenticalWaveSet(integral)) {
154  printErr << "cannot subtract " << integral << endl
155  << "from " << *this << endl
156  << "because the two integral matrices have different wave sets. aborting." << endl;
157  throw;
158  }
159  for (unsigned int i = 0; i < _nmbWaves; ++i) {
160  const string waveNameI = waveName(i);
161  for (unsigned int j = 0; j < _nmbWaves; ++j)
162  _integrals[i][j] -= integral.matrix()[waveIndex(waveNameI)][waveIndex(waveName(j))];
163  }
164  _nmbEvents -= integral.nmbEvents();
166  return *this;
167 }
168 
169 
171 ampIntegralMatrix::operator *=(const double factor)
172 {
173  for (unsigned int i = 0; i < _nmbWaves; ++i)
174  for (unsigned int j = 0; j < _nmbWaves; ++j)
175  _integrals[i][j] *= factor;
176  _nmbEvents *= factor;
177  return *this;
178 }
179 
180 
182 ampIntegralMatrix::operator /=(const double factor)
183 {
184  for (unsigned int i = 0; i < _nmbWaves; ++i)
185  for (unsigned int j = 0; j < _nmbWaves; ++j)
186  _integrals[i][j] /= factor;
187  _nmbEvents /= factor;
188  return *this;
189 }
190 
191 
192 bool
193 ampIntegralMatrix::containsWave(const string& waveName) const
194 {
195  waveNameToIndexMapIterator entry = _waveNameToIndexMap.find(waveName);
196  if (entry == _waveNameToIndexMap.end())
197  return false;
198  return true;
199 }
200 
201 
202 unsigned int
203 ampIntegralMatrix::waveIndex(const string& waveName) const
204 {
205  waveNameToIndexMapIterator entry = _waveNameToIndexMap.find(waveName);
206  if (entry == _waveNameToIndexMap.end()) {
207  printErr << "cannot find wave '" << waveName << "' in integral matrix. aborting." << endl;
208  throw;
209  }
210  return entry->second;
211 }
212 
213 
214 const string&
215 ampIntegralMatrix::waveName(const unsigned int waveIndex) const
216 {
217  if (waveIndex < _waveNames.size())
218  return _waveNames[waveIndex];
219  else {
220  printErr << "wave index " << waveIndex << " is out of range. aborting." << endl;
221  throw;
222  }
223 }
224 
225 
226 const waveDescription*
227 ampIntegralMatrix::waveDesc(const unsigned int waveIndex) const
228 {
229  if (waveIndex < _waveDescriptions.size())
230  return &(_waveDescriptions[waveIndex]);
231  return 0;
232 }
233 
234 
235 bool
237 {
238  for (unsigned i = 0; i < _waveDescriptions.size(); ++i)
239  if (not _waveDescriptions[i].keyFileParsed())
240  return false;
241  return true;
242 }
243 
244 
245 complex<double>
246 ampIntegralMatrix::element(const unsigned int waveIndexI,
247  const unsigned int waveIndexJ) const
248 {
249  if (waveIndexI >= _nmbWaves) {
250  printErr << "wave index for i = " << waveIndexI << " out of range. "
251  << "number of waves = " << _nmbWaves << endl;
252  throw;
253  }
254  if (waveIndexJ >= _nmbWaves) {
255  printErr << "wave index for j = " << waveIndexJ << " out of range. "
256  << "number of waves = " << _nmbWaves << endl;
257  throw;
258  }
259  return _integrals[waveIndexI][waveIndexJ] / ((double)_nmbEvents);
260 }
261 
262 
263 bool
264 ampIntegralMatrix::integrate(const vector<string>& binAmpFileNames,
265  const vector<string>& rootAmpFileNames,
266  const unsigned long maxNmbEvents,
267  const string& weightFileName)
268 {
269  // open amplitude files and set wave <-> index maps
270  vector<ifstream*> binAmpFiles;
271  const unsigned long nmbBinEvents = openBinAmpFiles(binAmpFiles, binAmpFileNames, 0);
272  const unsigned int nmbBinWaves = binAmpFiles.size();
273  vector<TTree*> ampTrees;
274  vector<amplitudeTreeLeaf*> ampTreeLeafs;
275  const unsigned long nmbRootEvents = openRootAmpFiles(ampTrees, ampTreeLeafs,
276  rootAmpFileNames, binAmpFiles.size());
277  const unsigned int nmbRootWaves = ampTrees.size();
278  _nmbWaves = nmbBinWaves + nmbRootWaves;
279  if (_nmbWaves > 0)
280  printInfo << "calculating integral for " << _nmbWaves << " amplitude(s)" << endl;
281  else {
282  printWarn << "could not open any amplitude files. cannot calculate integral." << endl;
283  return false;
284  }
285  if ((nmbBinEvents > 0) and (nmbRootEvents > 0) and (nmbBinEvents != nmbRootEvents)) {
286  printWarn << ".bin and .root amplitude files contain different number of amplitude values "
287  << "(" << nmbBinEvents << " vs. " << nmbRootEvents << "). "
288  << "cannot calculate integral." << endl;
289  return false;
290  }
291  if ((nmbBinEvents == 0) and (nmbRootEvents == 0)) {
292  printWarn << "amplitude files contain no amplitudes values. cannot calculate integral." << endl;
293  return false;
294  }
295  if (nmbBinEvents > 0)
296  _nmbEvents = nmbBinEvents;
297  else
298  _nmbEvents = nmbRootEvents;
299  _nmbEvents = (maxNmbEvents) ? min(_nmbEvents, maxNmbEvents) : _nmbEvents;
300 
301  // make sure that either all or none of the waves have description
302  if (not allWavesHaveDesc())
303  _waveDescriptions.clear();
304 
305  // resize integral matrix
306  //_integrals.clear();
307  _integrals.resize(extents[_nmbWaves][_nmbWaves]);
308 
309  // open importance sampling weight file
311  ifstream weightFile;
312  bool useWeight = false;
313  if (weightFileName != "") {
314  if (_debug)
315  printDebug << "opening importance sampling weight file '" << weightFileName << "'" << endl;
316  weightFile.open(weightFileName.c_str());
317  if (not weightFile) {
318  printWarn << "cannot open importance sampling weight file '" << weightFileName << "' "
319  << "cannot calculate integral." << endl;
320  return false;
321  }
322  useWeight = true;
323  }
324 
325  // loop over events and calculate integral matrix
326  accumulator_set<double, stats<tag::sum(compensated)> > weightAcc;
327  accumulator_set<complex<double>, stats<tag::sum(compensated)> > ampProdAcc[_nmbWaves][_nmbWaves];
328  // process weight file and binary amplitude files
329  vector<complex<double> > amps[_nmbWaves];
330  progress_display progressIndicator(_nmbEvents, cout, "");
331  bool success = true;
332  for (unsigned long iEvent = 0; iEvent < _nmbEvents; ++iEvent) {
334 
335  // sum up importance sampling weight
336  double w = 1;
337  if (useWeight)
338  if (not(weightFile >> w)) {
339  success = false;
340  printWarn << "error reading weight file. stopping integration "
341  << "at event " << iEvent << " of total " << _nmbEvents << "." << endl;
342  break;
343  }
344  const double weight = 1 / w; // we have to undo the weighting of the events!
345  weightAcc(weight);
346 
347  // read amplitude values for this event from binary files
348  bool ampBinEof = false;
349  for (unsigned int waveIndex = 0; waveIndex < nmbBinWaves; ++waveIndex) {
350  amps[waveIndex].resize(1); // no subamps supported in .amp files
351  binAmpFiles[waveIndex]->read((char*)&(amps[waveIndex][0]), sizeof(complex<double>));
352  if ((ampBinEof = binAmpFiles[waveIndex]->eof())) {
353  success = false;
354  printWarn << "unexpected EOF while reading binary amplitude '"
355  << _waveNames[waveIndex] << "'. stopping integration "
356  << "at event " << iEvent << " of total " << _nmbEvents << "." << endl;
357  break;
358  }
359  }
360  if (ampBinEof)
361  break;
362 
363  // read amplitude values for this event from root trees
364  for (unsigned int waveIndex = nmbBinWaves; waveIndex < _nmbWaves; ++waveIndex) {
365  const unsigned int index = waveIndex - nmbBinWaves; // zero based index
366  ampTrees[index]->GetEntry(iEvent);
367  const unsigned int nmbSubAmps = ampTreeLeafs[index]->nmbIncohSubAmps();
368  if (nmbSubAmps < 1) {
369  printErr << "amplitude object for wave '" << _waveNames[waveIndex] << "' "
370  << "does not contain any amplitude values "
371  << "at event " << iEvent << " of total " << _nmbEvents << ". aborting." << endl;
372  throw;
373  }
374  // get all incoherent subamps
375  amps[waveIndex].resize(nmbSubAmps);
376  for (unsigned int subAmpIndex = 0; subAmpIndex < nmbSubAmps; ++subAmpIndex)
377  amps[waveIndex][subAmpIndex] = ampTreeLeafs[index]->incohSubAmp(subAmpIndex);
378  }
379 
380  // sum up integral matrix elements
381  for (unsigned int waveIndexI = 0; waveIndexI < _nmbWaves; ++waveIndexI)
382  for (unsigned int waveIndexJ = 0; waveIndexJ < _nmbWaves; ++waveIndexJ) {
383  // sum over incoherent subamps
384  const unsigned int nmbSubAmps = amps[waveIndexI].size();
385  if (nmbSubAmps != amps[waveIndexJ].size()) {
386  printErr << "number of incoherent sub-amplitudes for wave '"
387  << _waveNames[waveIndexI] << "' = " << nmbSubAmps
388  << " differs from that of wave '" << _waveNames[waveIndexJ] << "' = "
389  << amps[waveIndexJ].size()
390  << " at event " << iEvent << " of total " << _nmbEvents << ". aborting. "
391  << "be sure to use only .root amplitude files, "
392  << "if your channel has sub-amplitudes." << endl;
393  throw;
394  }
395  complex<double> val = 0;
396  for (unsigned int subAmpIndex = 0; subAmpIndex < nmbSubAmps; ++subAmpIndex)
397  val += amps[waveIndexI][subAmpIndex] * conj(amps[waveIndexJ][subAmpIndex]);
398  if (useWeight)
399  val *= weight;
400  ampProdAcc[waveIndexI][waveIndexJ](val);
401  }
402  } // event loop
403 
404  // copy values from accumulators and (if necessary) renormalize to
405  // integral of importance sampling weights
406  const double weightNorm = sum(weightAcc) / (double)_nmbEvents;
407  for (unsigned int waveIndexI = 0; waveIndexI < _nmbWaves; ++waveIndexI)
408  for (unsigned int waveIndexJ = 0; waveIndexJ < _nmbWaves; ++waveIndexJ) {
409  _integrals[waveIndexI][waveIndexJ] = sum(ampProdAcc[waveIndexI][waveIndexJ]);
410  if (useWeight)
411  _integrals[waveIndexI][waveIndexJ] *= 1 / weightNorm;
412  }
413 
414  printSucc << "calculated integrals of " << _nmbWaves << " amplitude(s) "
415  << "for " << _nmbEvents << " events" << endl;
416  // cleanup
417  for (unsigned int i = 0; i < binAmpFiles.size(); ++i)
418  if (binAmpFiles[i])
419  delete binAmpFiles[i];
420  binAmpFiles.clear();
421  return success;
422 }
423 
424 
425 void
426 ampIntegralMatrix::renormalize(const unsigned long nmbEventsRenorm)
427 {
428  if (_debug)
429  printDebug << "renormalizing integrals from " << _nmbEvents << " "
430  << "to " << nmbEventsRenorm << " events." << endl;
431  *this *= (double)nmbEventsRenorm / _nmbEvents;
432  _nmbEvents = nmbEventsRenorm;
433 }
434 
435 
436 bool
437 ampIntegralMatrix::writeAscii(ostream& out) const
438 {
439  if (not out) {
440  printWarn << "cannot write to output stream. cannot write integral." << endl;
441  return false;
442  }
443  out << _nmbWaves << endl
444  << _nmbEvents << endl;
445  // write integral matrix
446  out << _nmbWaves << " " << _nmbWaves << endl;
447  for (unsigned int waveIndexI = 0; waveIndexI < _nmbWaves; ++waveIndexI) {
448  for (unsigned int waveIndexJ = 0; waveIndexJ < _nmbWaves; ++waveIndexJ)
449  out << maxPrecisionDouble(_integrals[waveIndexI][waveIndexJ]) << "\t";
450  out << endl;
451  }
452  // write wave name -> index map
453  out << _waveNameToIndexMap.size() << endl;
455  i != _waveNameToIndexMap.end(); ++i)
456  out << i->first << " " << i->second << endl;
457  return true;
458 }
459 
460 
461 bool
463 {
464  if (not (in >> _nmbWaves >> _nmbEvents)) {
465  printWarn << "could not read number of waves and events" << endl;
466  return false;
467  }
468  // read matrix elements
469  unsigned int nmbRows, nmbCols;
470  if (not (in >> nmbRows >> nmbCols)) {
471  printWarn << "could not read number of rows and columns" << endl;
472  return false;
473  }
474  // resize integral matrix
475  //_integrals.clear();
476  _integrals.resize(extents[nmbRows][nmbCols]);
477  for (unsigned int i = 0; i < nmbRows; ++i)
478  for (unsigned int j = 0; j < nmbCols; ++j) {
479  if (not (in >> _integrals[i][j]) or in.eof()) {
480  printErr << "could not read integral values. stream seems trunkated." << endl;
481  throw;
482  }
483  }
484  // read wave name -> index map
485  unsigned int mapSize;
486  in >> mapSize;
487  while ((mapSize > 0) and in) {
488  string waveName;
489  unsigned int waveIndex;
490  if (not (in >> waveName >> waveIndex)) {
491  printErr << "could not read wave name -> index map. stream seems trunkated." << endl;
492  return false;
493  }
495  --mapSize;
496  }
497  _waveNames.resize(_nmbWaves);
499  i != _waveNameToIndexMap.end(); ++i)
500  _waveNames[i->second] = i->first;
501  return true;
502 }
503 
504 
505 bool
506 ampIntegralMatrix::writeAscii(const string& outFileName) const
507 {
508  if (_debug)
509  printDebug << "opening ASCII file '" << outFileName << "' for writing of integral matrix" << endl;
510  ofstream outFile(outFileName.c_str());
511  if (not outFile or not outFile.good()) {
512  printWarn << "cannot open file '" << outFileName << "' for writing of integral matrix" << endl;
513  return false;
514  }
515  const bool success = writeAscii(outFile);
516  if (success)
517  printSucc << "wrote integral to ASCII file '" << outFileName << "'" << endl;
518  else
519  printWarn << "problems writing integral to ASCII file '" << outFileName << "'" << endl;
520  return success;
521 }
522 
523 
524 bool
525 ampIntegralMatrix::readAscii(const string& inFileName)
526 {
527  if (_debug)
528  printDebug << "opening ASCII file '" << inFileName << "' for reading of integral matrix" << endl;
529  fstream inFile(inFileName.c_str());
530  if (not inFile or not inFile.good()) {
531  printWarn << "cannot open file '" << inFileName << "' for reading of integral matrix" << endl;
532  return false;
533  }
534  const bool success = readAscii(inFile);
535  if (success)
536  printSucc << "read integral from ASCII file '" << inFileName << "'" << endl;
537  else
538  printWarn << "problems reading integral from ASCII file '" << inFileName << "'" << endl;
539  return success;
540 }
541 
542 
543 ostream&
545  const bool printIntegralValues) const
546 {
547  out << "amplitude integral matrix:" << endl
548  << " number of waves .... " << _nmbWaves << endl
549  << " number of events ... " << _nmbEvents << endl
550  << " wave name -> index map:" << endl;
552  i != _waveNameToIndexMap.end(); ++i)
553  out << " " << i->first << " -> " << i->second << " -> " << _waveNames[i->second] << endl;
554  if (printIntegralValues) {
555  out << " integral matrix values:" << endl;
556  for (unsigned int waveIndexI = 0; waveIndexI < _nmbWaves; ++waveIndexI)
557  for (unsigned int waveIndexJ = 0; waveIndexJ < _nmbWaves; ++waveIndexJ)
558  out << " [" << setw(4) << waveIndexI << ", " << setw(4) << waveIndexJ << "] = "
559  << maxPrecisionDouble(_integrals[waveIndexI][waveIndexJ]) << endl;
560  }
561  return out;
562 }
563 
564 
565 unsigned long
566 ampIntegralMatrix::openBinAmpFiles(vector<ifstream*>& ampFiles,
567  const vector<string>& ampFileNames,
568  const unsigned int waveIndexOffset)
569 {
570  ampFiles.clear();
571  streampos ampFileSize = 0;
572  unsigned int waveIndex = waveIndexOffset;
573  for (unsigned int i = 0; i < ampFileNames.size(); ++i) {
574 
575  // get file path
576  const string& ampFilePath = ampFileNames[i];
577 
578  // open amplitude file
579  if (_debug)
580  printDebug << "opening binary amplitude file '" << ampFilePath << "'" << endl;
581  ifstream* ampFile = new ifstream();
582  ampFile->open(ampFilePath.c_str());
583  if(not *ampFile) {
584  printWarn << "cannot open amplitude file '" << ampFilePath << "'. skipping file." << endl;
585  continue;
586  }
587 
588  // check that all files have the same size
589  const streampos fileSize = rpwa::fileSize(*ampFile);
590  if (fileSize == 0) {
591  printWarn << "amplitude file '" << ampFilePath << "' has zero size. skipping file." << endl;
592  continue;
593  }
594  if (ampFileSize == 0)
595  ampFileSize = fileSize;
596  else if (fileSize != ampFileSize) {
597  printWarn << "amplitude file '" << ampFilePath << "' has different size "
598  << "than previous file. skipping file." << endl;
599  continue;
600  }
601 
602  // fill wave name into name-to-index map, if not already existent
603  const string waveName = fileNameFromPath(ampFilePath);
604  if (not containsWave(waveName)) {
606  _waveNames.resize(waveIndex + 1);
608  ++waveIndex;
609  ampFiles.push_back(ampFile);
610  } else
611  printWarn << "wave '" << waveName << "' already exists in integral matrix. "
612  << "ignoring file '" << ampFilePath << "'. "
613  << "make sure that there are no duplicate .amp files." << endl;
614  }
615  const unsigned int nmbAmpValues = ampFileSize / sizeof(complex<double>);
616  return nmbAmpValues;
617 }
618 
619 
620 unsigned long
621 ampIntegralMatrix::openRootAmpFiles(vector<TTree*>& ampTrees,
622  vector<amplitudeTreeLeaf*>& ampTreeLeafs,
623  const vector<string>& ampFileNames,
624  const unsigned int waveIndexOffset,
625  const string& ampLeafName)
626 {
627  ampTrees.clear ();
628  ampTreeLeafs.clear();
629  unsigned long nmbAmps = 0;
630 #ifdef USE_STD_COMPLEX_TREE_LEAFS
631  // force loading predefined std::complex dictionary
632  // see http://root.cern.ch/phpBB3/viewtopic.php?f=5&t=9618&p=50164
633  gROOT->ProcessLine("#include <complex>");
634  unsigned int waveIndex = waveIndexOffset;
635  vector<TTree*> trees;
636  vector<waveDescription*> waveDescs;
637  vector<string> keyNames;
638  for (unsigned int ampFileIndex = 0; ampFileIndex < ampFileNames.size(); ++ampFileIndex) {
639 
640  // get file path
641  const string& ampFilePath = ampFileNames[ampFileIndex ];
642 
643  // open amplitude file
644  if (_debug)
645  printDebug << "opening .root amplitude file '" << ampFilePath << "'" << endl;
646  TFile* ampFile = TFile::Open(ampFilePath.c_str(), "READ");
647  if (not ampFile or ampFile->IsZombie()) {
648  printErr << "could open amplitude file '" << ampFilePath << "'. skipping file." << endl;
649  continue;
650  }
651 
652  // find all amplitude trees with name matching *.amp and corresponding .key wave description
653  TIterator* keys = ampFile->GetListOfKeys()->MakeIterator();
654  bool foundAmpKey = false;
655  while (TKey* k = static_cast<TKey*>(keys->Next())) {
656  if (!k) {
657  printWarn << "NULL pointer to TKey in file '" << ampFilePath << "'. skipping TKey." << endl;
658  continue;
659  }
660  TTree* tree = 0;
662  const string keyName = k->GetName();
663  if (extensionFromPath(keyName) == "amp") {
664  foundAmpKey = true;
665  ampFile->GetObject(keyName.c_str(), tree);
666  // get corresponding .key wave description
667  ampFile->GetObject((changeFileExtension(keyName, "key")).c_str(), waveDesc);
668  trees.push_back (tree );
669  waveDescs.push_back(waveDesc);
670  keyNames.push_back (keyName );
671  }
672  }
673  if (not foundAmpKey)
674  printWarn << "no TKey in file '" << ampFilePath << "' matches '*.amp'. skipping file." << endl;
675  }
676 
677  // check whether reading was successful
678  assert((trees.size() == waveDescs.size()) and (trees.size() == keyNames.size()));
679  for (unsigned int i = 0; i < trees.size(); ++i)
680  if (not trees[i] or not waveDescs[i]) {
681  printWarn << "could not read tree or wave description from TKeys '"
682  << fileNameNoExtFromPath(keyNames[i]) << ".{amp,key}'. "
683  << "skipping TKeys." << endl;
684  trees.erase (trees.begin () + i);
685  waveDescs.erase(waveDescs.begin() + i);
686  keyNames.erase (keyNames.begin () + i);
687  }
688  assert((trees.size() == waveDescs.size()) and (trees.size() == keyNames.size()));
689  const unsigned int nmbAmpTrees = trees.size();
690 
691  // get amplitude leafs
692  _waveNames.resize(waveIndex + nmbAmpTrees + 1);
693  _waveDescriptions.resize(waveIndex + nmbAmpTrees + 1);
694  for (unsigned int i = 0; i < nmbAmpTrees; ++i) {
695  // connect tree leaf
696  amplitudeTreeLeaf* treeLeaf = 0;
697  trees[i]->SetBranchAddress(ampLeafName.c_str(), &treeLeaf);
698 
699  // check that all trees have the same number of entries
700  const unsigned long nmbEntries = numeric_cast<unsigned long>(trees[i]->GetEntriesFast());
701  if (nmbEntries == 0) {
702  printWarn << "amplitude tree '" << trees[i]->GetName() << "' has zero entries. "
703  << "skipping tree." << endl;
704  continue;
705  }
706  if (nmbAmps == 0)
707  nmbAmps = nmbEntries;
708  else if (nmbEntries != nmbAmps) {
709  printWarn << "amplitude tree '" << trees[i]->GetName() << "' has different number "
710  << "of entries than previous tree. skipping tree." << endl;
711  continue;
712  }
713 
714  // fill wave name into name-to-index map, if not already existent
715  const string waveName = fileNameNoExtFromPath(trees[i]->GetName());
716  if (not containsWave(waveName)) {
719  _waveDescriptions[waveIndex] = *(waveDescs[i]);
720  ++waveIndex;
721  ampTrees.push_back (trees[i]);
722  ampTreeLeafs.push_back(treeLeaf);
723  } else
724  printWarn << "wave '" << waveName << "' already exists in integral matrix. "
725  << "ignoring tree '" << trees[i]->GetName() << "'." << endl;
726  }
727 #endif // USE_STD_COMPLEX_TREE_LEAFS
728  return nmbAmps;
729 }
730 
731 
732 void
734 {
735  _waveNameToIndexMap.clear();
736  for (unsigned int i = 0; i < _waveNames.size(); ++i)
737  if (not containsWave(_waveNames[i]))
739  else
740  printWarn << "wave '" << _waveNames[i] << "' already exists in integral matrix. "
741  << "ignoring wave." << endl;
742 }
743 
744 
745 bool
747 {
748  if (nmbWaves() != integral.nmbWaves())
749  return false;
750  // check that all waves in this integral are also in other integral
751  for (unsigned int i = 0; i < _nmbWaves; ++i)
752  if (not integral.containsWave(waveName(i)))
753  return false;
754  // check that all waves in other integral are also in this integral
755  for (unsigned int i = 0; i < integral.nmbWaves(); ++i)
756  if (not containsWave(integral.waveName(i)))
757  return false;
758  return true;
759 }
760 
761 
762 void
764 {
765  // set storage variables
766  _intStorageShape.resize(_integrals.num_dimensions());
767  for (sizeType i = 0; i < _integrals.num_dimensions(); ++i)
768  _intStorageShape[i] = _integrals.shape()[i];
769  _intStorageNmbElements = _integrals.num_elements();
770  _intStorageData = _integrals.data();
771 }
772 
773 
774 void
776 {
777  // rebuild multiarray from storage variables
778  assert(_intStorageShape.size() == _integrals.num_dimensions());
779  _integrals.resize(extents[_intStorageShape[0]][_intStorageShape[1]]);
780  complex<double>* integralData = _integrals.data();
781  for (unsigned int i = 0; i < _intStorageNmbElements; ++i)
782  integralData[i] = _intStorageData[i];
783 }
784 
785 
786 // custom streamer that triggers copying of multiarray into C struct
787 // before writing and rebuilding of multiarrays after reading
788 //
789 // this might not work when ampIntegralMatrix is used as a TTree leaf
790 //
791 // a more elegant way would be to use read- and write-rule pragmas, but
792 // write rules are not yet supported
793 //
794 // see
795 // http://root.cern.ch/phpBB3/viewtopic.php?f=3&t=12213&p=54249&hilit=TStreamerInfo
796 // http://root.cern.ch/phpBB3/viewtopic.php?f=3&t=7334&p=30634&hilit=streamer+custom
797 void
798 ampIntegralMatrix::Streamer(TBuffer& R__b)
799 {
800  if (R__b.IsReading()) {
801  R__b.ReadClassBuffer(rpwa::ampIntegralMatrix::Class(), this);
802  readMultiArray();
804  } else {
805  storeMultiArray();
806  R__b.WriteClassBuffer(rpwa::ampIntegralMatrix::Class(), this);
807  }
808 }