PSAFilter.cpp 26.6 KB
Newer Older
dino's avatar
dino committed
1
/* PSA-actor base class, J. Ljungvall 2008,
2 3 4 5 6 7 8
 * based on implementation by Olivier Stezowski
 * 
 * Modified and maintained by
 *   D.Mengoni
 *   D.Bazzacco
 *   F.Recchia
 */
dino's avatar
dino committed
9

dino's avatar
 
dino committed
10
#include "PSAFilter.h"
dino's avatar
dino committed
11 12 13 14 15 16 17 18 19
#include "AgataKeyFactory.h"
#include "AgataFrameFactory.h"

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cmath>

20 21
#include "adetParams.h"

dino's avatar
dino committed
22 23
#include "misc.h"

24 25
std::string PSAFilter::gMotherClass = "PSAFilter";
std::string PSAFilter::gActualClass;
26

dino's avatar
dino committed
27
using namespace std;
dino's avatar
 
dino committed
28
using namespace ADF;
dino's avatar
dino committed
29 30 31 32 33 34

const int preTrigger = 10;

PSAFilter::PSAFilter() :
  fFrameCrystal(NULL),
  fFramePSA(NULL),
dino's avatar
dino committed
35
  fTrigger("data:ccrystal")
36
{
dino's avatar
 
dino committed
37
  fOdirPrefix.clear();
38 39

  fBasisFile.clear();
40
  fPsaXtalkFile.clear();
41
  fTraceLengthPSA = defTraceLengthPSA;
42
  fWriteNumTraces = 0;
43 44
  fCoreEnerMin    = 10.f;
  fCoreEnerMax    = 50000.f;
45 46 47
  fPsaMinSegMult  = 1;
  fPsaMaxSegMult  = CrystalInterface::kNbSegments;
  fVerbose        = false;
48
  fWritePsaHits   = false;
49
  fEnergyGain     = 1.f;
50 51 52 53
  fDeadSegment    = -1;       // no one

  memset(fTauSlice, 0, sizeof(fTauSlice));
  fTauGiven = false;
54

55
  theSlots = NULL;
56 57 58
#ifdef PSA_THREADED
  fPsaCount  = TCOUNT;
  fPsaModulo = TMODULO;
59
  theBlocks  = NULL;
60
  fPsaSlots  = fPsaCount*fPsaModulo;
61
#else
62
  fPsaCount  = 0;
63
  fPsaModulo = 1;
64
  fPsaSlots  = 1;
65 66
#endif

67
  fUseAdaptive  = true;
68
  fTryTwoHits   = false;
69 70 71
  fCoarseOnly   = false;
  fPsaSegCenter = false;
  fFullSearch   = false;
72
  fFitTZero     = true;
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
  fDistMetric   = -1;  // unititialized !!

  fUseMultiHist = true;
  fPsaMatrXYZR  = false;

  //fBlockIn.SetModeIO(ConfAgent::kRead);
  //fBlockOut.SetModeIO(ConfAgent::kWrite);

// not used since very long time
#ifdef PSA_FromGRU
  PSAxy_Proje = new TH2F("PSAxy_Proje","PSAxy_Proje",128,-50,50,128,-50,50);
  PSAxz_Proje = new TH2F("PSAxz_Proje","PSAxz_Proje",128,-50,50,128,0,100);
  PSAyz_Proje = new TH2F("PSAyz_Proje","PSAyz_Proje",128,-50,50,128,0,100);

  PSASpectraDB   = new GSpectra();
  PSANetworkRoot = new GNetServerRoot (PSASpectraDB);

  // GRU-v8
  Int_t port = 9094;
  PSANetworkRoot->SetPort(port);
  PSASpectraDB->SetfDefaultHostPort(port);
  PSASpectraDB->SetfDefaultHostName((char*)gSystem->HostName());

  PSASpectraDB->AddSpectrum (PSAxy_Proje);
  PSASpectraDB->AddSpectrum (PSAxz_Proje);
  PSASpectraDB->AddSpectrum (PSAyz_Proje);
  PSANetworkRoot->StartGNetServer(false); //UNCOMMENT HERE TO START THE GRU SERVER
#endif  // PSA_FromGRU
101

dino's avatar
dino committed
102 103 104 105
}

PSAFilter::~PSAFilter() 
{  
106
  for(Int_t slot = 0; slot < fPsaSlots; slot++) {
107
    theSlots[slot].Destroy();
dino's avatar
dino committed
108
  }
109 110 111 112 113
#ifdef PSA_FromGRU    
  delete PSAxy_Proje;
  delete PSAxz_Proje;
  delete PSAyz_Proje;
#endif 
dino's avatar
dino committed
114 115 116 117
} 

void PSAFilter::process_config(const Char_t *directory_path, UInt_t *error_code)
{
dino's avatar
 
dino committed
118
  *error_code = 0;
119
  cout << gMotherClass + "::process_config() called with directory_path = " << directory_path << endl;
dino's avatar
 
dino committed
120

dino's avatar
dino committed
121 122 123 124 125
  // first init narval stuff
  NarvalInterface::process_config(directory_path, error_code);
  if( *error_code )
    return;

126 127
  // Get name of daughter class from from configuration directory_path/gMotherClass.conf 
  int rv = getKeyFromFile(GetGlobalConfPath() + gMotherClass + ".conf", "ActualClass", gActualClass);
128
  if(rv == 2)
dino's avatar
 
dino committed
129
    *error_code = 102; // Fatal error because the configuration file MUST be present
130 131 132 133 134
}

void PSAFilter::process_initialise (UInt_t *error_code)
{
  Log.ClearMessage();
135 136
  Log.GetProcessName() = gMotherClass; 
  Log.SetProcessMethod("process_initialise");
137 138
  Log.SetPID(GetPID());

dino's avatar
dino committed
139
  GetParameters(error_code);
140 141
  if(*error_code) {
    Log << dolog;
142
    return;
143
  }
144 145 146 147 148 149 150

  // to get the input/output frames
  if( fFrameCrystal ) {
    delete fFrameCrystal;
    fFrameCrystal = NULL;
  }

151
  UInt_t rerr = 0;
152
  cout << endl;
153

154
  UInt_t defaultLength = ADF::CrystalInterface::kDefaultLength;
155
  ADF::CrystalInterface::kDefaultLength = fTraceLengthPSA;  // set "default" lenght of traces to 60//80
156

157 158 159 160
  fFrameCrystal = fTrigger.Add("Agata", "data:ccrystal");   // discard input data
  if( fFrameCrystal ) {
    // link named items with local variables.
    GObject *glob = GetDataPointer<CrystalInterface>(fFrameCrystal)->Global();
dino's avatar
 
dino committed
161 162
    glob->LinkItem("CrystalID",     &crystal_id); 
    glob->LinkItem("CrystalStatus", &crystal_status); 
163
  }
164 165 166
  else
    rerr |= 8;

167
  ADF::CrystalInterface::kDefaultLength = defaultLength;  // restore "default" length of traces
168

169 170 171 172
  fFramePSA = fTrigger.SetOutputFrame("Agata", "data:psa");
  if(fFramePSA) {
    // link named items with local variables.
    GObject *glob = GetDataPointer<PSAInterface>(fFramePSA)->Global();
dino's avatar
 
dino committed
173 174 175 176 177 178
    glob->LinkItem("CrystalID",     &crystal_id); 
    glob->LinkItem("CrystalStatus", &crystal_status); 
    glob->LinkItem("CoreE0",        &CoreE0); 
    glob->LinkItem("CoreE1",        &CoreE1);
    glob->LinkItem("CoreT0",        &CoreT0);
    glob->LinkItem("CoreT1",        &CoreT1);
dino's avatar
 
dino committed
179
    //glob->Link<Anonymous>("Anonymous", &myAno);
180 181
    //bool bb = glob->IsFullyLinked();
  }
182 183
  else
    rerr |= 4;
184 185

  // the trigger is registered
186 187 188 189 190 191
  if( !fFrameIO.Register(&fTrigger) )
    rerr |= 1;
  
  if(rerr) {
    cout << "Trigger definition error " << rerr << " in PSAFilter::process_initialise()" << endl;
    *error_code = 100 + rerr;
192
    Log << dolog;
193 194 195
    return;
  }

196
  // state set to kIdle so that the data can be treated 
197 198
  fFrameIO.SetStatus(BaseFrameIO::kIdle);

199
  // generate the interface to the grid search algorithm 
200
  if(fPsaCount  < 1 || fPsaModulo < 1 || fPsaSegCenter) {
201 202 203 204 205 206 207 208
    fPsaCount  = 0;
    fPsaModulo = 1;
    fPsaSlots  = 1;
  }
  else {
    fPsaSlots = fPsaCount*fPsaModulo;
  }

209
  theSlots = new PsaSlot[fPsaSlots];
210

211
  for(Int_t slot = 0; slot < fPsaSlots; slot++) {
212
    theSlots[slot].InitInput(fTraceLengthPSA);
213 214 215 216 217
  }

  // version-specific initializations
  *error_code = AlgoSpecificInitialise();

218
  cServer.SetCommandFile(GetConfPath() + gMotherClass + ".live");
219
#ifdef PSA_MULTIHIST
220
  cServer.SetHistGroup(&hGroup);
221
#endif  //PSA_MULTIHIST
222 223

  cServer.Start(gMotherClass);
224

225
#ifdef PSA_THREADED
226 227 228
  if(fPsaCount > 0) {
    // launch the threads of the local chains
    cout << "Grid Search performed using " << fPsaCount << " THREADS with blocks of " << fPsaModulo << " EVENTS" << endl; 
229
    theBlocks = new PsaBlock[fPsaCount];
230
    for(Int_t slot = 0; slot < fPsaCount ; slot++) {
231 232 233 234 235
      theBlocks[slot].State  = 0;                // start in the non-running state
      theBlocks[slot].First  = slot*fPsaModulo;  // the first slot of this thread
      theBlocks[slot].Count  = 0;                // empty
      theBlocks[slot].Thread = new boost::thread(PsaThread(this, slot));
      cout << "   LAUNCHED THREAD PsaThread [" << slot << "] " << theBlocks[slot].Thread << endl;
236 237
    }
  }
238
#endif
239
  Log << dolog;
240 241
}

dino's avatar
dino committed
242
void PSAFilter::GetParameters(UInt_t *error_code)
243
{
dino's avatar
 
dino committed
244 245
  *error_code = 0;

246
  string configFileName = GetConfPath() + gMotherClass + ".conf";
dino's avatar
 
dino committed
247
  ifstream configfile( configFileName.c_str() );
dino's avatar
dino committed
248
  if(!configfile.good()) {
249
    cout << endl << "Error opening " << configFileName << endl;
dino's avatar
dino committed
250 251 252
    *error_code = 102;
    return;
  }
dino's avatar
dino committed
253
  cout << endl << gMotherClass + "::GetParameters() reading from --> " << configFileName << endl;
dino's avatar
dino committed
254 255 256 257 258 259 260 261 262

  string line, keyw, data;
  bool ok = true;
  while(getline(configfile, line)) {
    if(!stringSplit(line, " \t", keyw, data))
      continue;       // empty or comment lines

    cout << line;
    ok = false;
263
    if( stringEq(keyw, "ActualClass") ) {
dino's avatar
dino committed
264
      ok = data.size() > 0;
265
      gActualClass = data;
dino's avatar
dino committed
266
    }
267
    else if( stringEq(keyw, "SaveDataDir") || stringEq(keyw, "WriteDataDir") || stringEq(keyw, "WriteDataPrefix") ) {
dino's avatar
dino committed
268 269
      ok = data.size() > 0;
      fOdirPrefix = data;
dino's avatar
 
dino committed
270
      forceTailSlash(fOdirPrefix);
dino's avatar
dino committed
271
    }
272
    else if( stringEq(keyw, "BasisFile") ) {
dino's avatar
dino committed
273 274 275
      ok = data.size() > 0;
      fBasisFile = data;
    }
276 277 278 279
    else if( stringEq(keyw, "XtalkFile") ) {
      ok = data.size() > 0;
      fPsaXtalkFile = data;
    }
280 281 282 283 284 285 286 287
    else if( stringEq(keyw, "NoMultiHist") || stringEq(keyw, "NoLocalSpectra") ) {
      fUseMultiHist = false;
      ok = true;
    }
    else if( stringEq(keyw, "MatrXYZR") || stringEq(keyw, "XYZRmatr") ) {
      fPsaMatrXYZR = true;
      ok = true;
    }
288
    else if( stringEq(keyw, "Verbose") ) {
dino's avatar
dino committed
289 290 291
      fVerbose = true;
      ok = true;
    }
292 293 294
    else if( stringEq(keyw, "DistanceMetric") ) {
      ok = 1 == sscanf(data.c_str(), "%f", &fDistMetric);
    }
295
    else if( stringEq(keyw, "GridSearch") ||  stringEq(keyw, "GridSearchType") ) {
296 297
      if( stringEq(data, "Full") ) {
        fUseAdaptive = false; fTryTwoHits = false;  fCoarseOnly = false; fPsaSegCenter = false; fFullSearch = true;
298
      }
299
      else if( stringEq(data, "Adaptive") ) {
300 301 302 303
        fUseAdaptive = true;  fTryTwoHits = false;  fCoarseOnly = false; fPsaSegCenter = false; fFullSearch = false;
      }
      else if( stringEq(data, "AdaptiveTwoHits") ) {
        fUseAdaptive = true;  fTryTwoHits = true ;  fCoarseOnly = false; fPsaSegCenter = false; fFullSearch = false;
304 305
      }
      else if(stringEq(data, "CoarseOnly") ) {
306 307 308 309 310 311 312
        fUseAdaptive = true;  fTryTwoHits = false;  fCoarseOnly = true;  fPsaSegCenter = false; fFullSearch = false;
      }
      //else if(stringEq(data, "CoarseOnlyTwoHits") ) {
      //  fUseAdaptive = true;  fTryTwoHits = true ;  fCoarseOnly = true;  fPsaSegCenter = false; fFullSearch = false;
      //}
      else if( stringEq(data, "Center") || stringEq(data, "SegCenter") ) {
        fUseAdaptive = false; fTryTwoHits = false;  fCoarseOnly = false; fPsaSegCenter = true;  fFullSearch = false;
313 314
      }
      else {
315
        fUseAdaptive = true;  fTryTwoHits = false;  fCoarseOnly = false; fPsaSegCenter = false; fFullSearch = false; // defaults to Adaptive
316 317 318
      }
      ok = true;
    }
319 320 321 322
    else if( stringEq(keyw, "NoFitTZero") ) {
      fFitTZero = false;
      ok = true;
    }
323 324 325 326
    else if( stringEq(keyw, "Threads") ) {
#ifdef PSA_THREADED
      ok = 2 == sscanf(data.c_str(), "%d %d", &fPsaCount, &fPsaModulo);
#else
327
      cout << " --> PSA_THREADED NOT DEFINED --> ignored" << endl;
328
#endif
329
      ok = true;
330
    }
331 332 333
    //else if( stringEq(keyw, "TraceLengthPSA") ||  stringEq(keyw, "TraceLength") ) {
    //  ok = 1 == sscanf(data.c_str(), "%d", &fTraceLengthPSA);
    //}
334
    else if( stringEq(keyw, "WriteTraces") ) {
335
      ok = 1 == sscanf(data.c_str(), "%d", &fWriteNumTraces);
dino's avatar
dino committed
336
    }
337 338 339 340
    else if( stringEq(keyw, "WritePsaHits") ) {
      fWritePsaHits = true;
      ok = true;
    }
341 342 343
    else if( stringEq(keyw, "EnergyGain") ) {
      ok = 1 == sscanf(data.c_str(), "%f", &fEnergyGain);
    }
344 345
    else if( stringEq(keyw, "CoreEnergyGate") ) {
      ok = 2 == sscanf(data.c_str(), "%f %f", &fCoreEnerMin, &fCoreEnerMax);
346
    }
347
    else if( stringEq(keyw, "SegmentFoldGate") ) {
dino's avatar
dino committed
348 349
      ok = 2 == sscanf(data.c_str(), "%d %d", &fPsaMinSegMult, &fPsaMaxSegMult);
    }
350 351 352 353 354
    else if( stringEq(keyw, "DeadSegment") ) {
      ok = 1 == sscanf(data.c_str(), "%d", &fDeadSegment);
      if(fDeadSegment >= CrystalInterface::kNbSegments)
        fDeadSegment = -1;
    }
355
    // this should be taken from the general calibration file of the detector, PreprocessingFilterPSA.conf
356 357 358 359
    else if( stringEq(keyw, "TauSlice") ) {
      ok = 7 == sscanf(data.c_str(), "%f %f %f %f %f %f %f", fTauSlice, fTauSlice+1, fTauSlice+2, fTauSlice+3, fTauSlice+4, fTauSlice+5, fTauSlice+6);
      fTauGiven = ok;
    }
dino's avatar
dino committed
360 361 362 363 364 365
    else {
      cout << "   --> ignored";
      ok = true;
    }

    if(!ok) {
dino's avatar
 
dino committed
366
      cout << "   --> missing argument(s)" << endl;
dino's avatar
dino committed
367 368 369
      *error_code = 103;
      return;
    }
370
    cout << endl;
dino's avatar
dino committed
371
  }
372

dino's avatar
dino committed
373 374
}

375
Int_t PSAFilter::SetInput(int slot)
dino's avatar
dino committed
376
{
377 378 379
  Frame *frame_in = fFrameCrystal->GetFrame();
  CrystalInterface *cdata = GetDataPointer<CrystalInterface>(frame_in);

dino's avatar
dino committed
380
  // loads the values from the frame into the ADFObject attached to the frame
381
  UInt_t bytes_in = frame_in->Read();
dino's avatar
dino committed
382

383
  PsaSlot *pSlot = theSlots + slot;
384

385 386
  pSlot->crystal_id     = crystal_id;
  pSlot->crystal_status = crystal_status;
387

dino's avatar
 
dino committed
388
  for(UShort_t isg=0; isg<CrystalInterface::kNbSegments; isg++){
389 390 391
    seg = cdata->GetSegment(isg);
    pSlot->SegE[isg] = (float)seg->GetE(); 
    seg->GetSignal()->Get(pSlot->fTracesSG[isg], fTraceLengthPSA);
dino's avatar
dino committed
392
  }
dino's avatar
 
dino committed
393
  for(UShort_t icc=0; icc<CrystalInterface::kNbCores; icc++){
394 395 396 397
    core = cdata->GetCore(icc);
    pSlot->CoreE[icc] = (float)core->GetE(); 
    pSlot->CoreT[icc] = (float)core->GetT();
    core->GetSignal()->Get(pSlot->fTracesCC[icc], fTraceLengthPSA);
dino's avatar
dino committed
398 399
  }

400 401 402 403 404
  pSlot->evnumber   = ((AgataKey *)frame_in->GetKey())->GetEventNumber();
  pSlot->timestamp  = ((AgataKey *)frame_in->GetKey())->GetTimeStamp();
  pSlot->numNetSegs = 0;
  pSlot->shiftT0    = 0;
  pSlot->tCycles    = 0;
dino's avatar
dino committed
405 406 407 408

  return 0;
}

409
Int_t PSAFilter::SetOutput(int slot)
dino's avatar
dino committed
410
{
411 412 413
  Frame *frame_out = fFramePSA->GetFrame();
  PSAInterface *psadata = GetDataPointer<PSAInterface>(frame_out);
  frame_out->Reset();
dino's avatar
dino committed
414

415
  PsaSlot *pSlot = theSlots + slot;
416

417
  if(pSlot->numNetSegs < 1)
dino's avatar
 
dino committed
418
    return 0;
dino's avatar
dino committed
419

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
  // there should be a way to mark two hits in the same segment
  // e.g. using the PSAHit::fstatus

  PsaOut_t * pOut = pSlot->PsaOut;
  for(UInt_t nh = 0; nh < pSlot->numNetSegs; nh++, pOut++) {
    ADF::PSAHit *pHit = (PSAHit*)psadata->NewHit();
    pHit->Reset();
    pHit->SetE(pOut->enerSG*pOut->bestFactor);
    pHit->SetXYZ(pOut->fx1, pOut->fy1, pOut->fz1);
    pHit->SetT(pOut->dTns);
    pHit->SetTrapCCe(pOut->eE_CC1);
    pHit->SetTrapCCh(pOut->hE_CC1);
    pHit->SetTrapSGe(pOut->eE_SG1);
    pHit->SetTrapSGh(pOut->hE_SG1);
    pHit->SetID(pOut->netChargeSeg,0);
    pHit->SetID(crystal_id,1);
436
    if(pOut->bestPoint2 >= 0) {
437 438 439 440 441 442 443 444 445 446 447
      ADF::PSAHit *pHit = (PSAHit*)psadata->NewHit();
      pHit->Reset();
      pHit->SetE(pOut->enerSG*(1.f-pOut->bestFactor));
      pHit->SetXYZ(pOut->fx2, pOut->fy2, pOut->fz2);
      pHit->SetT(pOut->dTns);
      pHit->SetTrapCCe(pOut->eE_CC2);
      pHit->SetTrapCCh(pOut->hE_CC2);
      pHit->SetTrapSGe(pOut->eE_SG2);
      pHit->SetTrapSGh(pOut->hE_SG2);
      pHit->SetID(pOut->netChargeSeg, 0);
      pHit->SetID(crystal_id,1);
448
    }
dino's avatar
dino committed
449 450
  }

451 452
  ((AgataKey *)frame_out->GetKey())->SetEventNumber(pSlot->evnumber);
  ((AgataKey *)frame_out->GetKey())->SetTimeStamp(pSlot->timestamp);  
453

454 455 456 457
  crystal_id     = pSlot->crystal_id;
  crystal_status = pSlot->crystal_status;
  CoreE0 = pSlot->CoreE[0];
  CoreE1 = pSlot->CoreE[1];
458
  
459 460 461 462 463
  CoreT0 = pSlot->CoreT[0];
  CoreT1 = pSlot->CoreT[1];

//#define ADDPSATIME
#ifdef ADDPSATIME
464 465
  // Add the T0 correction as determined by the PSA. --> The overall Ge-Ge timing becomes ~10% worse, with larger tails.
  // If the T0 shift is subtracted the overall ge-ge timing becomes ~2 worse (but very symmetric, meaning added noise).
466 467 468 469 470 471
  // The above seems not to be true if the number of samples used to determine Tzero in PsaFilterGridSearch::FitT0AfterPSA
  // is smal: e.g. at nsamps=10 we now get an improvement by 10%. To be tested with a wider dinamycal range.
  // Therefore, it is better not to correct. MOreover, one should also question the T0 realignment done in the PSA!
  CoreT0 += pSlot->shiftT0;
  CoreT1 += pSlot->shiftT0;
#endif
dino's avatar
dino committed
472

473 474
  //myAno.Set(crystal_id, 0);
  //myAno.fRealSize = sizeof(crystal_id);
475 476
  //myAno.Set(pSlot->timestamp, myAno.fRealSize);
  //myAno.fRealSize += sizeof(pSlot->timestamp);
477

478
  UInt_t bytes_out = frame_out->Write();
dino's avatar
dino committed
479

480
  return bytes_out ? 0 : 1;
dino's avatar
dino committed
481 482
}

483
Int_t PSAFilter::Process(int slot, int nslots)
dino's avatar
dino committed
484 485
{
  Int_t result = 0;
486
  //cout << "WARNING!! Empty Process()" << endl << flush;
dino's avatar
dino committed
487 488 489
  return result;
}

490 491 492 493 494 495 496 497 498 499 500
//void PSAFilter::process_block( void   *input_buffer,  UInt_t size_of_input_buffer,
//                               void   *output_buffer, UInt_t size_of_output_buffer,
//                               UInt_t *used_size_of_output_buffer,
//                               UInt_t *error_code)
//{
//  fBlockIn.SetBlock((Char_t *)input_buffer,size_of_input_buffer);
//  fBlockOut.SetBlock((Char_t *)output_buffer,size_of_output_buffer);
//
//  *error_code = PSAFilter::ProcessBlock(fBlockIn, fBlockOut);
//  *used_size_of_output_buffer = UInt_t(fBlockOut.GetSize());
//}
501 502 503 504 505 506 507 508 509 510 511

UInt_t PSAFilter::ProcessBlock (ADF::FrameBlock &in, ADF::FrameBlock &out)
{
#ifdef PSA_THREADED
  if(fPsaCount >  0)
    return ProcessBlockThreads(in, out);
  else
#endif
    return ProcessBlockNoThreads(in, out);
}

512 513 514
// In the non-threaded version, the processing is done one event at a time

UInt_t PSAFilter::ProcessBlockNoThreads(ADF::FrameBlock &inBlock, ADF::FrameBlock &outBlock)
515 516
{
  // attach the input/output buffer to the FrameIO system
517
  fFrameIO.Attach(&inBlock, &outBlock);
518 519 520 521 522 523 524 525 526 527 528

  // start the processing
  UInt_t error_code = 0;
  UInt_t nevs = cServer.GetCounts();

  while ( fFrameIO.Notify() ) {

    // fill local variables with data from the input
    if( SetInput() ) {
      error_code = 1;
      LOCK_COUT;
529
      Log.SetProcessMethod("ProcessBlock");
530 531 532 533 534 535 536 537
      Log << error << " During : SetInput()" << dolog;
      break;
    }

    // process the input buffer
    if( Process() ) {
      error_code = 2;
      LOCK_COUT;
538
      Log.SetProcessMethod("ProcessBlock");
539 540 541 542
      Log << error << " During : Process()" << dolog;
      break;
    }

543
    if(theSlots[0].numNetSegs < 1)
544 545 546 547 548 549 550 551 552
      continue;

    // spectra and traces
    PostProcess();

    // fill the output buffer
    if( SetOutput() ) {
      error_code = 3;
      LOCK_COUT;
553
      Log.SetProcessMethod("ProcessBlock");
554 555 556 557 558 559 560 561
      Log << error << " During : SetOutput()" << dolog;
      break;
    }

    // ok, so send the produced frame to the ouput
    if( !fFrameIO.Record() ) {
      error_code = 4;
      LOCK_COUT;
562
      Log.SetProcessMethod("ProcessBlock");
563 564 565 566 567 568
      Log << error << " During : Record()" << dolog;
      break;
    }

  }

569
  fFrameIO.Detach(&inBlock, &outBlock);
570 571

  nevs = cServer.GetCounts() - nevs;
dino's avatar
 
dino committed
572

573
  LOCK_COUT;
574
  cServer.Prompt(crystal_id, nevs, UInt_t(outBlock.GetSize()) );
575 576

  return error_code;
dino's avatar
dino committed
577 578
}

579
#ifdef PSA_THREADED
580

581 582
// In the threaded version, fPsaCount blocks of fPsaModulo events are processed in parallel.
// The blocks are used (writing-to, processing and reading-from) in a ring-counter mode
dino's avatar
 
dino committed
583

584
UInt_t PSAFilter::ProcessBlockThreads(ADF::FrameBlock &inBlock, ADF::FrameBlock &outBlock)
585 586
{
  // attach the input/output buffer to the FrameIO system
587
  fFrameIO.Attach(&inBlock, &outBlock);
588 589 590

  // start the processing
  UInt_t error_code = 0;
591
  UInt_t nevs = cServer.GetCounts();
dino's avatar
 
dino committed
592

593 594 595
  int  block = -1;    // index of the block being used
  int  evInp =  0;    // just for ispection during debug
  int  evOut =  0;
596 597 598

  bool endOfInput = false;
  while (!endOfInput) {
599

600 601
    block = (block + 1) % fPsaCount;
    PsaBlock *pBlock = theBlocks + block;
602

603
    bool blockHasData = false;
604
    {
605 606 607 608 609 610 611 612
      // Lock and check if the block has been activated (pBlock->State > 0)
      // In case, wait for its thread to finish the job (pBlock->State == 2)
      boost::mutex::scoped_lock slock(pBlock->Mutex);
      if(pBlock->State > 0) {
        blockHasData = true;
        if(pBlock->State != 2) {  // but not yet done
          while(pBlock->State != 2) {
            pBlock->Condition.wait(slock);
613
          }
614 615
        }
      }
616
      pBlock->State = 0; // having the lock we can safely set it to free
617 618
    }

619 620 621 622 623 624 625
    // Now the block is ours
    if(blockHasData) {
      // pass content of the block to the output
      for(UInt_t evn = 0; evn < pBlock->Count; evn++) {
        int slot = block*fPsaModulo+evn;
        if(theSlots[slot].retValue) {
          //chState[block] = 0; ???
626
          error_code = 2;
627
          LOCK_COUT;
628
          Log.SetProcessMethod("ProcessBlock");
629 630 631
          Log << error << " During : Process()" << dolog;
          break;
        }
632
        if(theSlots[slot].numNetSegs >0) {
633
          // spectra and traces
634
          PostProcess(slot);
635
          // fill the output buffer
636 637
          if( SetOutput(slot) ) {
            //chState[block] = 0; ???
638
            error_code = 3;
639
            LOCK_COUT;
640
            Log.SetProcessMethod("ProcessBlock");
641 642 643 644 645
            Log << error << " During : SetOutput()" << dolog;
            break;
          }
          // ok, so send the produced frame to the ouput
          if( !fFrameIO.Record() ) {
646
            //chState[block] = 0; ???
647
            error_code = 4;
648
            LOCK_COUT;
649
            Log.SetProcessMethod("ProcessBlock");
650 651 652
            Log << error << " During : Record()" << dolog;
            break;
          }
653
          evOut++;
654
        }
655
        theSlots[slot].numNetSegs = 0;
656 657 658
      }
    }
    if(error_code) {
659
      //chState[block] = 0; // ??
660 661 662
      break;
    }

663 664 665 666
    // fill this block with new data from the input
    pBlock->Count = 0;
    Int_t evn = 0;
    for( ; evn < fPsaModulo; evn++) {
667
      if(!fFrameIO.Notify() ) {
668
        endOfInput = true;
669 670
        break;
      }
671 672
      int slot = block*fPsaModulo+evn;
      if( SetInput(slot) ) {
673
        error_code = 1;
674
        LOCK_COUT;
675
        Log.SetProcessMethod("ProcessBlock");
676 677 678
        Log << error << " During : SetInput()" << dolog;
        break;
      }
679 680
      theSlots[slot].retValue = 0;
      evInp++;
681
    }
682 683
    if(evn < 1)
      break; // no more data or error
684

685 686 687 688 689
    pBlock->Count = evn;
    {
      // Lock and mark the block as ready to be processed
      boost::mutex::scoped_lock slock(pBlock->Mutex);
      pBlock->State = 1;
690
    }
691 692
    // tell the thread to proceed
    pBlock->Condition.notify_one();
693 694

  }   // while(!endOfInput)
695 696 697

  // Wait for the launched threads to finish

dino's avatar
 
dino committed
698
  // At this point the status of fFrameIO is BaseFrameIO::kIdle and we should no more write on it.
699
  // However, the output from the still-running threads is saved by forcing it to BaseFrameIO::kRunning 
dino's avatar
 
dino committed
700 701
  // It would be more efficient to synchronize the unfinished threads at the next call of ProcessBlock
  // but we do it here so as to keep the correspondence between input and output buffers
702

703
  for(Int_t nrs = 0; nrs < fPsaCount; nrs++) {
704

705 706
    block = (block + 1) % fPsaCount;
    PsaBlock *pBlock = theBlocks + block;
707

708
    bool blockHasData = false;
709
    {
710 711 712 713 714 715 716 717
      // Lock and check if the block has been activated (pBlock->State > 0)
      // In case, wait for its thread to finish the job (pBlock->State == 2)
      boost::mutex::scoped_lock slock(pBlock->Mutex);
      if(pBlock->State) {
        blockHasData = true;
        if(pBlock->State != 2) {  // but not yet done
          while(pBlock->State != 2) {
            pBlock->Condition.wait(slock);
718
          }
719 720
        }
      }
721
      pBlock->State = 0; // having the lock we can safely set it to free
722 723
    }

724 725 726 727 728 729 730
    // Now the block is ours
    if(blockHasData) {
      // pass content of the block to the output
      for(UInt_t evn = 0; evn < pBlock->Count; evn++) {
        int slot = block*fPsaModulo+evn;
        if(theSlots[slot].retValue ) {
          //chState[block] = 0; ???
731
          error_code = 2;
732
          LOCK_COUT;
733
          Log.SetProcessMethod("ProcessBlock");
734 735 736
          Log << error << " During : Process()" << dolog;
          break;
        }
737
        if(theSlots[slot].numNetSegs >0 ) {
dino's avatar
 
dino committed
738
          // spectra and traces
739 740 741 742
          PostProcess(slot);
          // fill the output buffer
          if( SetOutput(slot) ) {
            //chState[block] = 0; ???
743
            error_code = 3;
744
            LOCK_COUT;
745
            Log.SetProcessMethod("ProcessBlock");
746 747 748
            Log << error << " During : SetOutput()" << dolog;
            break;
          }
dino's avatar
 
dino committed
749
          // Reopen fFrameIO by forcing it to BaseFrameIO::kRunning
750
          if (fFrameIO.GetStatus() == BaseFrameIO::kIdle )
751 752
            fFrameIO.SetStatus(BaseFrameIO::kRunning);
          if( !fFrameIO.Record() ) {
753
            //chState[block] = 0; ???
754
            error_code = 4;
755
            LOCK_COUT;
756
            Log.SetProcessMethod("ProcessBlock");
757 758 759
            Log << error << " During : Record()" << dolog;
            break;
          }
760
          evOut++;
761
        }
762
        theSlots[slot].numNetSegs = 0;
763
      }
764
      pBlock->Count = 0;
765 766
    }
    if(error_code) {
767
      //chState[block] = 0; // ??
768 769 770 771
      break;
    }
  }

772
  fFrameIO.Detach(&inBlock, &outBlock);
773

774
  nevs = cServer.GetCounts() - nevs;
dino's avatar
 
dino committed
775

776
  LOCK_COUT;
777
  cServer.Prompt(crystal_id, nevs, UInt_t(outBlock.GetSize()) );
dino's avatar
dino committed
778 779

  return error_code;
780
}
781

782
#endif    // #ifdef PSA_THREADED
783

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
Int_t PSAFilter::PostProcess(int slot)
{
  PsaSlot *pSlot = theSlots + slot;
  int numNetSegs = pSlot->numNetSegs;
  if(numNetSegs < 1)
    return 0;

  // give the Algorithm the possibility to perform its own thread-safe PostProcess actions
  AlgoSpecificPostProcess(slot);

#ifdef PSA_FromGRU
  pOut = pSlot->PsaOut;
  for(UInt_t nh = 0; nh < pSlot->numNetSegs; nh++, pOut++) {
    float fx = pOut->fx1;
    float fy = pOut->fy1;
    float fz = pOut->fz1;
    PSAxy_Proje -> Fill(fx,fy);
    PSAxz_Proje -> Fill(fx,fz);
    PSAyz_Proje -> Fill(fy,fz);
    if(pOut->bestPoint2 >= 0) {
      float fx = pOut->fx2;
      float fy = pOut->fy2;
      float fz = pOut->fz2;
      PSAxy_Proje -> Fill(fx,fy);
      PSAxz_Proje -> Fill(fx,fz);
      PSAyz_Proje -> Fill(fy,fz);
    }
  }
#endif

  cServer.Exec(pSlot->timestamp);

  return 0;
}

dino's avatar
dino committed
819 820
void PSAFilter::process_reset (UInt_t *error_code)
{
821 822 823
  *error_code = 0;
  Log.ClearMessage();
  Log.SetProcessMethod("process_reset"); 
dino's avatar
dino committed
824 825
  fFrameIO.Print(Log()); 

826
  cServer.Reset();
827
  Log << dolog;
dino's avatar
dino committed
828
}
dino's avatar
 
dino committed
829

dino's avatar
dino committed
830 831
void PSAFilter::process_start (UInt_t *error_code)
{
832 833
  Log.GetProcessName() = "PSAFilter";
  Log.SetProcessMethod("process_start"); 
834
  cServer.Start(gMotherClass);
dino's avatar
dino committed
835
  *error_code = 0;
dino's avatar