adding parentheses following gcc 4.3 suggestion
[u/mrichter/AliRoot.git] / HLT / RCU / AliHLTAltroGenerator.cxx
1 // $Id$
2
3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project        * 
5 //* ALICE Experiment at CERN, All rights reserved.                         *
6 //*                                                                        *
7 //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
8 //*                  for The ALICE HLT Project.                            *
9 //*                                                                        *
10 //* Permission to use, copy, modify and distribute this software and its   *
11 //* documentation strictly for non-commercial purposes is hereby granted   *
12 //* without fee, provided that the above copyright notice appears in all   *
13 //* copies and that both the copyright notice and this permission notice   *
14 //* appear in the supporting documentation. The authors make no claims     *
15 //* about the suitability of this software for any purpose. It is          *
16 //* provided "as is" without express or implied warranty.                  *
17 //**************************************************************************
18
19 /** @file   AliHLTAltroGenerator.cxx
20     @author Matthias Richter
21     @date   
22     @brief  Simulation class of 10/40bit Altro Data.
23 */
24
25 #include <cassert>
26 #include <cerrno>
27 #include "AliHLTAltroGenerator.h"
28 #include "TArrayS.h"
29 #include "TArrayC.h"
30 #include "TRandom.h"
31 #include "TDatime.h"
32 #include "AliRawDataHeader.h"
33 #include "AliHLTAltroEncoder.h"
34
35 /** ROOT macro for the implementation of ROOT specific class methods */
36 ClassImp(AliHLTAltroGenerator)
37
38 AliHLTAltroGenerator::AliHLTAltroGenerator(int maxChannels,
39                                            int maxBunches,
40                                            int maxBunchLength,
41                                            int maxTimebin,
42                                            int maxSignal)
43   :
44   fpData(NULL),
45   fpSimData(NULL),
46   fChannelPositions(),
47   fNof10BitWords(0),
48   fpCDH(NULL),
49   fCDHSize(0),
50   fpTrailer(NULL),
51   fTrailerSize(0),
52   fMaxChannels(maxChannels),
53   fMaxBunches(maxBunches),
54   fMaxBunchLength(maxBunchLength),
55   fMaxTimebin(maxTimebin),
56   fMaxSignal(maxSignal),
57   fpRand(NULL),
58   fDirection(kBackwards),
59   fCurrentPosition(-1),
60   fCurrentBunch(-1),
61   fCurrentTimeOffset(-1)
62 {
63   // see header file for class documentation
64   // or
65   // refer to README to build package
66   // or
67   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
68 }
69
70 AliHLTAltroGenerator::~AliHLTAltroGenerator()
71 {
72   // see header file for class documentation
73   if (fpTrailer) delete[] fpTrailer;
74   if (fpCDH) delete[] fpCDH;
75   if (fpSimData) delete fpSimData;
76   if (fpData) delete fpData;
77 }
78
79 int AliHLTAltroGenerator::Generate()
80 {
81   // see header file for class documentation
82   int iResult=0;
83
84   if (!fpSimData) fpSimData=new TArrayS;
85   if (!fpSimData) {
86     return -ENOMEM;
87   }
88
89   Reset();
90
91   int nofChannels=GetRandom(1, fMaxChannels);
92   if (nofChannels==0) nofChannels=1;
93
94   HLTDebug("number of channels: %d", nofChannels);
95   int channelAddress=-1;
96   int lastChannel=-1;
97   int dataPos=0;
98   int repetitions=0;
99   for (int channel=0; channel<nofChannels; channel++) {
100     channelAddress=GetRandom(0, fMaxChannels);
101     //HLTDebug("channel %d: address %d, %d bunch(es)", channel, channelAddress, nofBunches);
102     if (channelAddress==lastChannel) {
103       channel--;
104       if (repetitions++>5) break;
105       continue;
106     }
107     int nofBunches=GetRandom(1, fMaxBunches);
108     if (nofBunches==0) {
109       channel--;
110       if (repetitions++>5) break;
111       continue;
112     }
113     repetitions=0;
114     int totalBunches=0;
115     int bunchEndTime=0;
116     int lastBunchEndTime=0;
117
118     HLTDebug("simulate channel %d: address %d", channel, channelAddress);
119
120     // save beginning of this channel for better navigation
121     AliChannelPosition position={channelAddress, dataPos, 0};
122
123     // add channel address and bunch count at the beginning
124     if (fpSimData->GetSize()<dataPos+2) fpSimData->Set(dataPos+2);
125     (*fpSimData)[dataPos++]=channelAddress;
126     dataPos++; // placeholder for number of bunches
127
128     int bunch=0;
129
130     // Matthias Oct 2008:
131     // Data was simulated in the wrong order: bunches for the higher timebins
132     // first. But real data is the other way round: bunches are written in the order
133     // of ascending timebins. A new consistency check was added to AliAltroDecoder
134     // (AliAltroBunch) in revision 29090. Now the channels are checked for overlapping
135     // bunches, the time of a bunch must be smaller than time of the previous one
136     // minus its length.
137     // Data is now simulated in the right order in order to fullfil this check.
138     for (bunch=0; bunch<nofBunches && bunchEndTime<fMaxTimebin-3; bunch++) {
139       while ((bunchEndTime+=GetRandom(0, fMaxTimebin-bunchEndTime))-lastBunchEndTime<3) {/*empty body*/};
140       int bunchLength=GetRandom(0, bunchEndTime-lastBunchEndTime<fMaxBunchLength?bunchEndTime-lastBunchEndTime:fMaxBunchLength);
141       if (bunchLength==0) continue;
142       totalBunches++;
143
144       HLTDebug("       bunch %d, length %d, end time %d ", bunch, bunchLength, bunchEndTime);
145
146       if (fpSimData->GetSize()<dataPos+bunchLength+4) fpSimData->Set(dataPos+bunchLength+4);
147       // write bunch length and time at both ends
148       (*fpSimData)[dataPos++]=bunchLength;
149       int time=bunchEndTime-bunchLength+1;
150       (*fpSimData)[dataPos++]=time;
151       for (; time<=bunchEndTime; time++) {      
152         int signal=GetRandom(0, fMaxSignal);
153         (*fpSimData)[dataPos++]=signal;
154       }
155       (*fpSimData)[dataPos++]=bunchEndTime;
156       (*fpSimData)[dataPos++]=bunchLength;
157       fNof10BitWords+=bunchLength+2;
158       lastBunchEndTime=bunchEndTime;
159       bunchEndTime+=bunchLength;
160     }
161     if (totalBunches>0) {
162       (*fpSimData)[position.fPosition+1]=totalBunches;
163       if (fpSimData->GetSize()<dataPos+2) fpSimData->Set(dataPos+2);
164       (*fpSimData)[dataPos++]=totalBunches;
165       position.fEnd=dataPos;
166       (*fpSimData)[dataPos++]=channelAddress;
167       lastChannel=channelAddress;
168       fNof10BitWords=(fNof10BitWords+7)/4; fNof10BitWords*=4; // align to 4 and add 4
169       fChannelPositions.push_back(position);
170       assert((*fpSimData)[position.fPosition]==(*fpSimData)[position.fEnd]);
171       HLTDebug("       channel %d added: address %d, %d bunch(es)", channel, channelAddress, totalBunches);
172     } else {
173       dataPos-=2;
174       HLTDebug("       channel %d skipped: address %d, %d bunch(es)", channel, channelAddress, totalBunches);
175     }
176   }
177
178   assert(fNof10BitWords%4==0);
179   if (iResult<0) {
180     fpSimData->Set(0);
181     return iResult;
182   }
183   fpSimData->Set(dataPos);
184   return GetDataSize();
185 }
186
187 int AliHLTAltroGenerator::GetNof40BitAltroWords() const
188 {
189   // see header file for class documentation
190   assert(fNof10BitWords%4==0);
191   return fNof10BitWords/4;
192 }
193
194 int AliHLTAltroGenerator::GetDataSize()
195 {
196   // see header file for class documentation
197   int iResult=0;
198   iResult=(fNof10BitWords*5)/4;
199   if (fpTrailer) {
200     *(reinterpret_cast<AliHLTUInt32_t*>(fpTrailer))=GetNof40BitAltroWords();
201     iResult+=fTrailerSize;
202   }
203   if (fpCDH) iResult+=fCDHSize;
204   return iResult;
205 }
206
207 int AliHLTAltroGenerator::GetData(AliHLTUInt8_t* &pBuffer)
208 {
209   // see header file for class documentation
210   int iResult=GetDataSize();
211   if (iResult>0) {
212     if (!fpData) fpData=new TArrayC(iResult);
213     if (fpData) {
214       if (fpData->GetSize()<iResult) fpData->Set(iResult);
215       if ((iResult=GetData(reinterpret_cast<AliHLTUInt8_t*>(fpData->GetArray()), fpData->GetSize()))>=0) {
216         pBuffer=reinterpret_cast<AliHLTUInt8_t*>(fpData->GetArray());
217       }
218     } else {
219       iResult=-ENOMEM;
220     }
221   }
222   return iResult;
223 }
224
225 int AliHLTAltroGenerator::GetData(AliHLTUInt8_t* pBuffer, int size)
226 {
227   // see header file for class documentation
228   int iResult=0;
229   int dataPos=0;
230
231   if (size<GetDataSize()) return -ENOSPC;
232
233   // copy Common Data Header
234   if (fpCDH) {
235     fpCDH->fSize=GetDataSize();
236     memcpy(pBuffer+dataPos, fpCDH, fCDHSize);
237     dataPos+=fCDHSize;
238   }
239
240   // encode simulated data
241   if ((iResult=EncodeData(pBuffer+dataPos, size-dataPos))>=0) {
242     dataPos+=iResult;
243   }
244
245   // copy trailer
246   if (fpTrailer) {
247     memcpy(pBuffer+dataPos, fpTrailer, fTrailerSize);
248     AliHLTUInt32_t* pLast=reinterpret_cast<AliHLTUInt32_t*>(fpTrailer+fTrailerSize-sizeof(AliHLTUInt32_t));
249     *pLast=GetNof40BitAltroWords();
250     dataPos+=fTrailerSize;
251   }
252
253   if (iResult<0) return iResult;
254   assert(fpCDH==NULL || (int)fpCDH->fSize==dataPos);
255   return dataPos;
256 }
257
258 int AliHLTAltroGenerator::SetCDH(AliRawDataHeader* pCDH, int size)
259 {
260   // see header file for class documentation
261   int iResult=0;
262   if (pCDH && size>0) {
263     if (fpCDH) delete[] fpCDH;
264     fpCDH=new AliRawDataHeader;
265     if (fpCDH) {
266       memcpy(fpCDH, pCDH, size);
267       fCDHSize=size;
268     } else {
269       iResult=-ENOMEM;
270     }
271   } else {
272     iResult=-EINVAL;
273   }
274   return iResult;
275 }
276
277 int AliHLTAltroGenerator::SetRCUTrailer(AliHLTUInt8_t* pTrailer, int size)
278 {
279   // see header file for class documentation
280   int iResult=0;
281   if (pTrailer && size>=(int)sizeof(AliHLTUInt32_t)) {
282     AliHLTUInt32_t* pLast=reinterpret_cast<AliHLTUInt32_t*>(pTrailer+size-sizeof(AliHLTUInt32_t));
283     if (size!=sizeof(AliHLTUInt32_t)) {
284       // if more than one trailer words, the last one is the trailer length (# 32bit words)
285       if (*pLast!=size/sizeof(AliHLTUInt32_t)) {
286         HLTError("invalid trailer: trailer length (last 32bit word) does not match trailer size (bytes)");
287         return -EBADF;
288       }
289     }
290     if (fpTrailer) delete[] fpTrailer;
291     fpTrailer=new AliHLTUInt8_t[size];
292     if (fpTrailer) {
293       memcpy(fpTrailer, pTrailer, size);
294       fTrailerSize=size;
295     } else {
296       iResult=-ENOMEM;
297     }
298   } else {
299     iResult=-EINVAL;
300   }
301   return iResult;
302 }
303
304 int AliHLTAltroGenerator::GetChannels(vector<AliHLTUInt16_t> list)
305 {
306   // see header file for class documentation
307   int iResult=0;
308   list.clear();
309   for (vector<AliChannelPosition>::iterator element=fChannelPositions.begin();
310        element!=fChannelPositions.end();
311        element++) {
312     list.push_back(element->fChannel);
313   }
314   iResult=list.size();
315   return iResult;
316 }
317
318 int AliHLTAltroGenerator::SetSorting(AliHLTUInt16_t */*array*/, int /*arraySize*/)
319 {
320   // see header file for class documentation
321   int iResult=0;
322   HLTError("function not yet implemented");
323   return iResult;
324 }
325
326 int AliHLTAltroGenerator::EncodeData(AliHLTUInt8_t* pBuffer, int size)
327 {
328   // see header file for class documentation
329   int iResult=0;
330   if (!pBuffer) return -EINVAL;
331
332   AliHLTAltroEncoder encoder;
333   encoder.SetBuffer(pBuffer, size);
334
335   Short_t channelAddress=-1;
336   for (vector<AliChannelPosition>::iterator element=fChannelPositions.begin();
337        element!=fChannelPositions.end() && iResult>=0;
338        element++) {
339     if (!fpSimData ||
340         fpSimData->GetSize()<=element->fPosition ||
341         fNof10BitWords==0) {
342       iResult=-ENODATA;
343       break;
344     }
345     channelAddress=element->fChannel;
346     assert(fpSimData->At(element->fPosition)==channelAddress);
347     if (fpSimData->At(element->fPosition)!=channelAddress) {
348       iResult=-ENODATA;
349       break;
350     }
351     int dataPos=element->fPosition+1;
352     int nofBunches=fpSimData->At(dataPos++);
353     int bunch=0;
354     for (; bunch<nofBunches; bunch++) {
355       int bunchLength=fpSimData->At(dataPos++);
356       int startTime=fpSimData->At(dataPos++);
357       int time=startTime;
358       for (; time<startTime+bunchLength; time++) {
359         iResult=encoder.AddSignal(fpSimData->At(dataPos++), time);
360       }
361       assert(time-1==fpSimData->At(dataPos));
362       dataPos++; // DO NOT PUT INTO ASSERT
363       assert(bunchLength==fpSimData->At(dataPos));
364       dataPos++; // DO NOT PUT INTO ASSERT
365     }
366
367     if (iResult>=0 && channelAddress>=0) {
368       assert(nofBunches==fpSimData->At(dataPos));
369       dataPos++; // DO NOT PUT INTO ASSERT
370       assert(channelAddress==fpSimData->At(dataPos));
371       dataPos++; // DO NOT PUT INTO ASSERT
372     }
373     encoder.SetChannel(channelAddress);
374   }
375
376   if (iResult>=0) {
377     iResult=(encoder.GetTotal40bitWords()*5)/4;
378   }
379
380   return iResult;
381 }
382
383 int AliHLTAltroGenerator::GetRandom(int min, int max)
384 {
385   // see header file for class documentation
386   if (max-min<2) return min;
387   bool setTheSeed=fpRand!=NULL;
388   if (fpRand==NULL) {
389     fpRand=new TRandom;
390   }
391   if (fpRand==NULL) return min;
392   if (!setTheSeed) {
393     TDatime dt;
394     fpRand->SetSeed(dt.Get());
395   }
396   return fpRand->Integer(max-min);
397 }
398
399 int AliHLTAltroGenerator::Reset()
400 {
401   // see header file for class documentation
402   fChannelPositions.clear();
403   fNof10BitWords=0;
404   Rewind();
405   return 0;
406 }
407
408 int AliHLTAltroGenerator::Rewind()
409 {
410   // see header file for class documentation
411   fCurrentPosition=-1;
412   fCurrentBunch=-1;
413   fCurrentTimeOffset=-1;
414   return 0;
415 }
416
417 bool AliHLTAltroGenerator::Next()
418 {
419   // see header file for class documentation
420   bool haveData=false;
421   if (!fpSimData) return false;
422   do {
423     if ((haveData=(fCurrentTimeOffset>=0 &&
424                    fCurrentBunch>0 &&
425                    ++fCurrentTimeOffset<GetBunchSize()))) {
426       break;
427     }
428
429     if ((haveData=(NextBunch()) && GetBunchSize()>0)) {
430       fCurrentTimeOffset=0;
431       break;
432     }
433   } while (NextChannel());
434   return haveData;
435 }
436
437 AliHLTUInt16_t AliHLTAltroGenerator::GetSignal()
438 {
439   // see header file for class documentation
440   if (!fpSimData || fCurrentTimeOffset<0) return 0;
441   assert(fCurrentPosition>=0 && fCurrentPosition<(int)fChannelPositions.size());
442   assert(fCurrentBunch>=0);
443   if (fDirection==kForwards) {
444     return fpSimData->At(fCurrentBunch+2+fCurrentTimeOffset);
445   } else if (fDirection==kBackwards){
446     return fpSimData->At(fCurrentBunch-(2+fCurrentTimeOffset));
447   }
448   return 0;
449 }
450
451 bool AliHLTAltroGenerator::NextChannel()
452 {
453   // see header file for class documentation
454   bool haveData=false;
455   if (fpSimData && fChannelPositions.size()==0) return false;
456   fpSimData->GetArray();
457   if (fCurrentPosition==-1) {
458     if (fDirection==kForwards) fCurrentPosition=0;
459     else fCurrentPosition=fChannelPositions.size()-1;
460     haveData=true;
461   } else {
462     if (fDirection==kForwards && (haveData=(fCurrentPosition+1<(int)fChannelPositions.size()))) {
463       fCurrentPosition++;
464     } else if (fDirection==kBackwards && (haveData=(fCurrentPosition>0))) {
465       fCurrentPosition--;
466     }
467   }
468   
469   fCurrentBunch=-1;
470   fCurrentTimeOffset=-1;
471   return haveData;
472 }
473
474 AliHLTUInt16_t AliHLTAltroGenerator::GetHwAddress()
475 {
476   // see header file for class documentation
477   if (fCurrentPosition>=0 && fCurrentPosition<(int)fChannelPositions.size())
478     return fChannelPositions[fCurrentPosition].fChannel;
479   return ~((AliHLTUInt16_t)0);
480 }
481
482 int AliHLTAltroGenerator::GetBunchCount()
483 {
484   // see header file for class documentation
485   if (fpSimData && fCurrentPosition>=0 && fCurrentPosition<(int)fChannelPositions.size()) {
486     if (fDirection==kForwards)
487       return fpSimData->At(fChannelPositions[fCurrentPosition].fPosition+1);
488     else if (fDirection==kBackwards)
489       return fpSimData->At(fChannelPositions[fCurrentPosition].fEnd-1);
490   }
491   return ~((AliHLTUInt16_t)0);
492 }
493
494 bool AliHLTAltroGenerator::NextBunch()
495 {
496   // see header file for class documentation
497   bool haveData=false;
498   if (fpSimData && fCurrentPosition>=0 && fCurrentPosition<(int)fChannelPositions.size()) {
499     if (fDirection==kBackwards) {
500       if (fCurrentBunch<0) {
501         // bunch count in channel end - 1
502         if ((haveData=(fpSimData->At(fChannelPositions[fCurrentPosition].fEnd-1))>0)) {
503           // first bunch length at channel end - 2
504           fCurrentBunch=fChannelPositions[fCurrentPosition].fEnd-2;
505         }
506       } else if (fCurrentBunch>fChannelPositions[fCurrentPosition].fPosition+1) {
507         fCurrentBunch-=fpSimData->At(fCurrentBunch)+4;
508         haveData=fCurrentBunch>fChannelPositions[fCurrentPosition].fPosition+1;
509       }
510       // cross check
511       if (haveData) {
512         assert(fpSimData->At(fCurrentBunch)==fpSimData->At(fCurrentBunch-fpSimData->At(fCurrentBunch)-3));
513         haveData=fpSimData->At(fCurrentBunch)==fpSimData->At(fCurrentBunch-fpSimData->At(fCurrentBunch)-3);
514       }
515     } else if (fDirection==kForwards) {
516       if (fCurrentBunch<0) {
517         // bunch count in channel start + 1
518         if ((haveData=(fpSimData->At(fChannelPositions[fCurrentPosition].fPosition+1))>0)) {
519           // first bunch length at channel start + 2
520           fCurrentBunch=fChannelPositions[fCurrentPosition].fPosition+2;
521         }
522       } else if (fCurrentBunch<fChannelPositions[fCurrentPosition].fEnd-1) {
523         fCurrentBunch+=fpSimData->At(fCurrentBunch)+4;
524         haveData=fCurrentBunch<fChannelPositions[fCurrentPosition].fEnd-1;
525       }
526       // cross check
527       if (haveData) {
528         assert(fpSimData->At(fCurrentBunch)==fpSimData->At(fCurrentBunch+fpSimData->At(fCurrentBunch)+3));
529         haveData=fpSimData->At(fCurrentBunch)==fpSimData->At(fCurrentBunch+fpSimData->At(fCurrentBunch)+3);
530       }
531     }
532   }
533   fCurrentTimeOffset=-1;
534   return haveData;
535 }
536
537 AliHLTUInt16_t AliHLTAltroGenerator::GetBunchSize()
538 {
539   // see header file for class documentation
540   if (fCurrentBunch<0) return 0;
541   if (fCurrentBunch<fChannelPositions[fCurrentPosition].fPosition+2) return 0;
542   if (fCurrentBunch>fChannelPositions[fCurrentPosition].fEnd-2) return 0;
543   return fpSimData->At(fCurrentBunch);
544 }
545
546 AliHLTUInt16_t AliHLTAltroGenerator::GetStartTime()
547 {
548   // see header file for class documentation
549   if (!fpSimData || GetBunchSize()==0) return 0;
550   AliHLTUInt16_t startTime=0;
551   if (fDirection==kForwards) {
552     startTime=fpSimData->At(fCurrentBunch+1);
553   } else if (fDirection==kBackwards) {
554     startTime=fpSimData->At(fCurrentBunch-fpSimData->At(fCurrentBunch)-2);
555   }
556   if (fCurrentTimeOffset>=0) {
557     if (fDirection==kForwards) {
558       startTime+=fCurrentTimeOffset;
559     } else if (fDirection==kBackwards) {
560       startTime=GetEndTime();
561     }
562   }
563   return startTime;
564 }
565
566 AliHLTUInt16_t AliHLTAltroGenerator::GetEndTime()
567 {
568   // see header file for class documentation
569   if (!fpSimData || GetBunchSize()==0) return 0;
570   AliHLTUInt16_t endTime=0;
571   if (fDirection==kForwards) {
572     endTime=fpSimData->At(fCurrentBunch+fpSimData->At(fCurrentBunch)+2);
573   } else if (fDirection==kBackwards) {
574     endTime=fpSimData->At(fCurrentBunch-1);
575   }
576   if (fCurrentTimeOffset>=0) {
577     assert(fCurrentTimeOffset<fpSimData->At(fCurrentBunch));
578     if (fDirection==kForwards) {
579       endTime=GetStartTime();
580     } else if (fDirection==kBackwards) {
581       endTime-=fCurrentTimeOffset;
582     }
583   }
584   return endTime;
585 }
586
587 const Short_t* AliHLTAltroGenerator::GetSignals()
588 {
589   // see header file for class documentation
590   if (!fpSimData || GetBunchSize()==0) return NULL;
591   if (fDirection==kForwards) {
592     return fpSimData->GetArray()+fCurrentBunch+2;
593   } else if (fDirection==kBackwards) {
594     return fpSimData->GetArray()+(fCurrentBunch-fpSimData->At(fCurrentBunch)-1);
595   }
596   return NULL;
597 }
598
599 void AliHLTAltroGenerator::Print()
600 {
601   // see header file for class documentation
602   cout << *this << endl;
603 }
604
605 ostream &operator<<(ostream &stream, AliHLTAltroGenerator &generator)
606 {
607   // see header file for class documentation
608   int iResult=0;
609   Short_t channelAddress=-1;
610   for (vector<AliHLTAltroGenerator::AliChannelPosition>::iterator element=generator.fChannelPositions.begin();
611        element!=generator.fChannelPositions.end() && iResult>=0;
612        element++) {
613     if (!generator.fpSimData ||
614         generator.fpSimData->GetSize()<=element->fPosition ||
615         generator.fNof10BitWords==0) {
616       stream << "AliHLTAltroGenerator: no data available" << endl;;
617       break;
618     }
619     channelAddress=element->fChannel;
620     assert(generator.fpSimData->At(element->fPosition)==channelAddress);
621     if (generator.fpSimData->At(element->fPosition)!=channelAddress) {
622       stream << "AliHLTAltroGenerator: internal data mismatch" << endl;;
623       iResult=-ENODATA;
624       break;
625     }
626     int dataPos=element->fPosition+1;
627     int nofBunches=generator.fpSimData->At(dataPos++);
628     stream << "***************************************************************" << endl;
629     stream << "channel address: " << channelAddress << "    " << nofBunches << " bunch(es)" << endl;
630     int bunch=0;
631     for (; bunch<nofBunches; bunch++) {
632       int bunchLength=generator.fpSimData->At(dataPos++);
633       int startTime=generator.fpSimData->At(dataPos++);
634       int time=startTime;
635       stream << "   length " << bunchLength << " start time " << startTime << ":     ";
636       for (; time<startTime+bunchLength; time++) {
637         stream << " " << generator.fpSimData->At(dataPos++);
638       }
639       assert(time-1==generator.fpSimData->At(dataPos));
640       dataPos++; // DO NOT PUT INTO ASSERT
641       assert(bunchLength==generator.fpSimData->At(dataPos));
642       dataPos++; // DO NOT PUT INTO ASSERT
643       stream << "      -> end time " << time-1 << endl;
644     }
645
646     if (iResult>=0 && channelAddress>=0) {
647       assert(nofBunches==generator.fpSimData->At(dataPos));
648       dataPos++; // DO NOT PUT INTO ASSERT
649       assert(channelAddress==generator.fpSimData->At(dataPos));
650       dataPos++; // DO NOT PUT INTO ASSERT
651     }
652   }
653
654   return stream;
655 }