]> git.uio.no Git - u/mrichter/AliRoot.git/blob - RALICE/icepack/iceconvert/IceRawTWR.cxx
fa15e48df267e0e87db6975d967f8eb84e1ad7c5
[u/mrichter/AliRoot.git] / RALICE / icepack / iceconvert / IceRawTWR.cxx
1 /*******************************************************************************
2  * Copyright(c) 2003, IceCube Experiment at the South Pole. All rights reserved.
3  *
4  * Author: The IceCube RALICE-based Offline Project.
5  * Contributors are mentioned in the code where appropriate.
6  *
7  * Permission to use, copy, modify and distribute this software and its
8  * documentation strictly for non-commercial purposes is hereby granted
9  * without fee, provided that the above copyright notice appears in all
10  * copies and that both the copyright notice and this permission notice
11  * appear in the supporting documentation.
12  * The authors make no claims about the suitability of this software for
13  * any purpose. It is provided "as is" without express or implied warranty.
14  *******************************************************************************/
15
16 // $Id$
17
18 ///////////////////////////////////////////////////////////////////////////
19 // Class IceRawTWR
20 // Conversion of Amanda raw TWR data into IceEvent data structures.
21 // The code to actually read the TWR raw data structures is an Ralice/IcePack
22 // implementation of Wolfgang Wagner's (Dortmund University, Germany)
23 // original read_twr_binary_file.cxx and wf2hit_new.cxx source code.
24 // The trigger information as encountered in the raw data, is available
25 // in the IceEvent structure via a device named "Trigger".
26 // The various triggers (and times) have been stored as different "hits"
27 // in this "Trigger" device, just like it was done in the IceF2k processor
28 // for the mu-daq F2K data.
29 // An indication of the active DAQ system is available in the IceEvent structure
30 // via a device named "Daq". Here the various daq systems (TWR, Muon, ...)
31 // from which the actual hits (ADC, LE, TOT) eventually will be composed
32 // are indicated as "signals" of the device itself. 
33 // This class is derived from AliJob providing a task-based processing
34 // structure on an event-by-event basis.
35 // The main object in the job environment is an IceEvent* pointer.
36 // In case the user has provided sub-tasks, these will be executed
37 // on an event-by-event basis after the IceEvent structure has been filled
38 // with the raw TWR data and before the final structures are written out.
39 // Note that the data structures are only written out if an outputfile has
40 // been specified via the SetOutputFile memberfunction.
41 // In case no outputfile has been specified, this class provides a facility
42 // to investigate/analyse raw TWR data using the Ralice/IcePack analysis tools.
43 //
44 // Usage example :
45 // ---------------
46 //
47 // gSystem->Load("ralice");
48 // gSystem->Load("icepack");
49 // gSystem->Load("iceconvert");
50 //
51 // IceRawTWR q("IceRawTWR","TWR raw data to IcePack data structure conversion");
52 //
53 // // Limit the number of entries for testing
54 // q.SetMaxEvents(10);
55 //
56 // // Print frequency to produce a short summary print every printfreq events
57 // q.SetPrintFreq(1);
58 //
59 // // The TWR raw data input filename(s)
60 // q.AddInputFile("twr_2005_101_009225_0983_57784_57850.dat.twr.to_tape_1");
61 //
62 // // Output file for the event structures
63 // q.SetOutputFile("events.root");
64 //
65 // ///////////////////////////////////////////////////////////////////
66 // // Here the user can specify his/her sub-tasks to be executed
67 // // on an event-by-event basis after the IceEvent structure
68 // // has been filled and before the data is written out.
69 // // Sub-tasks (i.e. a user classes derived from TTask) are entered
70 // // as follows :
71 // //
72 // //    MyXtalk task1("task1","Cross talk correction");
73 // //    MyClean task2("task2","Hit cleaning");
74 // //    q.Add(&task1);
75 // //    q.Add(&task2);
76 // //
77 // // The sub-tasks will be executed in the order as they are entered.
78 // ///////////////////////////////////////////////////////////////////
79 //
80 // // Perform the conversion and execute subtasks (if any)
81 // // on an event-by-event basis
82 // q.ExecuteJob();
83 //
84 //--- Author: Nick van Eijndhoven 12-dec-2006 Utrecht University
85 //- Modified: NvE $Date$ Utrecht University
86 ///////////////////////////////////////////////////////////////////////////
87  
88 #include "IceRawTWR.h"
89 #include "Riostream.h"
90
91 ClassImp(IceRawTWR) // Class implementation to enable ROOT I/O
92
93 IceRawTWR::IceRawTWR(const char* name,const char* title) : AliJob(name,title)
94 {
95 // Default constructor.
96 // By default maxevent=-1, split=0, bsize=32000, printfreq=1.
97
98  fSplit=0;
99  fBsize=32000;
100  fMaxevt=-1;
101  fPrintfreq=1;
102  fInfiles=0;
103  fOutfile=0;
104 }
105 ///////////////////////////////////////////////////////////////////////////
106 IceRawTWR::~IceRawTWR()
107 {
108 // Default destructor.
109
110  if (fInfiles)
111  {
112   delete fInfiles;
113   fInfiles=0;
114  }
115 }
116 ///////////////////////////////////////////////////////////////////////////
117 void IceRawTWR::SetMaxEvents(Int_t n)
118 {
119 // Set the maximum number of events to be processed.
120 // n=-1 implies processing of the complete input file, which is the default
121 // initialisation in the constructor.
122  fMaxevt=n;
123 }
124 ///////////////////////////////////////////////////////////////////////////
125 void IceRawTWR::SetPrintFreq(Int_t f)
126 {
127 // Set the printfrequency to produce info every f events.
128 // f=1 is the default initialisation in the constructor.
129  if (f>=0) fPrintfreq=f;
130 }
131 ///////////////////////////////////////////////////////////////////////////
132 void IceRawTWR::SetSplitLevel(Int_t split)
133 {
134 // Set the split level for the ROOT data file.
135 // split=0 is the default initialisation in the constructor.
136  if (split>=0) fSplit=split;
137 }
138 ///////////////////////////////////////////////////////////////////////////
139 void IceRawTWR::SetBufferSize(Int_t bsize)
140 {
141 // Set the buffer size for the ROOT data file.
142 // bsize=32000 is the default initialisation in the constructor.
143  if (bsize>=0) fBsize=bsize;
144 }
145 ///////////////////////////////////////////////////////////////////////////
146 void IceRawTWR::AddInputFile(TString name)
147 {
148 // Add the name of this TWR raw data input file to the list to be processed.
149
150  if (!fInfiles)
151  {
152   fInfiles=new TObjArray();
153   fInfiles->SetOwner();
154  }
155
156  TObjString* s=new TObjString();
157  s->SetString(name);
158  fInfiles->Add(s);
159 }
160 ///////////////////////////////////////////////////////////////////////////
161 void IceRawTWR::SetOutputFile(TFile* ofile)
162 {
163 // Set the output file for the ROOT data.
164  if (fOutfile) delete fOutfile;
165  fOutfile=ofile;
166 }
167 ///////////////////////////////////////////////////////////////////////////
168 void IceRawTWR::SetOutputFile(TString name)
169 {
170 // Create the output file for the ROOT data.
171  if (fOutfile) delete fOutfile;
172  fOutfile=new TFile(name.Data(),"RECREATE","F2K data in IceEvent structure");
173 }
174 ///////////////////////////////////////////////////////////////////////////
175 TFile* IceRawTWR::GetOutputFile()
176 {
177 // Provide pointer to the ROOT output file.
178  return fOutfile;
179 }
180 ///////////////////////////////////////////////////////////////////////////
181 void IceRawTWR::Exec(Option_t* opt)
182 {
183 // Job to loop over the specified number of events and convert the 
184 // TWR raw data into the IceEvent structure.
185 // If maxevents<0 (default) all the entries of the input file
186 // will be processed.
187 // Every "printfreq" events a short event summary will be printed.
188 // The default value is printfreq=1.
189 // The output will be written on a standard output tree named "T".
190 //
191 // Notes :
192 // -------
193 // 1) This class is derived from AliJob, allowing a task based processing.
194 //    After the conversion of a raw data event into an IceEvent structure,
195 //    the processing of all available sub-tasks (if any) is invoked.
196 //    This provides an event-by-event (sub)task processing before the
197 //    final data structures are written out.
198 // 2) The main object in this job environment is an IceEvent* pointer.
199
200  if (!fInfiles)
201  {
202   cout << " *IceRawTWR Exec* No data input file(s) specified." << endl;
203   return;
204  }
205
206  Int_t ninfiles=fInfiles->GetEntries();
207  if (!ninfiles)
208  {
209   cout << " *IceRawTWR Exec* No data input file(s) specified." << endl;
210   return;
211  }
212
213  TTree* otree=0;
214  if (fOutfile)
215  {
216   otree=new TTree("T","TWR raw data converted to IceEvent structures");
217   otree->SetDirectory(fOutfile);
218  }
219
220  IceEvent* evt=new IceEvent();
221  evt->SetTrackCopy(1);
222  evt->SetDevCopy(1);
223
224  // Branch in the tree for the event structure
225  if (otree) otree->Branch("IceEvent","IceEvent",&evt,fBsize,fSplit); 
226
227  // Initialise the job working environment
228  SetMainObject(evt);
229  if (fOutfile)
230  {
231   AddObject(fOutfile);
232   AddObject(otree);
233  }
234
235  TString inputfile;
236
237  cout << " ***" << endl;
238  cout << " *** Start processing of job " << GetName() << " ***" << endl;
239  cout << " ***" << endl;
240  for (Int_t i=0; i<ninfiles; i++)
241  {
242   TObjString* sx=(TObjString*)fInfiles->At(i);
243   if (!sx) continue;
244   inputfile=sx->GetString(); 
245   cout << " TWR raw data input file : " << inputfile.Data() << endl;
246  }
247  cout << " Maximum number of events to be processed : " << fMaxevt << endl;
248  cout << " Print frequency : " << fPrintfreq << endl;
249  if (fOutfile)
250  {
251   cout << " ROOT output file : " << fOutfile->GetName() << endl;
252   cout << " Output characteristics : splitlevel = " << fSplit << " buffersize = " << fBsize << endl;
253  }
254
255  ListEnvironment();
256
257  // Storage of the used parameters in the IceRawTWR device
258  AliDevice params;
259  params.SetNameTitle("IceRawTWR","IceRawTWR processor parameters");
260  params.SetSlotName("Nchannels",1);
261  params.SetSlotName("Ntriggers",2);
262  params.SetSlotName("BaselineOffset",3);
263  params.SetSignal(float(N_OF_CHANNELS),1);
264  params.SetSignal(float(N_OF_TRIGGERS),2);
265  params.SetSignal(float(BASELINE_MEAN_MAGIC),3);
266
267  // Set DAQ device info
268  AliDevice daq;
269  daq.SetName("Daq");
270  daq.SetSlotName("TWR",1);
271  daq.SetSignal(1,1);
272
273  twr_raw_data_file_t twr_file;
274  Int_t year,runnum,evtnum;
275
276  Int_t error;
277  UInt_t nhead;
278
279  GPS_t gps;
280  UInt_t gpslow,gpshigh,gpssecs; // The GPS time information
281  Int_t seconds,nsecs;           // Seconds and nanoseconds since start of the UT year
282
283  Int_t nevt=0;
284  fHeader=0;
285  for (Int_t ifile=0; ifile<ninfiles; ifile++)
286  {
287   TObjString* sx=(TObjString*)fInfiles->At(ifile);
288   if (!sx) continue;
289
290   inputfile=sx->GetString(); 
291   if (inputfile=="") continue;
292
293   // Open the TWR raw data input file in binary mode
294   fInput=fopen(inputfile.Data(),"rb");
295
296   if (!fInput)
297   {
298    cout << " *IceRawTWR Exec* No input file found with name : " << inputfile.Data() << endl;
299    continue;
300   }
301
302   // Extract info like run number, file number etc... from filename
303   extract_info_from_filename((char*)inputfile.Data(),&twr_file);
304
305   year=twr_file.year;
306   runnum=twr_file.run_no;
307
308   // Initialise the event structure 
309   clear_event(&fEvent);
310
311   // Read the file header information
312   error=read_header_from_file(fInput,&fHeader,&nhead);
313
314   if (error || !nhead) 
315   {
316    cout << " *IceRawTWR Exec* Error in header for input file : " << inputfile.Data() << endl;
317    continue;
318   }
319
320   // Correct the mapping
321   update_system(fHeader,runnum);
322  
323   while (!read_event(fInput,fHeader,&fEvent))
324   {
325    if (fMaxevt>-1 && nevt>=fMaxevt) break;
326
327    evtnum=fEvent.eventcounter;
328
329    // The GPS telegram info
330    gps=fEvent.gps;
331    gpslow=gps.seconds;            // The low 24 bits of the seconds count
332    gpshigh=gps.info.bits.seconds; // The high 8 bits of the seconds count
333    gpssecs=gpshigh<<24;
334    gpssecs+=gpslow;
335
336    // Seconds and nanoseconds since the start of the UT year
337    seconds=gpssecs;
338    nsecs=100*gps.count_10MHz;
339    
340    // Reset the complete Event structure
341    evt->Reset();
342
343    evt->SetRunNumber(runnum);
344    evt->SetEventNumber(evtnum);
345    evt->SetUT(year,0,seconds,nsecs);
346
347    evt->AddDevice(params);
348    evt->AddDevice(daq);
349
350    PutTrigger(year);
351
352    PutWaveforms(year);
353
354    // Invoke all available sub-tasks (if any)
355    CleanTasks();
356    ExecuteTasks(opt);
357
358    if (fPrintfreq)
359    {
360     if (!(nevt%fPrintfreq)) evt->HeaderData();
361    }
362
363    // Write the complete structure to the output Tree
364    if (otree) otree->Fill();
365
366    // Update event counter
367    nevt++;
368
369    // Reset the raw event structure 
370    clear_event(&fEvent);
371   } // End of event reading loop
372
373   // Delete the file header structure
374   clear_system(fHeader);
375
376   if (fMaxevt>-1 && nevt>=fMaxevt) break;
377
378  } // End of input file loop
379
380  // Flush possible memory resident data to the output file
381  if (fOutfile) fOutfile->Write();
382
383  // Remove the IceEvent object from the environment
384  // and delete it as well
385  if (evt)
386  {
387   RemoveObject(evt);
388   delete evt;
389  }
390 }
391 ///////////////////////////////////////////////////////////////////////////
392 void IceRawTWR::PutWaveforms(Int_t year)
393 {
394 // Get the waveform info from the raw data event into the IcePack structure.
395
396  IceEvent* evt=(IceEvent*)GetMainObject();
397  if (!evt) return;
398
399  // Loop over all the waveforms and add the histo(s) to the corresponding OM's
400  TH1F histo;
401  Int_t nbins=0;
402  Float_t xlow=0;
403  Float_t xup=0;
404  TString hname;
405  IceAOM om;
406  IceAOM* omx=0;
407  Int_t omid;
408  Int_t omidmax=680;
409  Int_t error;
410  Float_t baseline;
411  for (Int_t i=0; i<N_OF_CHANNELS; i++)
412  {
413   if (!fEvent.wfm_filled[i]) continue;
414
415   omid=fEvent.twr_id_of_om[i];
416   if (omid<=0 || omid>omidmax) continue; // Skip trigger channels
417
418   // Get corresponding device from the current event structure  
419   omx=(IceAOM*)evt->GetIdDevice(omid);
420   if (!omx)
421   {
422    om.Reset(1);
423    om.SetUniqueID(omid);
424    evt->AddDevice(om);
425    omx=(IceAOM*)evt->GetIdDevice(omid);
426   }
427
428   if (!omx) continue;
429
430   clear_waveform_analysis(&fWform);
431   error=restore_waveform(fEvent.wfm[i],&fWform,year);
432
433   if (error) continue;
434
435   baseline=fWform.frag_mean[0];
436
437   hname="BASELINE-WF";
438   hname+=omx->GetNwaveforms()+1;
439   omx->AddNamedSlot(hname);
440   omx->SetSignal(baseline,hname);
441
442   // Fill the waveform histogram
443   hname="OM";
444   hname+=omid;
445   hname+="-WF";
446   hname+=omx->GetNwaveforms()+1;
447
448   histo.Reset();
449   histo.SetName(hname.Data());
450   nbins=fWform.n_point;
451   xlow=fWform.wfm_x[0];
452   xup=fWform.wfm_x[nbins-1];
453   histo.SetBins(nbins,xlow,xup);
454
455   for (Int_t jbin=1; jbin<=nbins; jbin++)
456   {
457    histo.SetBinContent(jbin,baseline-fWform.wfm_y[jbin-1]);
458   }
459
460   omx->SetWaveform(&histo,omx->GetNwaveforms()+1);
461  }
462 }
463 ///////////////////////////////////////////////////////////////////////////
464 void IceRawTWR::PutTrigger(Int_t year)
465 {
466 // Get the trigger info from the raw data event into the IcePack structure.
467 // Currently only the trigger settings for the years 2005 and 2006 have been
468 // implemented.
469 // In addition to the hardware and software triggers as encountered in the
470 // raw data, an artificial "main" trigger has been introduced.
471 // This artificial "main" trigger is just an "or" of the standard hard and soft
472 // triggers (except calibration and random triggers) and serves only to
473 // provide a generic "main" trigger a la Amanda mu-daq so that the default
474 // "IceCleanHits" hit cleaning procedure will work correctly.
475 // The trigger time for the artificial "main" trigger is taken to be the
476 // time of the earliest hardware trigger pulse. In case there is no hardware
477 // trigger pulse available, the "main" trigger time is set to 0.
478 // For other years, only the artificial "main" trigger with a trigger time
479 // set to 0 will be stored in the IceEvent structure.
480
481  // Fill the trigger structure
482  Int_t error=retrigger(&fEvent,&fTrigger);
483  if (error) return;
484
485  IceEvent* evt=(IceEvent*)GetMainObject();
486  if (!evt) return;
487
488  AliDevice trig;
489  trig.SetNameTitle("Trigger","Amanda/IceCube event triggers");
490  AliSignal s;
491  Float_t trigtime=0;
492
493  if (year !=2005 && year != 2006)
494  {
495   s.SetName("main");
496   s.SetUniqueID(0);
497   s.SetSlotName("trig_pulse_le",1);
498   s.SetSignal(trigtime,1);
499   trig.AddHit(s);
500   // Store the trigger data into the IceEvent structure
501   evt->AddDevice(trig);
502   return;
503  }
504
505  // Trigger settings for 2005 and 2006
506  if (!fTrigger.n_software_trigger && !fTrigger.n_hardware_trigger) return;
507
508  TString trignames[N_OF_TRIGGERS]={"m24","m18","string","spase","cal-t0","cal-la","m12",
509                                    "main-logic","main-or","random","m20-frag","volume"};
510  Int_t imain=0;
511  for (Int_t i=0; i<N_OF_TRIGGERS; i++)
512  {
513   if (!fTrigger.trigger_active[i]) continue;
514
515   s.Reset(1);
516   s.SetName(trignames[i]);
517   s.SetUniqueID(i);
518   trigtime=0;
519   if (fTrigger.trigger_has_pulse[i]) trigtime=fTrigger.trigger_time[i];
520   s.SetSlotName("trig_pulse_le",1);
521   s.SetSignal(trigtime,1);
522   trig.AddHit(s);
523   // Set flag to indicate creation of artificial "main" trigger
524   if (i!=4 && i!=5 && i!=9) imain=1;
525  }
526
527  // Set the artificial "main" trigger
528  if (imain)
529  {
530   s.Reset(1);
531   s.SetName("main");
532   s.SetUniqueID(N_OF_TRIGGERS);
533   s.SetSlotName("trig_pulse_le",1);
534   trigtime=0;
535   if (fTrigger.first_trigger>=0) trigtime=fTrigger.first_trigger_time;
536   s.SetSignal(trigtime,1);
537   trig.AddHit(s);
538  }
539
540  // Store the trigger data into the IceEvent structure
541  evt->AddDevice(trig);
542 }
543 ///////////////////////////////////////////////////////////////////////////
544 Int_t IceRawTWR::extract_info_from_filename(char* fname,twr_raw_data_file_t* twr_file)
545 {
546   char start_str[20],year_str[20],day_str[20],run_no_str[20], 
547        file_no_str[20],begin_str[20],end_str[20];
548   char* filename;
549
550   filename = strstr(fname, "twr");
551   if(filename == NULL)
552   if(strncmp("twr_", start_str, 4)) 
553     {
554       printf("%s\n", filename);
555       return(ERROR_NOT_VALID_FILENAME);
556     }
557
558   strncpy(start_str, filename, 4);
559   if(strncmp("twr_", start_str, 4)) 
560     {
561       printf("%s %s\n", filename, start_str);
562       return(ERROR_NOT_VALID_FILENAME);
563     }
564   strncpy(year_str, &filename[4], 4);
565   twr_file->year = strtol(year_str, 0, 10);
566
567   if(twr_file->year==2003)
568     {
569       strncpy(day_str, &filename[9], 3);
570       day_str[3] = '\0';
571       twr_file->day = strtol(day_str, 0, 10);
572       
573       strncpy(run_no_str, &filename[13], 4);
574       run_no_str[4] = '\0';
575       twr_file->run_no = strtol(run_no_str, 0, 10);
576       
577       strncpy(file_no_str, &filename[18], 4);
578       file_no_str[4] = '\0';
579       twr_file->file_no = strtol(file_no_str, 0, 10);
580     }
581   
582   if(twr_file->year==2004)
583     {
584       strncpy(day_str, &filename[9], 3);
585       day_str[3] = '\0';
586       twr_file->day = strtol(day_str, 0, 10);
587       
588       strncpy(run_no_str, &filename[13], 4);
589       run_no_str[4] = '\0';
590       twr_file->run_no = strtol(run_no_str, 0, 10);
591       
592       strncpy(file_no_str, &filename[18], 4);
593       file_no_str[4] = '\0';
594       twr_file->file_no = strtol(file_no_str, 0, 10);
595       
596       strncpy(begin_str, &filename[23], 5);
597       begin_str[5] = '\0';
598       twr_file->begin = strtol(begin_str, 0, 10);
599       
600       strncpy(end_str, &filename[29], 5);
601       end_str[5] = '\0';
602       twr_file->end = strtol(end_str, 0, 10);
603     }
604
605   if(twr_file->year > 2004)      
606     {
607       strncpy(day_str, &filename[9], 3);
608       day_str[3] = '\0';
609       twr_file->day = strtol(day_str, 0, 10);
610       
611       strncpy(run_no_str, &filename[13], 6);
612       run_no_str[6] = '\0';
613       twr_file->run_no = strtol(run_no_str, 0, 10);
614       
615       strncpy(file_no_str, &filename[20], 4);
616       file_no_str[4] = '\0';
617       twr_file->file_no = strtol(file_no_str, 0, 10);
618       
619       strncpy(begin_str, &filename[25], 5);
620       begin_str[5] = '\0';
621       twr_file->begin = strtol(begin_str, 0, 10);
622       
623       strncpy(end_str, &filename[31], 5);
624       end_str[5] = '\0';
625       twr_file->end = strtol(end_str, 0, 10);
626     }
627   return(0);
628 }
629 ///////////////////////////////////////////////////////////////////////////
630 Int_t IceRawTWR::clear_system(sys_config_t* sys)
631 {
632 // Deletion of the file header structure.
633
634  if (!sys) return 0;
635
636  for(Int_t icrate=0; icrate < int(sys->n_crates); icrate++)
637  {
638   if (!sys->crate[icrate]) continue;
639   for(Int_t itwr=0; itwr < int(sys->crate[icrate]->n_twr); itwr++)
640   {
641    if (sys->crate[icrate]->twr[itwr]) delete sys->crate[icrate]->twr[itwr];
642   }
643   delete sys->crate[icrate];
644  }
645  delete sys;
646  sys=0;
647  return 0;
648 }
649 ///////////////////////////////////////////////////////////////////////////
650 Int_t IceRawTWR::clear_event(event_t* event_ptr)
651 {
652   Int_t i_value;
653   Int_t *int_ptr = (int*) event_ptr;
654
655   for(i_value=0; i_value < int(sizeof(event_t)/sizeof(Int_t)); i_value++)
656     {
657       *int_ptr++ = 0;
658     }
659   return(0);
660 }
661 ///////////////////////////////////////////////////////////////////////////
662 Int_t IceRawTWR::read_header_from_file(FILE* fin,sys_config_t** system_ptr,UInt_t* header_length)
663 {
664   Int_t i_crate, i_twr, i_channel;
665   UInt_t count_twr_in_system = 0;
666   UInt_t dummy;
667   
668   sys_config_t *sys;
669
670   // allocating memory for sys_config structure
671   sys = (sys_config_t*) malloc( sizeof(sys_config_t) );
672
673   fread(&dummy,sizeof(UInt_t),1,fin); // Header Begin Mark
674
675   fread(header_length,sizeof(UInt_t),1,fin);   // Length of header
676   fread(&sys->clockdiv,sizeof(UInt_t),1,fin);  
677   fread(&sys->n_crates,sizeof(UInt_t),1,fin);   
678
679   if( (sys->n_crates > MAX_N_CRATES) || (sys->n_crates < 0) )
680     return(ERROR_TOO_MANY_CRATES);
681
682   for(i_crate=0; i_crate < int(sys->n_crates); i_crate++)
683     {
684       sys->crate[i_crate] = 
685         (crate_config_t*) malloc( sizeof(crate_config_t) );
686
687       fread(&sys->crate[i_crate]->vme_base_bridge,sizeof(UInt_t),1,fin); 
688       fread(&sys->crate[i_crate]->vme_base_100MHz,sizeof(UInt_t),1,fin); 
689       fread(&sys->crate[i_crate]->base_gps,sizeof(UInt_t),1,fin); 
690       fread(&sys->crate[i_crate]->n_twr,sizeof(UInt_t),1,fin); 
691       
692       if( (sys->crate[i_crate]->n_twr > MAX_N_TWR_PER_CRATE) 
693           || (sys->crate[i_crate]->n_twr < 0) )
694         return(ERROR_TOO_MANY_TWRS);
695
696       for(i_twr=0; i_twr < int(sys->crate[i_crate]->n_twr); i_twr++)
697         {
698           sys->crate[i_crate]->twr[i_twr] = 
699             (twr_config_t*) malloc( sizeof(twr_config_t) );
700           count_twr_in_system++;
701           fread(&sys->crate[i_crate]->twr[i_twr]->base, 
702                sizeof(UInt_t),1,fin);
703           fread(&sys->crate[i_crate]->twr[i_twr]->id, 
704                sizeof(UInt_t),1,fin);
705
706           sys->crate[i_crate]->twr[i_twr]->id 
707             = sys->crate[i_crate]->twr[i_twr]->id - 0x10; /* Correct */
708
709
710           fread(&dummy,sizeof(UInt_t),1,fin); /* stat_reg */
711           fread(&sys->crate[i_crate]->twr[i_twr]->mod_id, 
712                sizeof(UInt_t),1,fin);
713           fread(&dummy,sizeof(UInt_t),1,fin); /* acq_ctrl */
714           fread(&sys->crate[i_crate]->twr[i_twr]->ext_start, 
715                sizeof(UInt_t),1,fin);
716           fread(&sys->crate[i_crate]->twr[i_twr]->ext_stop, 
717                sizeof(UInt_t),1,fin);
718           fread(&dummy,sizeof(UInt_t),1,fin); /* evtconfig */
719
720           for(i_channel = 0; i_channel < CHANNELS_PER_TWR; i_channel++)
721             {
722               fread(&sys->crate[i_crate]->twr[i_twr]->om_no[i_channel], 
723                    sizeof(UInt_t),1,fin);
724             }
725
726           for(i_channel = 0; i_channel < CHANNELS_PER_TWR; i_channel++)
727             {
728               fread(&sys->crate[i_crate]->twr[i_twr]->om_is_optical[i_channel], 
729                    sizeof(UInt_t),1,fin);
730             }
731
732           for(i_channel = 0; i_channel < CHANNELS_PER_TWR; i_channel++)
733             {
734               fread(&sys->crate[i_crate]->twr[i_twr]->baseline[i_channel], 
735                    sizeof(UInt_t),1,fin);
736             }
737
738           for(i_channel = 0; i_channel < CHANNELS_PER_TWR; i_channel++)
739             {
740               fread(&sys->crate[i_crate]->twr[i_twr]->threshold[i_channel],
741                    sizeof(UInt_t),1,fin);
742             }
743
744           sys->twr_field[(i_crate * 0x10) + i_twr]
745               = sys->crate[i_crate]->twr[i_twr];
746           
747           /* Bug fix needed */
748           for(i_channel=0; i_channel < 8; i_channel++)
749           {
750              if( sys->crate[i_crate]->twr[i_twr]->om_no[i_channel] == 9000 )
751                  sys->crate[i_crate]->twr[i_twr]->om_no[i_channel] 
752                    = N_OF_CHANNELS - 1; 
753           }
754         }
755     }
756
757   // Set number of TWRs in system
758   sys->n_twr = count_twr_in_system;
759
760   *system_ptr = sys;
761   return(0);
762 }
763 ///////////////////////////////////////////////////////////////////////////
764 Int_t IceRawTWR::update_system(sys_config_t* sys,Int_t run_number)
765 {
766   Int_t i_crate, i_twr, i_channel;
767
768   /* Data for bug fix 1 */
769   UInt_t om_no_r1[CHANNELS_PER_TWR] 
770     = {111, 112, 113, 114, 115, 116, 39, 118}; 
771   UInt_t om_is_optical_r1[CHANNELS_PER_TWR] 
772      = {0, 0, 0, 0, 0, 0, 0, 0};
773   UInt_t threshold_r1[CHANNELS_PER_TWR]
774     = {50, 50, 50, 50, 50, 50, 80, 50};
775
776   UInt_t om_no_r2[CHANNELS_PER_TWR] 
777     = {473, 484, 485, 486, 487, 475, 490, 491}; 
778   UInt_t om_is_optical_r2[CHANNELS_PER_TWR] 
779      = {1, 1, 1, 1, 1, 1, 1, 1};
780   UInt_t threshold_r2[CHANNELS_PER_TWR]
781     = {15, 50, 55, 40, 15, 23, 15, 15};
782
783   
784   /* Bugfix 1 Andreas Bug */ 
785
786   /*
787     By accident this TWR was counted twice in TWR.cnf
788     as Crate 0 TWR 7 and Crate 4 TWR 7
789     from run up to run
790     TWR_OM          639     642     1       9       10      11      12      30
791     OPTICAL         0       0       0       0       0       0       0       0
792     TWR_BASELINE    110     120     110     140     150     160     170     180
793     TWR_THRESHOLD   50      50      80      80      80      80      80      80
794
795     Crate 4 TWR 7 should be replaced with this TWR
796     TWR_OM          111     112     113     114     115     116     39      118
797     OPTICAL         0       0       0       0       0       0       0       0
798     TWR_BASELINE    110     120     130     140     150     160     170     180
799     TWR_THRESHOLD   50      50      50      50      50      50      80      50
800   */
801
802   if( 
803      (run_number >= 9153 )  /* Begin season 2005 13.2.05 */  
804      && (run_number < 9800) /* Timo corrected TWR.cnf on after run ??? */
805      /* Need to find exact date */
806      )
807     {
808       i_crate = 4;
809       i_twr = 7;
810       for(i_channel = 0; i_channel < CHANNELS_PER_TWR; i_channel++)
811         {
812           sys->crate[i_crate]->twr[i_twr]->om_no[i_channel]         
813             = om_no_r1[i_channel]; 
814           sys->crate[i_crate]->twr[i_twr]->om_is_optical[i_channel] 
815             = om_is_optical_r1[i_channel]; 
816           sys->crate[i_crate]->twr[i_twr]->threshold[i_channel]     
817             = threshold_r1[i_channel];
818         }
819     }
820
821   /* Bugfix 2 Timos Bug */ 
822
823   /*
824     By accident this TWR was counted twice in TWR.cnf
825     as Crate 0 TWR 1 and Crate 5 TWR b
826     from run 9153 up to run 9188
827
828     TWR_OM          492     493     495     496     497     499     500     501
829     OPTICAL         1       1       1       1       1       1       1       1
830     TWR_BASELINE    110     120     130     140     150     160     170     180
831     TWR_THRESHOLD   16      45      25      42      35      46      15      15
832
833     Crate 5 TWR b should be corrected to 
834     TWR_OM          473     484     485     486     487     475     490     491
835     OPTICAL         1       1       1       1       1       1       1       1
836     TWR_BASELINE    4000    120     130     140     150     4000    170     180
837     TWR_THRESHOLD   15      50      55      40      15      23      15      15
838   */
839
840   if( 
841      (run_number >= 9153 )  /* Begin season 2005 = Feb 2nd 05 */  
842      && (run_number < 9189) /* Timo corrected TWR.cnf on      */
843      /* Mar 15th 05 = day 74 after run 9188                   */
844      )
845     {
846       i_crate = 5;
847       i_twr = 0xb;
848       for(i_channel = 0; i_channel < CHANNELS_PER_TWR; i_channel++)
849         {
850           sys->crate[i_crate]->twr[i_twr]->om_no[i_channel]         
851             = om_no_r2[i_channel]; 
852           sys->crate[i_crate]->twr[i_twr]->om_is_optical[i_channel] = 
853             om_is_optical_r2[i_channel]; 
854           sys->crate[i_crate]->twr[i_twr]->threshold[i_channel]     = 
855             threshold_r2[i_channel];
856         }
857     }
858  return(0);
859 }
860 ///////////////////////////////////////////////////////////////////////////
861 Int_t IceRawTWR::read_event(FILE* fin,sys_config_t* sys,event_t* event_ptr)
862 {
863     Int_t i_wfm;
864     UInt_t length_of_event_block;
865     
866     Int_t n_twr, n_of_waveforms_in_event, read_number;
867     UInt_t length_wfm[CHANNELS_PER_TWR];
868     UInt_t dummy, channel_no, om_no, twr_no;
869     
870     // Reset waveform filled register
871     memset(&event_ptr->wfm_filled[0], 0, sizeof(UInt_t) * N_OF_CHANNELS);
872
873     if( !fread(&dummy,sizeof(UInt_t),1,fin) ) return(1);
874
875     if(dummy != 0xbbbbbbbb) 
876     {
877         printf("Wrong event begin mark %x\n", dummy); 
878         while( (dummy !=0xbbbbbbbb) 
879                && (fread(&dummy,sizeof(UInt_t),1,fin) != 0) )
880           {;//printf("dummy:%x\n", dummy);
881           }
882     }
883     if( !fread(&length_of_event_block,sizeof(UInt_t),1,fin) ) return(1);
884     if( !fread(&event_ptr->eventcounter,sizeof(UInt_t),1,fin) ) return(1);
885     if( !fread(&event_ptr->which_trigger,sizeof(UInt_t),1,fin) ) return(1);
886     if( !fread(&event_ptr->gps,sizeof(GPS_t),1,fin) ) return(1);
887         
888     // --reading waveforms from TWR blocks
889     n_twr = 0;
890     while(n_twr < int(sys->n_twr))
891     {
892         // --read TWR header
893         if( !fread(&dummy,sizeof(UInt_t),1,fin) ) return(1);
894         if(dummy != 0xffffffff) 
895         {printf("Wrong twr begin mark %x\n", dummy); return(2);}
896         if( !fread(&twr_no,sizeof(UInt_t),1,fin) ) return(1);
897
898         // nur voruebergehend !!
899         twr_no -= 0x10;
900
901         if( !fread(&event_ptr->twr[twr_no].timestamp,sizeof(UInt_t),1,fin) ) 
902             return(1);
903         if( !fread(&n_of_waveforms_in_event,sizeof(UInt_t),1,fin) ) 
904             return(1);
905         event_ptr->twr[twr_no].n_wfm = n_of_waveforms_in_event;
906
907         for(i_wfm=0; i_wfm < n_of_waveforms_in_event; i_wfm++)
908         {
909             if( !fread(&length_wfm[i_wfm],sizeof(UInt_t),1,fin) ) return(1);
910         }
911             
912         // read waveforms
913         for(i_wfm=0; i_wfm < n_of_waveforms_in_event; i_wfm++)
914         {
915             if(length_wfm[i_wfm] != 0)
916             {
917               if( !fread(&channel_no,sizeof(UInt_t),1,fin) ) return(1);
918               if(sys->twr_field[twr_no]->om_no[channel_no] 
919                    < N_OF_CHANNELS)
920                     om_no = sys->twr_field[twr_no]->om_no[channel_no];
921                 else
922                     om_no = N_OF_CHANNELS-1;
923
924                 /* Fix needed */
925
926                 event_ptr->twr_id_of_om[om_no] = twr_no;
927
928                 read_number = fread(&event_ptr->wfm[om_no], 
929                                    length_wfm[i_wfm]-sizeof(UInt_t),1,fin);
930                 event_ptr->wfm_filled[om_no] = 1;
931                 if( !read_number ) return(1);
932
933                 // read_number correction for usage of fread() instead of read()
934                 read_number*=length_wfm[i_wfm]-sizeof(UInt_t);
935
936                 if( read_number != int(length_wfm[i_wfm]-sizeof(UInt_t)) ) 
937                 {
938                   cout << " read_number : " << read_number
939                        << " length_wfm["<<i_wfm<<"] : " << length_wfm[i_wfm]
940                        << " sizeof(UInt_t) : " << sizeof(UInt_t) << endl;
941                   return(2);
942                 }
943             }   
944         }
945         n_twr++;
946     } // end while n_twr
947     return(0);
948 }
949 ///////////////////////////////////////////////////////////////////////////
950 Int_t IceRawTWR::retrigger(event_t* ev,trigger_hits_t* trig)
951 {
952 // Returns the active trigger(s)
953
954  // Initialise the trigger_hits_t structure with zeroes
955  memset(trig, 0, sizeof(trigger_hits_t) );
956
957  // Obtain the software trigger info
958  trig->n_software_trigger=0;
959  for(Int_t itrigger=0; itrigger<N_OF_TRIGGERS; itrigger++)
960  {
961   if(ev->which_trigger & trigger_bits[itrigger])
962   {
963    //printf("SetTrigger %i\n", i_trigger);
964    trig->trigger_active[itrigger]=1;
965    trig->n_software_trigger++;
966   } 
967   else
968   {
969    trig->trigger_active[itrigger]=0;
970   }
971  }
972
973  // Obtain the hardware trigger info
974  trig->n_hardware_trigger=0;
975  trig->first_trigger_time=10000000;
976  trig->first_trigger=-1;
977
978  for(Int_t jtrigger=0; jtrigger<N_OF_TRIGGERS; jtrigger++)
979  {
980   if(!trigger_channel[jtrigger]) continue;
981
982   if(ev->wfm_filled[trigger_channel[jtrigger]])
983   {
984    trig->trigger_active[jtrigger]=1;
985    trig->trigger_time[jtrigger]=(ev->wfm[trigger_channel[jtrigger]].value[2] & 0xfff);
986    trig->trigger_has_pulse[jtrigger]=1;
987    if (trig->trigger_time[jtrigger] < trig->first_trigger_time)
988    {
989     trig->first_trigger_time=trig->trigger_time[jtrigger];
990     trig->first_trigger=jtrigger;
991    }
992    trig->n_hardware_trigger++;
993   }
994  }
995  return 0;
996 }
997 ///////////////////////////////////////////////////////////////////////////
998 Int_t IceRawTWR::clear_waveform_analysis(waveform_analyse_t* wfm_om)
999 {
1000   Int_t i_value, i_frag, i_edge, i_peak;
1001
1002   if(wfm_om == 0) return(1);
1003
1004   // output from analysis
1005   wfm_om->n_frag = 0;
1006   for(i_frag=0; i_frag < MAX_N_OF_FRAGS; i_frag++)
1007     {
1008       wfm_om->frag_n_points[i_frag] = 0;
1009       wfm_om->frag_begin[i_frag] = 0;
1010       wfm_om->frag_end[i_frag] = 0;
1011       wfm_om->frag_mean[i_frag] = 0;
1012       wfm_om->frag_begin_time[i_frag] = 0;
1013     }
1014   
1015   wfm_om->n_peak = 0;
1016   for(i_peak=0; i_peak < MAX_N_OF_PEAKS; i_peak++)
1017     {
1018       wfm_om->peak_begin[i_peak] = 0;
1019       wfm_om->peak_end[i_peak] = 0;
1020       wfm_om->peak_max[i_peak] = 0;
1021       wfm_om->peak_TDC_edge[i_peak] = 0;
1022       wfm_om->peak_local_minimum[i_peak] = 0;
1023       wfm_om->crosstalk_charge_n_value[i_peak] = 0;
1024       wfm_om->peak_in_fragment[i_peak] = 0;
1025        
1026       wfm_om->peak_mean[i_peak] = 0.0;
1027     
1028       wfm_om->peak_m[i_peak] = 0.0;
1029       wfm_om->peak_b[i_peak] = 0.0;
1030       wfm_om->peak_t0[i_peak] = 0.0;
1031       wfm_om->peak_begin_time[i_peak] = 0.0; 
1032       wfm_om->peak_charge[i_peak] = 0.0;
1033       wfm_om->peak_height[i_peak] = 0.0;
1034       wfm_om->fitted_amplitude[i_peak] = 0.0;
1035       wfm_om->fitted_TOT[i_peak] = 0.0;
1036       wfm_om->crosstalk_charge[i_peak] = 0.0;
1037       wfm_om->crosstalk_slope[i_peak] = 0.0;
1038     }
1039   
1040   wfm_om->n_point = 0;
1041   wfm_om->wfm_min = 4095; 
1042   wfm_om->wfm_max = 0; 
1043   wfm_om->b_out_of_range = 0;
1044   
1045   for(i_value=0; i_value < 1024; i_value++)
1046     {
1047       wfm_om->wfm_x[i_value] = 0;
1048       wfm_om->wfm_y[i_value] = 0;
1049     }
1050
1051   wfm_om->n_tdc_edges = 0;
1052   for(i_edge=0; i_edge < MAX_N_OF_TDC_EDGES; i_edge++)
1053     {
1054       wfm_om->leading_edge[i_edge] = 0.0;
1055       wfm_om->falling_edge[i_edge] = 0.0;
1056       wfm_om->identified_twr_hit[i_edge] = -1;
1057     }
1058
1059  return(0);
1060 }
1061 ///////////////////////////////////////////////////////////////////////////
1062 Int_t IceRawTWR::restore_waveform(waveform_t f_wfm,waveform_analyse_t* wfm_om,Int_t year)
1063 {
1064     UShort_t wfm_length, mean;
1065     static UShort_t tmp_wf[2000];
1066
1067     Int_t debug = 0;
1068     Int_t fragment_start = 0; 
1069     Int_t frag_count = 0;     // position in current fragment
1070     Int_t n_position = 0;     // position in displayed waveform
1071     UInt_t  n_word = 2;      // position in featured waveform
1072     Int_t n_fragment = 0;     // actual fragment 
1073     Int_t b_wrong_value = 0;
1074
1075     UShort_t assumed_frag_begin, last_value; /* bug in eventbuilder */
1076
1077     wfm_om->wfm_min = 4095.0;
1078     wfm_om->wfm_max = 0.0;
1079
1080     if( (f_wfm.value[0] & 0xf000) != 0xf000 ) return(1);
1081     wfm_length = (f_wfm.value[0] & 0xfff)/2;
1082
1083     mean = f_wfm.value[1] + BASELINE_MEAN_MAGIC;    
1084     while( ((f_wfm.value[n_word] & 0xf000) == 0x4000) && 
1085            (n_word < wfm_length) &&
1086            (n_fragment < MAX_N_OF_FRAGS) )
1087     {
1088       fragment_start = f_wfm.value[n_word] & 0xfff;
1089       n_word++;
1090       wfm_om->frag_begin_time[n_fragment] 
1091         = fragment_start * NSECS_PER_TWR_BIN;
1092       wfm_om->frag_begin[n_fragment] = n_position;
1093       wfm_om->frag_mean[n_fragment] = mean;
1094       
1095       b_wrong_value = 0;
1096       frag_count = 0;
1097       
1098       while( ((f_wfm.value[n_word] & 0xf000) != 0x2000) &&
1099              ((f_wfm.value[n_word] & 0xf000) != 0x4000) &&/*Reconstructable*/
1100              !b_wrong_value && /* Buggy */
1101              (n_word < wfm_length) )
1102         {
1103           if(year > 2004)
1104             {
1105               /* 2005 2006 data */
1106               if(frag_count == 0)
1107                 {
1108                   tmp_wf[n_word] = f_wfm.value[n_word] + mean;
1109                   wfm_om->wfm_y[n_position] = (float) tmp_wf[n_word];
1110                   wfm_om->wfm_x[n_position] = (float) 
1111                     wfm_om->frag_begin_time[n_fragment]
1112                     + (frag_count * NSECS_PER_TWR_BIN);
1113                 }
1114               else if(frag_count == 1)
1115                 {
1116                   tmp_wf[n_word] = f_wfm.value[n_word] + tmp_wf[n_word-1];
1117                   wfm_om->wfm_y[n_position] = (float) tmp_wf[n_word];
1118                   wfm_om->wfm_x[n_position] = (float) 
1119                     wfm_om->frag_begin_time[n_fragment]
1120                     + (frag_count * NSECS_PER_TWR_BIN);
1121                 }
1122               else 
1123                 {
1124                   tmp_wf[n_word] = 
1125                     2*tmp_wf[n_word-1] + f_wfm.value[n_word];
1126                   tmp_wf[n_word] -= tmp_wf[n_word-2];
1127                   
1128                   wfm_om->wfm_y[n_position] = (float) tmp_wf[n_word];
1129                   wfm_om->wfm_x[n_position] = (float) 
1130                     wfm_om->frag_begin_time[n_fragment]
1131                     + (frag_count * NSECS_PER_TWR_BIN);
1132                 }
1133               
1134               
1135               /*
1136                 Hack for wrongly merged overlapping fragments
1137               */
1138               if(tmp_wf[n_word] > 0x1fff)
1139                 {
1140                   /* BUG FIXXXX                                         */
1141                   /* assume that fragment merge in eventbuilder caused  */
1142                   /* problem two fragments overlap in EXACTLY ONE point */
1143                   /* and are merged first point of the added part of    */
1144                   /* the fragment is encoded using the former fragment  */
1145                   /* start as a data point                              */
1146                   
1147                   last_value         = tmp_wf[n_word-1];
1148                   assumed_frag_begin = 0x4000 + fragment_start + frag_count;
1149                   tmp_wf[n_word] =  f_wfm.value[n_word] + 2 * last_value;
1150                   tmp_wf[n_word] -= assumed_frag_begin;
1151                   wfm_om->wfm_y[n_position] = (float) tmp_wf[n_word];
1152                   
1153                   /* Look if value is still buggy */
1154                   if(tmp_wf[n_word] > 0x1fff) b_wrong_value = 1;
1155                   
1156                   debug = ERROR_MISS_FRAG_STOP;
1157                 }
1158             } /* end year >= 2005 */
1159           else
1160             {
1161               /* 2003 2004 data */
1162               wfm_om->wfm_y[n_position] = (float) f_wfm.value[n_word];
1163               wfm_om->wfm_x[n_position] = (float) 
1164                 wfm_om->frag_begin_time[n_fragment]
1165                 + (frag_count * NSECS_PER_TWR_BIN);
1166             } /* end year 2003 2004 */
1167           
1168           /* Set min and max Y */
1169           
1170           if(wfm_om->wfm_y[n_position] > wfm_om->wfm_max)
1171             wfm_om->wfm_max = wfm_om->wfm_y[n_position];
1172           if(wfm_om->wfm_y[n_position] < wfm_om->wfm_min)
1173             wfm_om->wfm_min = wfm_om->wfm_y[n_position];
1174           
1175           n_position++;
1176           n_word++;
1177           frag_count++;
1178         }
1179
1180         if((f_wfm.value[n_word] & 0xf000) == 0x2000) /* Normal wavf */
1181           {
1182
1183             wfm_om->frag_end[n_fragment] = n_position - 1; 
1184             wfm_om->frag_n_points[n_fragment] = 
1185               wfm_om->frag_end[n_fragment] 
1186               - wfm_om->frag_begin[n_fragment] + 1;
1187             wfm_om->n_point += wfm_om->frag_n_points[n_fragment];
1188             n_word++;
1189           }
1190         else 
1191           return(ERROR_CORRUPTED_WF);
1192
1193         n_fragment++;
1194     } /* end while fragment */
1195
1196
1197     wfm_om->n_frag = n_fragment;
1198     if( !(n_word & 0x1) ) n_word++;
1199
1200     if(n_fragment >= MAX_N_OF_FRAGS) return(ERROR_MAX_N_FRAGMENTS_EXCEEDED);
1201     
1202
1203     // Hack to get rid of last value of waveform always set to 0
1204     if (wfm_om->wfm_y[wfm_om->n_point] == 0.0)
1205     {
1206      // erase last point of waveform
1207      wfm_om->n_point--;
1208
1209      // Shorten last pulse if necessary
1210      // if( wfm_om.peak_end[wfm_om.n_peak-1] 
1211      //     == wfm_om.frag_end[wfm_om.n_frag-1] )
1212      //   wfm_om.peak_end[wfm_om.n_peak-1]--;
1213                   
1214      // Shorten last fragment
1215      wfm_om->frag_n_points[wfm_om->n_frag-1]--;
1216      wfm_om->frag_end[wfm_om->n_frag-1]--;
1217
1218      wfm_om->wfm_min = 4095.0;
1219      wfm_om->wfm_max = 0.0;
1220      for (Int_t i_value=0; i_value < wfm_om->n_point; i_value++)
1221      {
1222       if (wfm_om->wfm_y[i_value] > wfm_om->wfm_max) wfm_om->wfm_max=wfm_om->wfm_y[i_value];
1223       if (wfm_om->wfm_y[i_value] < wfm_om->wfm_min) wfm_om->wfm_min=wfm_om->wfm_y[i_value];
1224      }
1225     }
1226
1227  return(debug);
1228 }
1229 ///////////////////////////////////////////////////////////////////////////