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
  CoreT0 = pSlot->CoreT[0];
  CoreT1 = pSlot->CoreT[1];

462
#define ADDPSATIME
463
#ifdef ADDPSATIME
464 465 466 467 468 469
  // Add the T0 correction as determined by the PSA.
  // Using a large number of samples (nsamples>20) in PsaFilterGridSearch::FitT0AfterPSA to determine Tzero,
  // Tgamma-gamma becomes ~10% worse than using only the timing done in PreprocessingFilterPSA. 
  // With (nsamples=10) Tgamma-gamma improves by ~10% but the peaks start getting tails.
  // A reasonable compromise seems to be (nsamples=15), but the Tgamma-gamma improvement is rather modest.
  // This matter is not completely clarified and one can decide to ignore the correction by commenting the #define ADDPSATIME.
470 471 472
  CoreT0 += pSlot->shiftT0;
  CoreT1 += pSlot->shiftT0;
#endif
dino's avatar
dino committed
473

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

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

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

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

491 492 493 494 495 496 497 498 499 500 501
//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());
//}
502 503 504 505 506 507 508 509 510 511 512

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);
}

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

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

  // 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;
530
      Log.SetProcessMethod("ProcessBlock");
531 532 533 534 535 536 537 538
      Log << error << " During : SetInput()" << dolog;
      break;
    }

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

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

    // spectra and traces
    PostProcess();

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

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

  }

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

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

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

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

580
#ifdef PSA_THREADED
581

582 583
// 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
584

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

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

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

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

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

604
    bool blockHasData = false;
605
    {
606 607 608 609 610 611 612 613
      // 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);
614
          }
615 616
        }
      }
617
      pBlock->State = 0; // having the lock we can safely set it to free
618 619
    }

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

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

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

  }   // while(!endOfInput)
696 697 698

  // Wait for the launched threads to finish

dino's avatar
 
dino committed
699
  // At this point the status of fFrameIO is BaseFrameIO::kIdle and we should no more write on it.
700
  // However, the output from the still-running threads is saved by forcing it to BaseFrameIO::kRunning 
dino's avatar
 
dino committed
701 702
  // 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
703

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

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

709
    bool blockHasData = false;
710
    {
711 712 713 714 715 716 717 718
      // 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);
719
          }
720 721
        }
      }
722
      pBlock->State = 0; // having the lock we can safely set it to free
723 724
    }

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

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

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

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

  return error_code;
781
}
782

783
#endif    // #ifdef PSA_THREADED
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 819
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
820 821
void PSAFilter::process_reset (UInt_t *error_code)
{
822 823 824
  *error_code = 0;
  Log.ClearMessage();
  Log.SetProcessMethod("process_reset"); 
dino's avatar
dino committed
825 826
  fFrameIO.Print(Log()); 

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

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