Hall C ROOT/C++ Analyzer (hcana)
THcHelicityScaler.cxx
Go to the documentation of this file.
1 
20 //#include "THaEvtTypeHandler.h"
21 #include "THcHelicityScaler.h"
22 #include "GenScaler.h"
23 #include "Scaler3801.h"
24 #include "THaCodaData.h"
25 #include "THaEvData.h"
26 #include "THcGlobals.h"
27 #include "THaGlobals.h"
28 #include "THcParmList.h"
29 #include "THcHelicity.h"
30 #include "TNamed.h"
31 #include "TMath.h"
32 #include "TString.h"
33 #include "TROOT.h"
34 #include <cstring>
35 #include <cstdio>
36 #include <cstdlib>
37 #include <iostream>
38 #include <sstream>
39 #include <map>
40 #include <bitset>
41 #include <iterator>
42 #include "THaVarList.h"
43 #include "VarDef.h"
44 #include "Helper.h"
45 
46 using namespace std;
47 using namespace Decoder;
48 
49 static const UInt_t ICOUNT = 1;
50 static const UInt_t IRATE = 2;
51 static const UInt_t ICURRENT = 3;
52 static const UInt_t ICHARGE = 4;
53 static const UInt_t ITIME = 5;
54 static const UInt_t ICUT = 6;
55 static const UInt_t MAXCHAN = 32;
56 static const UInt_t defaultDT = 4;
57 
58 
59 THcHelicityScaler::THcHelicityScaler(const char *name, const char* description)
60  : THaEvtTypeHandler(name,description),
61  fBankID(9801),
62  fUseFirstEvent(kTRUE), fDelayedType(-1),
63  fBCM_Gain(0), fBCM_Offset(0), fBCM_SatOffset(0), fBCM_SatQuadratic(0), fBCM_delta_charge(0),
64  evcount(0), evcountR(0.0), ifound(0),
65  fNormIdx(-1), fNormSlot(-1),
66  dvars(0), dvarsFirst(0),
67  fScalerTree(0), fOnlyBanks(kFALSE),
68  fClockChan(-1), fLastClock(0)
69 {
70 
71  fRocSet.clear();
72  fModuleSet.clear();
73 
74  //---------------------------------------------------------------------------
75 
76  fROC=-1;
77  fNScalerChannels = 32;
78 
79  AddEvtType(1);
80  AddEvtType(2);
81  AddEvtType(4);
82  AddEvtType(5);
83  AddEvtType(6);
84  AddEvtType(7);
85  AddEvtType(129);
86  SetDelayedType(129);
87 
88 }
89 
91 {
92 
93  if (!TROOT::Initialized()) {
94  delete fScalerTree;
95  }
96  Podd::DeleteContainer(scalers);
97  Podd::DeleteContainer(scalerloc);
98  delete [] dvars;
99  delete [] dvarsFirst;
100  delete [] fBCM_SatOffset;
101  delete [] fBCM_SatQuadratic;
102  delete [] fBCM_delta_charge;
103  delete [] fBCM_Gain;
104  delete [] fBCM_Offset;
105 
106  for( vector<UInt_t*>::iterator it = fDelayedEvents.begin();
107  it != fDelayedEvents.end(); ++it )
108  delete [] *it;
109  fDelayedEvents.clear();
110 }
111 
113 {
114 
115  // Process any delayed events in order received
116 
117  for(std::vector<UInt_t*>::iterator it = fDelayedEvents.begin();
118  it != fDelayedEvents.end(); ++it) {
119  UInt_t* rdata = *it;
120  evNumberR += 1;
121  AnalyzeBuffer(rdata);
122  }
123 
124  for( vector<UInt_t*>::iterator it = fDelayedEvents.begin();
125  it != fDelayedEvents.end(); ++it )
126  delete [] *it;
127  fDelayedEvents.clear();
128 
129  //Write the helicity variables to scaler tree
130  if (fScalerTree) { fScalerTree->Write(); }
131 
132 
133  //Compute Scaler Asymmetries
134  /*
135  for(Int_t i=0;i<fNScalerChannels;i++) {
136  if(fScalerSums[i]>0.5) {
137  fScalAsymmetry[i] = (fHScalers[0][i]-fHScalers[1][i])/fScalerSums[i];
138  fScalAsymmetryError[i] = 2*TMath::Sqrt(fHScalers[0][i]*fHScalers[1][i]
139  *fScalerSums[i])
140  /(fScalerSums[i]*fScalerSums[i]);
141  } else {
142  fScalAsymmetry[i] = 0.0;
143  fScalAsymmetryError[i] = 0.0;
144  }
145 
146  }
147  */
148 
149  //------Compute Time Asymmetries-------
150 
151  //C.Y. 12/15/2020 Time Asymmetry / Error Calculations (with scaler_current cut)
152 
153  if(fQuartetCount <= 1) {
154  fTimeAsymmetry = -1000.;
155  fTimeAsymmetryError = 0.0;
156  } else {
157  fTimeAsymmetry = fTimeAsymSum/fQuartetCount; //normalize asymmetry to total number of quartets
162  } else {
163  fTimeAsymmetryError = 0.0;
164  }
165  }
166 
167 
168 
169  //------Compute Scaler Asymmetries-------
170 
171  //C.Y. 12/15/2020 Scaler Asymmetry / Error Calculations (with scaler_current cut)
172 
173  for(Int_t i=0; i<fNScalerChannels; i++) {
174 
175  if(fQuartetCount <= 1) {
176  fScalAsymmetry[i] = -1000.;
177  fScalAsymmetryError[i] = 0.0;
178  } else {
179  fScalAsymmetry[i] = fScalAsymSum[i]/fQuartetCount; //normalize asymmetry to total number of quartets
184  } else {
185  fScalAsymmetryError[i] = 0.0;
186  }
187  }
188 
189  }
190 
191 
192  //------Compute Charge Asymmetries-------
193 
194  //C.Y. 12/14/2020 Charge Asymmetry / Error Calculations (with scaler_current cut)
195 
196  //Set the helicity scaler module channels for each BCM
197  std::map<std::string, Int_t> bcmindex;
198  bcmindex["BCM1_Hel.scal"] = 0;
199  bcmindex["BCM2_Hel.scal"] = 2;
200  bcmindex["Unser_Hel.scal"] = 6;
201  bcmindex["BCM4A_Hel.scal"] = 10;
202  bcmindex["BCM4B_Hel.scal"] = 4;
203  bcmindex["BCM4C_Hel.scal"] = 12;
204  //bcmindex["1MHz_Hel.scal"] = 8;
205 
206 
207  //cout << endl << "---------------------- Beam Charge Asymmetries ---------------------- " << endl;
208  //cout << " BCM Total Charge Beam ON Beam ON Asymmetry" << endl;
209  //cout << " Name Charge Asymmetry Charge Asymmetry Error" << endl;
210 
211  for(Int_t i=0;i<fNumBCMs;i++) {
212 
213  if(fQuartetCount <= 1) {
214  fChargeAsymmetry[i] = -1000.;
215  fChargeAsymmetryError[i] = 0.0;
216  } else {
217  fChargeAsymmetry[i] = fChargeAsymSum[i]/fQuartetCount; //normalize charge asymmetry to total number of quartets (as the sum is for every quartet)
218 
223  } else {
224  fChargeAsymmetryError[i] = 0.0;
225  }
226  }
227 
228  //printf("%6s %12.2f %12.8f %12.2f %12.8f %12.8f\n",fBCM_Name[i].c_str(),fCharge[i],
229  // fChargeAsymmetry[i],fChargeSum[i],asy,asyerr);
230  }
231 
232 
233  //Compute +/- helicity Times (no BCM cut)
234  Double_t pclock = fHScalers[0][fClockChan];
235  Double_t mclock = fHScalers[1][fClockChan];
236 
237  fTimePlus = pclock/fClockFreq;
238  fTimeMinus = mclock/fClockFreq;
239  //fTime = (pclock+mclock)/fClockFreq;
240  //if(pclock+mclock>0) {
241  //fTimeAsymmetry = (pclock-mclock)/(pclock+mclock);
242  //} else {
243  // fTimeAsymmetry = 0.0;
244  //}
245  //printf("TIME(s)%12.2f %12.8f %12.2f\n",fTime, fTimeAsymmetry, fTimeSum);
246 
247 
248  //Compute Helicity Trigger Asymmetries (no BCM cut)
251  } else {
252  fTriggerAsymmetry = 0.0;
253  }
254 
255  return 0;
256 }
257 
258 
260 {
261 
262  char prefix[2];
263  prefix[0]='g';
264  prefix[1]='\0';
265  fNumBCMs = 0;
266  DBRequest list[]={
267  {"NumBCMs",&fNumBCMs, kInt, 0, 1},
268  {0}
269  };
270  gHcParms->LoadParmValues((DBRequest*)&list, prefix);
271 
272  if(fNumBCMs > 0) {
273  fBCM_Gain = new Double_t[fNumBCMs];
278 
279  string bcm_namelist;
280  DBRequest list2[]={
281  {"BCM_Gain", fBCM_Gain, kDouble, (UInt_t) fNumBCMs},
282  {"BCM_Offset", fBCM_Offset, kDouble,(UInt_t) fNumBCMs},
283  {"BCM_SatQuadratic", fBCM_SatQuadratic, kDouble,(UInt_t) fNumBCMs,1},
284  {"BCM_SatOffset", fBCM_SatOffset, kDouble,(UInt_t) fNumBCMs,1},
285  {"BCM_Names", &bcm_namelist, kString},
286  {"BCM_Current_threshold", &fbcm_Current_Threshold, kDouble,0, 1},
287  {"BCM_Current_threshold_index", &fbcm_Current_Threshold_Index, kInt,0,1},
288  {0}
289  };
290 
293  for(Int_t i=0;i<fNumBCMs;i++) {
294  fBCM_SatOffset[i]=0.;
295  fBCM_SatQuadratic[i]=0.;
296  }
297  gHcParms->LoadParmValues((DBRequest*)&list2, prefix);
298  vector<string> bcm_names = Podd::vsplit(bcm_namelist);
299  for(Int_t i=0;i<fNumBCMs;i++) {
300  fBCM_Name.push_back(bcm_names[i]+"_Hel.scal");
301  fBCM_delta_charge[i]=0.;
302  }
303  }
304  fTotalTime=0.;
305  fPrevTotalTime=0.;
306  fDeltaTime=-1.;
307 
308  return kOK;
309 }
310 
312 
321  fDelayedType = evtype;
322 }
323 
325 {
333  //C.Y. | THcScalerEvtHandler::Analyze() uses this flag (which is forced to be 1),
334  //but as to why, it is beyond me. For consistency, I have also used it here.
335  // This is some hack to make sure that the scaler ROOT tree is created at
336  // the first event. lfirst could probably be removed and simply to
337  // if(!fScalerTree) ... to create the tree.
338  Int_t lfirst=1;
339 
340  if(evdata->GetEvNum() > 0) {
341  evNumber=evdata->GetEvNum();
343  }
344 
345  if ( !IsMyEvent(evdata->GetEvType()) ) return -1;
346 
347  if (fDebugFile) {
348  *fDebugFile << endl << "---------------------------------- "<<endl<<endl;
349  *fDebugFile << "\nEnter THcHelicityScaler for fName = "<<fName<<endl;
350  EvDump(evdata);
351  }
352 
353 
354  if (lfirst && !fScalerTree) {
355 
356  lfirst = 0;
357 
358  //Assign a name to the helicity scaler tree
359  TString sname1 = "TSHel";
360  TString sname2 = sname1 + fName;
361  TString sname3 = fName + " Scaler Data";
362 
363  if (fDebugFile) {
364  *fDebugFile << "\nAnalyze 1st time for fName = "<<fName<<endl;
365  *fDebugFile << sname2 << " " <<sname3<<endl;
366  }
367 
368  //Create Scaler Tree
369  fScalerTree = new TTree(sname2.Data(),sname3.Data());
370  fScalerTree->SetAutoSave(200000000);
371 
372  TString name, tinfo;
373 
374  name = "evcount";
375  tinfo = name + "/D";
376  fScalerTree->Branch(name.Data(), &evcountR, tinfo.Data(), 4000);
377 
378  name = "evNumber";
379  tinfo = name + "/D";
380  fScalerTree->Branch(name.Data(), &evNumberR, tinfo.Data(), 4000);
381 
382  //C.Y. 12/02/2020 Added actual helicity to be stored in scaler tree
383  name = "actualHelicity";
384  tinfo = name + "/D";
385  fScalerTree->Branch(name.Data(), &actualHelicityR, tinfo.Data(), 4000);
386 
387  //C.Y. 12/09/2020 Added quartetphase to be stored in scaler tree
388  name = "quartetPhase";
389  tinfo = name + "/D";
390  fScalerTree->Branch(name.Data(), &quartetphaseR, tinfo.Data(), 4000);
391 
392  for (size_t i = 0; i < scalerloc.size(); i++) {
393  name = scalerloc[i]->name;
394  tinfo = name + "/D";
395  fScalerTree->Branch(name.Data(), &dvars[i], tinfo.Data(), 4000);
396  }
397 
398  }
399 
400  UInt_t *rdata = (UInt_t*) evdata->GetRawDataBuffer();
401 
402  if((Int_t)evdata->GetEvType() == fDelayedType) { // Save this event for processing later
403  UInt_t evlen = evdata->GetEvLength();
404 
405  UInt_t *datacopy = new UInt_t[evlen];
406  fDelayedEvents.push_back(datacopy);
407  memcpy(datacopy,rdata,evlen*sizeof(UInt_t));
408  return 1;
409  }
410 
411  else { // A normal event
412  if (fDebugFile) *fDebugFile<<"\n\nTHcHelicityScaler :: Debugging event type "<<dec<<evdata->GetEvType()<< " event num = " << evdata->GetEvNum() << endl<<endl;
413  Int_t ret;
414  if((ret=AnalyzeBuffer(rdata)))
415  {
416  if (fDebugFile) *fDebugFile << "scaler tree ptr 1 "<<fScalerTree<<endl;
417  if (fDebugFile) *fDebugFile << "ret = "<< ret <<endl;
418  }
419 
420  return ret;
421  }
422 
423 }
425 {
433  fNTrigsInBuf = 0;
434 
435  // Parse the data, load local data arrays.
436  UInt_t *p = (UInt_t*) rdata;
437 
438  UInt_t *plast = p+*p; // Index to last word in the bank
439  Int_t roc = -1;
440  UInt_t evlen = *p+1;
441 
442  Int_t ifound=0;
443 
444  while(p<plast) {
445  UInt_t banklen = *p;
446  p++; // point to header
447 
448  if (fDebugFile) {
449  *fDebugFile << "Bank: " << hex << *p << dec << " len: " << *(p-1) << endl;
450  }
451  if((*p & 0xff00) == 0x1000) { // Bank Containing banks
452  if(evlen-*(p-1) > 1) { // Don't use overall event header
453  roc = (*p>>16) & 0xf;
454  if(fDebugFile) *fDebugFile << "ROC: " << roc << " " << evlen << " " << *(p-1) << hex << " " << *p << dec << endl;
455  // cout << "ROC: " << roc << " " << evlen << " " << *(p-1) << hex << " " << *p << dec << endl;
456  if(roc != fROC) { // Not a ROC with helicity scaler
457  p+=*(p-1)-1; // Skip to next ROC
458  }
459  }
460  p++; // Now pointing to a bank in the bank
461  } else if (((*p & 0xff00) == 0x100) && (*p != 0xC0000100)) {
462  // Bank containing integers. Look for scalers
463  // This is either ROC bank containing integers or
464  // a bank within a ROC containing data from modules of a single type
465  // Look for banks with the helicity scaler bank ID (9801)
466  // Assume that very first word is a scaler header
467  // At any point in the bank where the word is not a matching
468  // header, we stop.
469  UInt_t tag = (*p>>16) & 0xffff; // Bank ID (ROC #)
470  // UInt_t num = (*p) & 0xff;
471  UInt_t *pnext = p+banklen; // Next bank
472  p++; // First data word
473  // If the bank is not a helicity scaler bank
474  // or it is not one of the ROC containing helcity scaler data
475  // skip to the next bank
476  //cout << "BankID=" << tag << endl;
477 
478  if (tag != fBankID) {
479  p = pnext; // Fall through to end of the above else if
480  // cout << " Skipping to next bank" << endl;
481 
482  } else {
483  // This is a helicity scaler bank
484  if (roc == fROC) {
485  UInt_t nevents = (banklen-2)/fNScalerChannels;
486  //cout << "# of helicity events in bank:" << " " << nevents << endl;
487  if (nevents > 100) {
488  cout << "Error! Beam off for too long" << endl;
489  }
490 
491  fNTrigsInBuf = 0;
492 
493  // Save helcitiy and quad info for THcHelicity
494  for (UInt_t iev = 0; iev < nevents; iev++) { // find number of helicity events in each bank
495  Int_t index = fNScalerChannels*iev+1;
496 
497  //C.Y. 11/26/2020 This methods extracts the raw helicity information
498  AnalyzeHelicityScaler(p+index);
499  }
500  }
501  }
502 
503  while(p < pnext) {
504  Int_t nskip = 0;
505  if(fDebugFile) {
506  *fDebugFile << "Scaler Header: " << hex << *p << dec;
507  }
508 
509  if(nskip == 0) {
510  if(fDebugFile) {
511  *fDebugFile << endl;
512  }
513  break; // Didn't find a matching header
514  }
515  p = p + nskip;
516  }
517  p = pnext;
518  } else {
519  p = p+*(p-1); // Skip to next bank
520  }
521 
522  }
523 
524  if (fDebugFile) {
525  *fDebugFile << "Finished with decoding. "<<endl;
526  *fDebugFile << " Found flag = "<<ifound<<endl;
527  }
528 
529  if (!ifound) return 0;
530 
531  return 1;
532 }
533 
535 {
565  Int_t hbits = (p[0]>>30) & 0x3; // quartet and helcity bits in scaler word
566  Bool_t isquartet = (hbits&2) != 0;
567  Int_t ispos = hbits&1;
568  Int_t actualhelicity = 0;
570  fNTrigsInBuf++;
571  fNTriggers++;
572 
573  Int_t quartetphase = (fNTriggers-fFirstCycle)%4;
574 
575  // fRingSeed_reported is a bit pattern with a history of the starting
576  // helicity of the last 30 quartets
577  // It is filled in the if block below.
578  // fNBits is the number of quartets that have been seen so far.
579  // Once it reaches 30, then fRingSeed_reported can be used to predict
580  // future reported helicities. That prediction is compared to the
581  // reported helicity and error messages are printed if the reported and
582  // predicted helicities don't agree.
583  if(fFirstCycle >= -10) {
584  if(quartetphase == 0) {
585  Int_t predicted = RanBit30(fRingSeed_reported);
586  fRingSeed_reported = ((fRingSeed_reported<<1) | ispos) & 0x3FFFFFFF;
587  // Check if ringseed_predicted agrees with reported if(fNBits>=30)
588  if(fNBits >= 30 && predicted != fRingSeed_reported) {
589  // Should probably reset fNBits to 0 and fFirstCycle to -100
590  cout << "THcHelicityScaler: Helicity Prediction Failed" << endl;
591  cout << "Reported " << bitset<32>(fRingSeed_reported) << endl;
592  cout << "Predicted " << bitset<32>(predicted) << endl;
593  }
594  fNBits++;
595  if(fNBits==30) {
596  cout << "THcHelicityScaler: A " << bitset<32>(fRingSeed_reported) <<
597  " found at cycle " << fNTriggers << endl;
598  }
599  } else if (quartetphase == 3) {
600  if(!isquartet) {
601  cout << "THcHelicityScaler: Quartet bit expected but not set (" <<
602  fNTriggers << ")" << endl;
603  fNBits = 0;
604  fRingSeed_reported = 0;
605  fRingSeed_actual = 0;
606  fFirstCycle = -100;
607  }
608  }
609  } else { // First cycle not yet identified
610  if(isquartet) { // Helicity and quartet signal for next set of scalers
611  fFirstCycle = fNTriggers - 3;
612  quartetphase = (fNTriggers-fFirstCycle)%4;
613  // Helicity at start of quartet is same as last of quartet, so we can start filling the seed
614  fRingSeed_reported = ((fRingSeed_reported<<1) | ispos) & 0x3FFFFFFF;
615  fNBits++;
616  if(fNBits==30) {
617  cout << "THcHelicityScaler: B " << bitset<32>(fRingSeed_reported) <<
618  " found at cycle " << fNTriggers << endl;
619  }
620  }
621  }
622 
623  // If 30 or more quartets have been seen, then the reported seed can be
624  // advanced by 2 quartets to account for the fact that the helicity
625  // reporting is delayed by 8 helicity windows.
626  if(fNBits>=30) {
629 
630  // Turns out that there is a known bug for the input bits of the
631  // SIS3801. The bits are delayed by one trigger. At the time this
632  // class was written this bug was unkonwn to the author. The following
633  // code was determined empiracally to deal with that bug.
634 #define DELAY9
635 #ifdef DELAY9
636  if(quartetphase == 3) {
638  actualhelicity = (fRingSeed_actual&1)?+1:-1;
639  } else {
640  actualhelicity = (fRingSeed_actual&1)?+1:-1;
641  if(quartetphase == 0 || quartetphase == 1) {
642  actualhelicity = -actualhelicity;
643  }
644  }
645  quartetphase = (quartetphase+1)%4;
646 #else
647  actualhelicity = (fRingSeed_actual&1)?+1:-1;
648  if(quartetphase == 1 || quartetphase == 2) {
649  actualhelicity = -actualhelicity;
650  }
651 #endif
652  } else {
653  fRingSeed_actual = 0;
654  }
655 
656  //C.Y. 12/09/2020 : Pass quartet phase to scaler tree varable
657  quartetphaseR = quartetphase;
658 
659  //C.Y. 11/26/2020 The block of code below is used to extract the helicity information from each
660  //channel of the helicity scaler onto a variable to be stored in the scaler tree. For each channel,
661  //each helicity state (+, -, or undefined) is stored in a single varibale. Each helicity state
662  //is tagged to the corresponding scaler read via 'actualHelicityR' which is stored below..
663 
664  //C.Y. Assign actual helicity value to a variable to be written to tree (the value may be (0, +hel (+1), or -hel(-1))
665  //Where actualhelicity=0 is NOT the MPS. It is zero when the actual helicity has not been determined.
666  actualHelicityR = actualhelicity;
667 
668  //C.Y. 11/26/2020 Loop over all 32 scaler channels for a specific helicity scaler module (SIS 3801)
669  for(Int_t i=0;i<fNScalerChannels;i++) {
670 
671  //C.Y. 11/26/2020 the count expression below gets the scaler raw helicity information (+, -, or MPS helicity states) for the ith channel
672  Int_t count = p[i]&0xFFFFFF; // Bottom 24 bits equivalent of scalers->Decode()
673  fScalerChan[i] = count; //pass the helicity raw information to each helicity scaler channel array element
674  }
675 
676 
677 
678  //C.Y. 11/26/2020 The block of code below is used to get a cumulative sum of +/- helicity used
679  //for calculation of the cumulative beam charge asymmetry and other quantities in the ::End() method
680  if(actualhelicity!=0) {
681 
682  //index=0 (+ helicity), index=1 (- helicity)
683  Int_t hindex = (actualhelicity>0)?0:1;
684 
685  //C.Y. 11/24/2020 increment the counter for either '+' or '-' helicity states
686  (actualhelicity>0)?(fNTriggersPlus++):(fNTriggersMinus++);
687 
688  //C.Y. 11/24/2020 Loop over all 32 scaler channels for a specific helicity scaler module (SIS 3801)
689  for(Int_t i=0;i<fNScalerChannels;i++) {
690 
691  Int_t count = p[i]&0xFFFFFF; // Bottom 24 bits equivalent of scalers->Decode()
692 
693  //Increment either the '+' (hindex=0) or '-' (hindex=1) helicity counts for each [i] scaler channel channel of a given module
694  fHScalers[hindex][i] += count;
695  fScalerSums[i] += count;
696  }
697  }
698 
699 
700 
701  //Set the helicity scaler clock to define the time
702  fDeltaTime = fScalerChan[fClockChan]/fClockFreq; //total clock counts / clock_frequency (1MHz) for a specific scaler read interval
703  fTotalTime = fPrevTotalTime + fDeltaTime; //cumulative scaler time
704 
705  if (fDeltaTime==0) {
706  cout << " ******************* Severe Warning ****************************" << endl;
707  cout << " In THcHelicityScaler have found fDeltaTime is zero !! " << endl;
708  cout << " ******************* Alert DAQ experts ***************************" << endl;
709  if (fDebugFile) *fDebugFile << " In THcHelicityScaler have found fDeltaTime is zero !! " << endl;
710  }
711 
712  fPrevTotalTime=fTotalTime; //set the current total time to the previous time for the upcoming read
713 
714  //C.Y. Nov 27, 2020 : (below) code to write the helicity raw data to a variable
715  //and map the variable to the scaler location
716 
717  Double_t scal_current=0;
718  //Loop over each scaler variable from the map
719  for (size_t i = 0; i < scalerloc.size(); i++) {
720  size_t ivar = scalerloc[i]->ivar;
721  size_t idx = scalerloc[i]->index;
722  size_t ichan = scalerloc[i]->ichan;
723 
724  //ANALYZE 1ST SCALER READ SEPARATE (There is no previous read before this one)
725  if (evcount==0) {
726 
727  //Loop over the scaler variable (ivar), helicity slot (idx), and slot channel (ichan) --> idx=0 (only one helicity module per spectrometer arm)
728  if ((ivar < scalerloc.size()) &&
729  (idx < scalers.size()) &&
730  (ichan < MAXCHAN)) {
731 
732  //If fUseFirstEvent=kTRUE (do not skip 1st read)
733  if(fUseFirstEvent){
734 
735  //Write scaler counts
736  if (scalerloc[ivar]->ikind == ICOUNT){
737  dvars[ivar] = fScalerChan[ichan];
738  dvarsFirst[ivar] = 0.0;
739  }
740 
741  //Write scaler time
742  if (scalerloc[ivar]->ikind == ITIME){
743  dvars[ivar] = fDeltaTime;
744  dvarsFirst[ivar] = 0.0;
745  }
746 
747  //Write scaler rate
748  if (scalerloc[ivar]->ikind == IRATE) {
749  dvars[ivar] = (fScalerChan[ichan])/fDeltaTime;
750  dvarsFirst[ivar] = 0.0;
751  }
752 
753  //Write either scaler current or scaler charge
754  if(scalerloc[ivar]->ikind == ICURRENT || scalerloc[ivar]->ikind == ICHARGE){
755 
756  //Get BCM index
757  Int_t bcm_ind=-1;
758  for(Int_t itemp =0; itemp<fNumBCMs;itemp++)
759  {
760  size_t match = string(scalerloc[ivar]->name.Data()).find(string(fBCM_Name[itemp]));
761  if (match!=string::npos)
762  {
763  bcm_ind=itemp;
764  }
765  }
766 
767  //Calculate and write scaler current
768  if (scalerloc[ivar]->ikind == ICURRENT) {
769 
770  //set default to zero
771  dvars[ivar]=0.;
772  //Check bcm index and calculate current in a temporary placeholder, "cur_temp"
773  if (bcm_ind != -1) {
774  Double_t cur_temp=((fScalerChan[ichan])/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];
775  cur_temp = cur_temp + fBCM_SatQuadratic[bcm_ind]*TMath::Max(cur_temp-fBCM_SatOffset[i],0.0);
776  //Assign the calculated scaler current to dvars
777  dvars[ivar]=cur_temp;
778  }
779  //Check which bcm index to place a bcm current threshold cut later on. Assign the the beam current read to "scal_current" for later use.
780  if (bcm_ind == fbcm_Current_Threshold_Index) {scal_current= dvars[ivar];}
781  }
782 
783  //Calculate andd write scaler charge
784  if (scalerloc[ivar]->ikind == ICHARGE) {
785  //Check bcm index and calculate current in a temporary placeholder, "cur_temp", to determine the charge later on.
786  if (bcm_ind != -1) {
787  Double_t cur_temp=((fScalerChan[ichan])/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];
788  cur_temp=cur_temp+fBCM_SatQuadratic[bcm_ind]*TMath::Power(TMath::Max(cur_temp-fBCM_SatOffset[bcm_ind],0.0),2.0);
789  //Calculate the charge for this scaler read
790  fBCM_delta_charge[bcm_ind]=fDeltaTime*cur_temp;
791  //Assign the charge to dvars
792  dvars[ivar] = fBCM_delta_charge[bcm_ind];
793  }
794  }
795  }
796  }
797 
798  //If user has set fUseFirstEvent=kFALSE (then use dvarsFirst to store the information for the 1st event, and leave dvars at 0.0)
799  //(The same calculations as above, but assign dvars=0.0, so that it does not count when written to the scaler tree)
800  else { //ifnotusefirstevent
801 
802  if (scalerloc[ivar]->ikind == ICOUNT) {
803  dvarsFirst[ivar] = fScalerChan[ichan];
804  dvars[ivar] = 0.0;
805  }
806 
807  if (scalerloc[ivar]->ikind == ITIME){
808  dvarsFirst[ivar] = fDeltaTime;
809  dvars[ivar] = 0.0;
810  }
811 
812  if (scalerloc[ivar]->ikind == IRATE) {
813  dvarsFirst[ivar] = (fScalerChan[ichan])/fDeltaTime;
814  dvars[ivar] = 0.0;
815  }
816 
817  if(scalerloc[ivar]->ikind == ICURRENT || scalerloc[ivar]->ikind == ICHARGE)
818  {
819  Int_t bcm_ind=-1;
820  for(Int_t itemp =0; itemp<fNumBCMs;itemp++)
821  {
822  size_t match = string(scalerloc[ivar]->name.Data()).find(string(fBCM_Name[itemp]));
823  if (match!=string::npos)
824  {
825  bcm_ind=itemp;
826  }
827  }
828 
829  if (scalerloc[ivar]->ikind == ICURRENT) {
830 
831  dvarsFirst[ivar] = 0.0;
832  dvars[ivar] = 0.0;
833 
834  if (bcm_ind != -1) {
835  Double_t cur_temp=((fScalerChan[ichan])/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];
836  cur_temp=cur_temp+fBCM_SatQuadratic[bcm_ind]*TMath::Power(TMath::Max(cur_temp-fBCM_SatOffset[i],0.0),2.0);
837  dvarsFirst[ivar] = cur_temp;
838  }
839 
840  if (bcm_ind == fbcm_Current_Threshold_Index) scal_current= dvarsFirst[ivar];
841  }
842 
843  if (scalerloc[ivar]->ikind == ICHARGE) {
844 
845  if (bcm_ind != -1) {
846  Double_t cur_temp=((fScalerChan[ichan])/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];
847  cur_temp=cur_temp+fBCM_SatQuadratic[bcm_ind]*TMath::Power(TMath::Max(cur_temp-fBCM_SatOffset[bcm_ind],0.0),2.0);
848  fBCM_delta_charge[bcm_ind]=fDeltaTime*cur_temp;
849  dvarsFirst[ivar] = fBCM_delta_charge[bcm_ind];
850  }
851  }
852  }
853  }
854  }
855  else {
856  cout << "THcHelicityScaler:: ERROR:: incorrect index "<<ivar<<" "<<idx<<" "<<ichan<<endl;
857  }
858  }
859 
860  //Calculate Scaler Quantities for ALL OTHER SCALER READS (OTHER THAN THE FIRST READ)
861  else{ // evcount != 0
862 
863  if ((ivar < scalerloc.size()) &&
864  (idx < scalers.size()) &&
865  (ichan < MAXCHAN)) {
866 
867  if (scalerloc[ivar]->ikind == ICOUNT) {
868  dvars[ivar] = fScalerChan[ichan];
869  }
870 
871  if (scalerloc[ivar]->ikind == ITIME) {
872  dvars[ivar] = fDeltaTime;
873  }
874 
875  if (scalerloc[ivar]->ikind == IRATE) {
876  dvars[ivar] = fScalerChan[ichan]/fDeltaTime;
877  }
878 
879  if(scalerloc[ivar]->ikind == ICURRENT || scalerloc[ivar]->ikind == ICHARGE)
880  {
881  Int_t bcm_ind=-1;
882  for(Int_t itemp =0; itemp<fNumBCMs;itemp++)
883  {
884  size_t match = string(scalerloc[ivar]->name.Data()).find(string(fBCM_Name[itemp]));
885  if (match!=string::npos)
886  {
887  bcm_ind=itemp;
888  }
889  }
890  if (scalerloc[ivar]->ikind == ICURRENT) {
891  dvars[ivar]=0.;
892 
893  if (bcm_ind != -1) {
894 
895  if (fDeltaTime>0) {
896  Double_t cur_temp=(fScalerChan[ichan]/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];
897  cur_temp=cur_temp+fBCM_SatQuadratic[bcm_ind]*TMath::Power(TMath::Max(cur_temp-fBCM_SatOffset[bcm_ind],0.0),2.0);
898  dvars[ivar]=cur_temp;
899  }
900  }
901  if (bcm_ind == fbcm_Current_Threshold_Index) scal_current= dvars[ivar];
902  }
903 
904  if (scalerloc[ivar]->ikind == ICHARGE) {
905 
906  if (bcm_ind != -1) {
907  dvars[ivar] = 0.0;
908 
909  if (fDeltaTime>0) {
910  Double_t cur_temp=(fScalerChan[ichan]/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];
911  cur_temp=cur_temp+fBCM_SatQuadratic[bcm_ind]*TMath::Power(TMath::Max(cur_temp-fBCM_SatOffset[bcm_ind],0.0),2.0);
912  fBCM_delta_charge[bcm_ind]=fDeltaTime*cur_temp;
913  }
914  dvars[ivar] = fBCM_delta_charge[bcm_ind];
915  }
916  }
917  }
918 
919  } else {
920  cout << "THcHelicityScaler:: ERROR:: incorrect index "<<ivar<<" "<<idx<<" "<<ichan<<endl;
921  }
922  }
923  }
924 
925  //Analyze Scaler Reads ONLY FOR SCAL_CURRENTS > BCM_CURRENT THRESHOLD
926  //(These variables have the name structure: varibaleName_Cut)
927 
928  for (size_t i = 0; i < scalerloc.size(); i++) {
929  size_t ivar = scalerloc[i]->ivar;
930  size_t ichan = scalerloc[i]->ichan;
931 
932  if (scalerloc[ivar]->ikind == ICUT+ICOUNT){
933  if ( scal_current > fbcm_Current_Threshold) {
934  dvars[ivar] = fScalerChan[ichan];
935  }
936  }
937 
938  if (scalerloc[ivar]->ikind == ICUT+ICHARGE){
939  Int_t bcm_ind=-1;
940  for(Int_t itemp =0; itemp<fNumBCMs;itemp++)
941  {
942  size_t match = string(scalerloc[ivar]->name.Data()).find(string(fBCM_Name[itemp]));
943  if (match!=string::npos)
944  {
945  bcm_ind=itemp;
946  }
947  }
948  if ( scal_current > fbcm_Current_Threshold && bcm_ind != -1) {
949  dvars[ivar] = fBCM_delta_charge[bcm_ind];
950  }
951  }
952 
953  if (scalerloc[ivar]->ikind == ICUT+ITIME){
954  if ( scal_current > fbcm_Current_Threshold) {
955  dvars[ivar] = fDeltaTime;
956  }
957  }
958 
959  }
960 
961  //--------------------------------------
962 
963  //C.Y. 12/13/2020 : Calculate the asymmetries / errors at the end of each quartet (S.A. Wood approach)
964 
965  if(actualhelicity!=0) {
966 
967  //Reset fHaveCycle to kFALSE at the start of each quartet (e.g. - + + -, + - - +
968  if(quartetphase==0) {
969  fHaveCycle[0] = fHaveCycle[1] = fHaveCycle[2] = fHaveCycle[3] = kFALSE;
970  }
971 
972  //Check if BCM scaler current is above set threshold
973  if(scal_current > fbcm_Current_Threshold && (quartetphase==0 || fHaveCycle[max(quartetphase-1,0)])) {
974  fHaveCycle[quartetphase] = kTRUE;
975 
976  //Loop over each BCM to get the charge for each cycle of a quartet
977  for(Int_t i=0; i<fNumBCMs; i++) {
978  fChargeCycle[quartetphase][i] = fBCM_delta_charge[i];
979  }
980 
981  //Loop over each Scaler Channel to the the counts for each cycle of a quartet
982  for(Int_t i=0; i<fNScalerChannels; i++) {
983  fScalCycle[quartetphase][i] = fScalerChan[i];
984  }
985 
986  //Set the time for each cycle of the quartet
987  fTimeCycle[quartetphase] = fDeltaTime;
988 
989  }
990 
991  // Compute asymmetries at the end of each quartet
992  if(quartetphase == 3 && fHaveCycle[3]) {
993 
994  //Loop over BCMs
995  for(Int_t i=0;i<fNumBCMs;i++) {
996 
997  //compute charge asymmetry for each quartet at the end of said quartet
998  Double_t asy = actualhelicity*(fChargeCycle[0][i]+fChargeCycle[3][i]
999  - fChargeCycle[1][i]-fChargeCycle[2][i]) /
1000  (fChargeCycle[0][i]+fChargeCycle[3][i]+fChargeCycle[1][i]+fChargeCycle[2][i]);
1001 
1002  fChargeSum[i] += fChargeCycle[0][i]+fChargeCycle[1][i]
1003  +fChargeCycle[2][i]+fChargeCycle[3][i];
1004 
1005  //keep track of sums for proper error calculation
1006  fChargeAsymSum[i] += asy;
1007  fChargeAsymSum2[i] += asy*asy;
1008  }
1009 
1010  //-------
1011 
1012  //Loop over Scaler Channels
1013  for(Int_t i=0; i<fNScalerChannels; i++) {
1014 
1015  //compute scaler asymmetry for each quartet at the end of said quartet
1016  Double_t asy = actualhelicity*(fScalCycle[0][i]+fScalCycle[3][i]
1017  - fScalCycle[1][i]-fScalCycle[2][i]) /
1018  (fScalCycle[0][i]+fScalCycle[3][i]+fScalCycle[1][i]+fScalCycle[2][i]);
1019 
1020  fScalSum[i] += fScalCycle[0][i]+fScalCycle[1][i]
1021  +fScalCycle[2][i]+fScalCycle[3][i];
1022 
1023  //keep track of sums for proper error calculation
1024  fScalAsymSum[i] += asy;
1025  fScalAsymSum2[i] += asy*asy;
1026  }
1027 
1028  //-------
1029 
1030  //compute time asymmetry for each quartet at the end of said quartet
1031  Double_t asy = actualhelicity*(fTimeCycle[0]+fTimeCycle[3]
1032  - fTimeCycle[1]-fTimeCycle[2]) /
1034 
1035  //keep track of total time
1036  fTimeSum += fTimeCycle[0]+fTimeCycle[1]
1037  +fTimeCycle[2]+fTimeCycle[3];
1038 
1039  //keep track of sums for proper error calculation
1040  fTimeAsymSum += asy;
1041  fTimeAsymSum2 += asy*asy;
1042 
1043  //------
1044 
1045  //keep track of the total number of quartets
1046  fQuartetCount++;
1047 
1048 
1049  }
1050 
1051 
1052  }
1053 
1054 
1055  //--------------------------------------
1056 
1057  //increment scaler reads
1058  evcount = evcount + 1;
1059  evcountR = evcount;
1060 
1061  //clear Genscaler scalers
1062  for (size_t j=0; j<scalers.size(); j++) scalers[j]->Clear("");
1063 
1064 
1065  //C.Y. 12/02/2020 Fill Scaler Tree Here
1066  if (fScalerTree) {
1067  fScalerTree->Fill();
1068  }
1069 
1070  return(0);
1071 }
1072 
1073 //_____________________________________________________________________________
1075 {
1080  UInt_t bit7 = (ranseed & 0x00000040) != 0;
1081  UInt_t bit28 = (ranseed & 0x08000000) != 0;
1082  UInt_t bit29 = (ranseed & 0x10000000) != 0;
1083  UInt_t bit30 = (ranseed & 0x20000000) != 0;
1084 
1085  UInt_t newbit = (bit30 ^ bit29 ^ bit28 ^ bit7) & 0x1;
1086 
1087  ranseed = ( (ranseed<<1) | newbit ) & 0x3FFFFFFF;
1088 
1089  return ranseed;
1090 
1091 }
1092 //_____________________________________________________________________________
1093 THaAnalysisObject::EStatus THcHelicityScaler::Init(const TDatime& date)
1094 {
1095 
1096  ReadDatabase(date);
1097  const int LEN = 200;
1098  char cbuf[LEN];
1099 
1100  fStatus = kOK;
1101  fNormIdx = -1;
1102 
1103  for( vector<UInt_t*>::iterator it = fDelayedEvents.begin();
1104  it != fDelayedEvents.end(); ++it )
1105  delete [] *it;
1106  fDelayedEvents.clear();
1107 
1108  cout << "Howdy ! We are initializing THcHelicityScaler !! name = "
1109  << fName << endl;
1110 
1111  if(eventtypes.size()==0) {
1112  eventtypes.push_back(0); // Default Event Type
1113  }
1114 
1115  if(fROC < 0) {
1116  fROC = 8; // Default to SHMS crate
1117  }
1118 
1119 
1120  //C.Y. 11/26/2020 : Read In and Parse the variables in the helicity scaler map file
1121  TString dfile;
1122  dfile = fName + "scaler.txt";
1123 
1124  TString sname0 = "Scalevt";
1125  TString sname;
1126  sname = "hel"+fName+sname0; //This should be: 'helPScalevt' or 'helHScalevt'
1127 
1128  //Open helicity scaler .dat map file
1129  FILE *fi = Podd::OpenDBFile(sname.Data(), date);
1130  if ( !fi ) {
1131  cout << "Cannot find db file for "<<fName<<" scaler event handler"<<endl;
1132  return kFileError;
1133  }
1134 
1135  size_t minus1 = -1;
1136  size_t pos1;
1137  string scomment = "#";
1138  string svariable = "variable";
1139  string smap = "map";
1140  vector<string> dbline;
1141 
1142  while( fgets(cbuf, LEN, fi) != NULL) {
1143  std::string sin(cbuf);
1144  std::string sinput(sin.substr(0,sin.find_first_of("#")));
1145  if (fDebugFile) *fDebugFile << "string input "<<sinput<<endl;
1146  dbline = Podd::vsplit(sinput);
1147  if (dbline.size() > 0) {
1148  pos1 = FindNoCase(dbline[0],scomment);
1149  if (pos1 != minus1) continue;
1150  pos1 = FindNoCase(dbline[0],svariable);
1151 
1152  if (pos1 != minus1 && dbline.size()>4) {
1153  string sdesc = "";
1154  for (size_t j=5; j<dbline.size(); j++) sdesc = sdesc+" "+dbline[j];
1155  UInt_t islot = atoi(dbline[1].c_str());
1156  UInt_t ichan = atoi(dbline[2].c_str());
1157  UInt_t ikind = atoi(dbline[3].c_str());
1158  if (fDebugFile)
1159  *fDebugFile << "add var "<<dbline[1]<<" desc = "<<sdesc<<" islot= "<<islot<<" "<<ichan<<" "<<ikind<<endl;
1160  TString tsname(dbline[4].c_str());
1161  TString tsdesc(sdesc.c_str());
1162  AddVars(tsname,tsdesc,islot,ichan,ikind);
1163  // add extra scaler which is cut on the current
1164  if (ikind == ICOUNT ||ikind == ITIME ||ikind == ICHARGE ) {
1165  tsname=tsname+"Cut";
1166  AddVars(tsname,tsdesc,islot,ichan,ICUT+ikind);
1167  }
1168  }
1169 
1170  pos1 = FindNoCase(dbline[0],smap);
1171  if (fDebugFile) *fDebugFile << "map ? "<<dbline[0]<<" "<<smap<<" "<<pos1<<" "<<dbline.size()<<endl;
1172  if (pos1 != minus1 && dbline.size()>6) {
1173  Int_t imodel, icrate, islot, inorm;
1174  UInt_t header, mask;
1175  char cdum[20];
1176  sscanf(sinput.c_str(),"%s %d %d %d %x %x %d \n",cdum,&imodel,&icrate,&islot, &header, &mask, &inorm);
1177  if ((fNormSlot >= 0) && (fNormSlot != inorm)) cout << "THcHelicityScaler::WARN: contradictory norm slot "<<fNormSlot<<" "<<inorm<<endl;
1178  fNormSlot = inorm; // slot number used for normalization. This variable is not used but is checked.
1179  Int_t clkchan = -1;
1180  Double_t clkfreq = 1;
1181  if (dbline.size()>8) {
1182  clkchan = atoi(dbline[7].c_str());
1183  clkfreq = 1.0*atoi(dbline[8].c_str());
1184  fClockChan=clkchan;
1185  fClockFreq=clkfreq;
1186  }
1187  if (fDebugFile) {
1188  *fDebugFile << "map line "<<dec<<imodel<<" "<<icrate<<" "<<islot<<endl;
1189  *fDebugFile <<" header 0x"<<hex<<header<<" 0x"<<mask<<dec<<" "<<inorm<<" "<<clkchan<<" "<<clkfreq<<endl;
1190  }
1191 
1192  switch (imodel) {
1193  case 3801: //Hall C Helicity Scalers (SIS 3801)
1194  scalers.push_back(new Scaler3801(icrate, islot));
1195  if(!fOnlyBanks) fRocSet.insert(icrate);
1196  fModuleSet.insert(imodel);
1197  break;
1198  }
1199 
1200  if (scalers.size() > 0) {
1201  UInt_t idx = scalers.size()-1;
1202  // Headers must be unique over whole event, not
1203  // just within a ROC
1204  scalers[idx]->SetHeader(header, mask);
1205  // The normalization slot has the clock in it, so we automatically recognize it.
1206  // fNormIdx is the index in scaler[] and
1207  // fNormSlot is the slot#, checked for consistency
1208  if (clkchan >= 0) {
1209  scalers[idx]->SetClock(defaultDT, clkchan, clkfreq);
1210  cout << "Setting scaler clock ... channel = "<<clkchan<<" ... freq = "<<clkfreq<<endl;
1211  if (fDebugFile) *fDebugFile <<"Setting scaler clock ... channel = "<<clkchan<<" ... freq = "<<clkfreq<<endl;
1212  fNormIdx = idx;
1213  if (islot != fNormSlot) cout << "THcHelicityScaler:: WARN: contradictory norm slot ! "<<islot<<endl;
1214 
1215  }
1216  }
1217 
1218  }
1219  }
1220 
1221  } //end while loop
1222 
1223  // can't compare UInt_t to Int_t (compiler warning), so do this
1224  nscalers=0;
1225  for (size_t i=0; i<scalers.size(); i++) nscalers++;
1226  // need to do LoadNormScaler after scalers created and if fNormIdx found
1227  if (fDebugFile) *fDebugFile <<"fNormIdx = "<<fNormIdx<<endl;
1228  if ((fNormIdx >= 0) && fNormIdx < nscalers) {
1229  for (Int_t i = 0; i < nscalers; i++) {
1230  if (i==fNormIdx) continue;
1231  scalers[i]->LoadNormScaler(scalers[fNormIdx]);
1232  }
1233  }
1234 
1235  //Called after AddVars() has been called
1236  DefVars();
1237 
1238  // Verify that the slots are not defined twice
1239  for (UInt_t i1=0; i1 < scalers.size()-1; i1++) {
1240  for (UInt_t i2=i1+1; i2 < scalers.size(); i2++) {
1241  if (scalers[i1]->GetSlot()==scalers[i2]->GetSlot())
1242  cout << "THcHelicityScaler:: WARN: same slot defined twice"<<endl;
1243  }
1244  }
1245  // Identify indices of scalers[] vector to variables.
1246  for (UInt_t i=0; i < scalers.size(); i++) {
1247  for (UInt_t j = 0; j < scalerloc.size(); j++) {
1248  if (scalerloc[j]->islot==static_cast<UInt_t>(scalers[i]->GetSlot()))
1249  scalerloc[j]->index = i;
1250  }
1251  }
1252 
1253  if(fDebugFile) *fDebugFile << "THcHelicityScaler:: Name of scaler bank "<<fName<<endl;
1254  for (size_t i=0; i<scalers.size(); i++) {
1255  if(fDebugFile) {
1256  *fDebugFile << "Scaler # "<<i<<endl;
1257  scalers[i]->SetDebugFile(fDebugFile);
1258  scalers[i]->DebugPrint(fDebugFile);
1259  }
1260  }
1261 
1262 
1263  //------Initialize Helicity Variables / Arrays-----
1264  fNTriggers = 0;
1265  fNTrigsInBuf = 0;
1266  fFirstCycle = -100;
1267  fRingSeed_reported = 0;
1268  fRingSeed_actual = 0;
1269  fNBits = 0;
1271  fHScalers[0] = new Double_t[fNScalerChannels]; //+ helicity scaler counts
1272  fHScalers[1] = new Double_t[fNScalerChannels]; //- helicity scaler counts
1273  fScalerSums = new Double_t[fNScalerChannels]; //total helicity scaler counts (hel=0, excluded)
1274  fScalerChan = new Double_t[fNScalerChannels]; //C.Y. 11/26/2020 : added array to store helicity information per channel
1275 
1276  for(Int_t i=0;i<fNScalerChannels;i++) {
1277  fHScalers[0][i] = 0.0;
1278  fHScalers[1][i] = 0.0;
1279  fScalerSums[i] = 0.0;
1280  fScalerChan[i] = 0.0;
1281  }
1282 
1283 
1284  fTimePlus = fTimeMinus = 0.0;
1285  fTriggerAsymmetry = 0.0;
1286 
1287 
1288 
1289  //------C.Y.: 12/13/2020 Initialize Variables for quartet-by-quartet asymmetries (include BCM current threshold cut)---------
1290  //(and error calculation)
1291 
1292  for(Int_t i=0; i<4; i++) {
1293 
1294  fChargeCycle[i] = new Double_t[fNumBCMs];
1296 
1297  fHaveCycle[i] = kFALSE;
1298 
1299  for(Int_t j=0; j<fNumBCMs; j++) {
1300  fChargeCycle[i][j] = 0.0;
1301  }
1302 
1303  for(Int_t j=0; j<fNScalerChannels; j++) {
1304  fScalCycle[i][j] = 0.0;
1305  }
1306 
1307  fTimeCycle[i] = 0.0;
1308 
1309  }
1310 
1311  //Initialize quartet counter
1312  fQuartetCount = 0.0;
1313 
1314  //Initialize variables for time asymmetry calculation
1315  fTimeSum = 0.0;
1316  fTimeAsymmetry = 0.0;
1317  fTimeAsymmetryError = 0.0;
1318  fTimeAsymSum = 0.0;
1319  fTimeAsymSum2 = 0.0;
1320 
1321 
1322  //Initialize variables for charge asymmetry calculation
1323  fChargeSum = new Double_t[fNumBCMs];
1328 
1329  for(Int_t i=0;i<fNumBCMs;i++) {
1330  fChargeSum[i] = 0.0;
1331  fChargeAsymmetry[i] = 0.0;
1332  fChargeAsymSum[i] = 0.0;
1333  fChargeAsymSum2[i] = 0.0;
1334  }
1335 
1336  //Initialize variables for scaler asymmetry calculation
1342 
1343  for(Int_t i=0;i<fNScalerChannels;i++) {
1344  fScalSum[i] = 0.0;
1345  fScalAsymmetry[i] = 0.0;
1346  fScalAsymSum[i] = 0.0;
1347  fScalAsymSum2[i] = 0.0;
1348  }
1349 
1350 
1351  //------------------------------------------------------------------------------------------
1352 
1353 
1354  //Call MakeParms() to define variables to be used in report file
1355  MakeParms();
1356 
1357  return kOK;
1358 }
1359 
1361 {
1362 
1363  //Put Various helicity scaler results in gHcParms so they can be included in results.
1364 
1365  //no bcm cut required
1366  gHcParms->Define(Form("g%s_hscaler_plus[%d]",fName.Data(),fNScalerChannels),
1367  "Plus Helcity Scalers",*(fHScalers[0]));
1368 
1369  gHcParms->Define(Form("g%s_hscaler_minus[%d]",fName.Data(),fNScalerChannels),
1370  "Minus Helcity Scalers",*(fHScalers[1]));
1371 
1372  //gHcParms->Define(Form("g%s_hscaler_sum[%d]",fName.Data(),fNScalerChannels),
1373  // "Helcity Scalers Sum",*fScalerSums);
1374 
1375  gHcParms->Define(Form("g%s_hscaler_triggers",fName.Data()),
1376  "Total Helicity Scaler Triggers",fNTriggers);
1377 
1378  gHcParms->Define(Form("g%s_hscaler_triggers_plus",fName.Data()),
1379  "Positive Helicity Scaler Triggers",fNTriggersPlus);
1380 
1381  gHcParms->Define(Form("g%s_hscaler_triggers_minus",fName.Data()),
1382  "Negative Helicity Scaler Triggers",fNTriggersMinus);
1383 
1384  gHcParms->Define(Form("g%s_hscaler_trigger_asy",fName.Data()),
1385  "Helicity Trigger Asymmetry",fTriggerAsymmetry);
1386 
1387  //gHcParms->Define(Form("g%s_hscaler_time_plus",fName.Data()),
1388  // "Positive Helicity Time",fTimePlus);
1389 
1390  //gHcParms->Define(Form("g%s_hscaler_time_minus",fName.Data()),
1391  // "Negative Helicity Time",fTimeMinus);
1392 
1393  //bcm cut
1394  gHcParms->Define(Form("g%s_hscaler_sum[%d]",fName.Data(),fNScalerChannels),
1395  "Helcity Scalers Sum",*fScalSum);
1396 
1397  gHcParms->Define(Form("g%s_hscaler_asy[%d]",fName.Data(),fNScalerChannels),
1398  "Helicity Scaler Asymmetry[%d]",*fScalAsymmetry);
1399 
1400  gHcParms->Define(Form("g%s_hscaler_asyerr[%d]",fName.Data(),fNScalerChannels),
1401  "Helicity Scaler Asymmetry Error[%d]",*fScalAsymmetryError);
1402 
1403  gHcParms->Define(Form("g%s_hscaler_charge[%d]",fName.Data(),fNumBCMs),
1404  "Helicity Gated Charge",*fChargeSum);
1405 
1406  gHcParms->Define(Form("g%s_hscaler_charge_asy[%d]",fName.Data(),fNumBCMs),
1407  "Helicity Gated Charge Asymmetry",*fChargeAsymmetry);
1408 
1409  gHcParms->Define(Form("g%s_hscaler_charge_asyerr[%d]",fName.Data(),fNumBCMs),
1410  "Helicity Gated Charge Asymmetry Error",*fChargeAsymmetryError);
1411 
1412  gHcParms->Define(Form("g%s_hscaler_time",fName.Data()),
1413  "Helicity Gated Time (sec)",fTimeSum);
1414 
1415  gHcParms->Define(Form("g%s_hscaler_time_asy",fName.Data()),
1416  "Helicity Gated Time Asymmetry",fTimeAsymmetry);
1417 
1418  gHcParms->Define(Form("g%s_hscaler_time_asyerr",fName.Data()),
1419  "Helicity Gated Time Asymmetry Error",fTimeAsymmetryError);
1420 
1421 
1422 
1423 }
1424 
1425 
1426 
1427 //--------------------C.Y. Sep 20, 2020 : Added Utility Functions--------------------
1428 
1430  UInt_t ichan, UInt_t ikind)
1431 {
1432  if (fDebugFile) *fDebugFile << "C.Y. | Calling THcHelicityScaler::AddVars() "<<endl;
1433  // need to add fName here to make it a unique variable. (Left vs Right HRS, for example)
1434  TString name1 = fName + name;
1435  TString desc1 = fName + desc;
1436  // We don't yet know the correspondence between index of scalers[] and slots.
1437  // Will put that in later.
1438  scalerloc.push_back( new HCScalerLoc(name1, desc1, 0, islot, ichan, ikind,
1439  scalerloc.size()) );
1440 }
1441 
1443 {
1444  if (fDebugFile) *fDebugFile << "C.Y. | Calling THcHelicityScaler::DefVars() "<<endl;
1445  // called after AddVars has finished being called.
1446  Nvars = scalerloc.size();
1447  if (Nvars == 0) return;
1448  dvars = new Double_t[Nvars]; // dvars is a member of this class
1449  dvarsFirst = new Double_t[Nvars]; // dvarsFirst is a member of this class
1450  memset(dvars, 0, Nvars*sizeof(Double_t));
1451  memset(dvarsFirst, 0, Nvars*sizeof(Double_t));
1452  if (gHaVars) {
1453  if(fDebugFile) *fDebugFile << "THcScalerEVtHandler:: Have gHaVars "<<gHaVars<<endl;
1454  } else {
1455  cout << "No gHaVars ?! Well, that's a problem !!"<<endl;
1456  return;
1457  }
1458  if(fDebugFile) *fDebugFile << "THcHelicityScaler:: scalerloc size "<<scalerloc.size()<<endl;
1459  const Int_t* count = 0;
1460  for (size_t i = 0; i < scalerloc.size(); i++) {
1461  gHaVars->DefineByType(scalerloc[i]->name.Data(), scalerloc[i]->description.Data(),
1462  &dvars[i], kDouble, count);
1463  }
1464 }
1465 
1466 size_t THcHelicityScaler::FindNoCase(const string& sdata, const string& skey)
1467 {
1468  // Find iterator of word "sdata" where "skey" starts. Case insensitive.
1469  string sdatalc, skeylc;
1470  sdatalc = ""; skeylc = "";
1471  for (string::const_iterator p =
1472  sdata.begin(); p != sdata.end(); ++p) {
1473  sdatalc += tolower(*p);
1474  }
1475  for (string::const_iterator p =
1476  skey.begin(); p != skey.end(); ++p) {
1477  skeylc += tolower(*p);
1478  }
1479  if (sdatalc.find(skeylc,0) == string::npos) return -1;
1480  return sdatalc.find(skeylc,0);
1481 };
1482 
1483 //---------------------------------------------------------------------------------
1484 
1485 
Double_t * fBCM_SatQuadratic
Double_t * fChargeAsymSum2
THcHelicityScaler(const char *, const char *)
Double_t fbcm_Current_Threshold
Int_t AnalyzeBuffer(UInt_t *rdata)
Double_t * fBCM_delta_charge
Double_t * fScalCycle[4]
virtual Int_t Fill()
Event handler for Hall C helicity scalers.
Double_t * fChargeCycle[4]
Int_t fHelicityHistory[200]
std::vector< std::string > fBCM_Name
virtual Int_t End(THaRunBase *r=0)
virtual void SetAutoSave(Long64_t autos=-300000000)
UInt_t GetEvNum() const
int Int_t
bool Bool_t
STL namespace.
std::vector< UInt_t * > fDelayedEvents
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
static const UInt_t defaultDT
const char * Data() const
Double_t * fHScalers[2]
static Bool_t Initialized()
static const UInt_t MAXCHAN
UInt_t GetEvLength() const
double sin(double)
const UInt_t * GetRawDataBuffer() const
Double_t * fChargeAsymmetry
virtual Int_t Write(const char *name=0, Int_t option=0, Int_t bufsize=0)
static const UInt_t ITIME
Int_t AnalyzeHelicityScaler(UInt_t *p)
void AddVars(TString name, TString desc, UInt_t iscal, UInt_t ichan, UInt_t ikind)
unsigned int UInt_t
char * Form(const char *fmt,...)
std::vector< Decoder::GenScaler * > scalers
const std::string sname
static const UInt_t ICOUNT
Int_t Analyze(THaEvData *evdata)
tuple list
Definition: SConscript.py:9
const Bool_t kFALSE
static size_t FindNoCase(const std::string &sdata, const std::string &skey)
static const UInt_t IRATE
Int_t LoadParmValues(const DBRequest *list, const char *prefix="")
Retrieve parameter values from the parameter cache.
double Double_t
virtual Int_t ReadDatabase(const TDatime &date)
UInt_t GetEvType() const
std::set< UInt_t > fRocSet
ClassImp(THcDCLookupTTDConv) THcDCLookupTTDConv
std::vector< HCScalerLoc * > scalerloc
Double_t * fChargeAsymmetryError
virtual Int_t Branch(TCollection *list, Int_t bufsize=32000, Int_t splitlevel=99, const char *name="")
virtual EStatus Init(const TDatime &run_time)
Short_t Max(Short_t a, Short_t b)
static const UInt_t ICURRENT
static const UInt_t ICUT
R__EXTERN class THcParmList * gHcParms
Definition: THcGlobals.h:11
Int_t RanBit30(Int_t ranseed)
Double_t Sqrt(Double_t x)
std::set< UInt_t > fModuleSet
virtual void SetDelayedType(int evtype)
const Bool_t kTRUE
static const UInt_t ICHARGE
Double_t * fScalAsymmetryError
char name[80]