JAPAn
Just Another Parity Analyzer
Loading...
Searching...
No Matches
QwMollerADC_Channel.cc
Go to the documentation of this file.
1/*!
2 * \file QwMollerADC_Channel.cc
3 * \brief Implementation for Moller ADC channel decoding and management
4 */
5
7
8// System headers
9#include <stdexcept>
10#include "TMath.h"
11
12// Qweak headers
13#include "QwLog.h"
14#include "QwUnits.h"
15#include "QwBlinder.h"
16#include "QwHistogramHelper.h"
17#ifdef __USE_DATABASE__
18#include "QwDBInterface.h"
19#endif
20
21const Bool_t QwMollerADC_Channel::kDEBUG = kFALSE;
22
25
26const Double_t QwMollerADC_Channel::kTimePerSample = (2.0/30.0) * Qw::us; //2.0 originally
27
28/*! Conversion factor to translate the average bit count in an ADC
29 * channel into average voltage.
30 * The base factor is roughly 76 uV per count, and zero counts corresponds
31 * to zero voltage.
32 * Store as the exact value for 20 V range, 18 bit ADC.
33 */
34const Double_t QwMollerADC_Channel::kMollerADC_VoltsPerBit = (20./(1<<18));
35
36/*! Static member function to return the word offset within a data buffer
37 * given the module number index and the channel number index.
38 * @param moduleindex Module index within this buffer; counts from zero
39 * @param channelindex Channel index within this module; counts from zero
40 * @return The number of words offset to the beginning of this
41 * channel's data from the beginning of the MollerADC buffer.
42 */
43Int_t QwMollerADC_Channel::GetBufferOffset(Int_t moduleindex, Int_t channelindex){
44 Int_t offset = -1;
45 if (moduleindex<0 ){
46 QwError << "QwMollerADC_Channel::GetBufferOffset: Invalid module index,"
47 << moduleindex
48 << ". Must be zero or greater."
49 << QwLog::endl;
50 } else if (channelindex<0 || channelindex>kMaxChannels){
51 QwError << "QwMollerADC_Channel::GetBufferOffset: Invalid channel index,"
52 << channelindex
53 << ". Must be in range [0," << kMaxChannels << "]."
54 << QwLog::endl;
55 } else {
56 offset = ( (moduleindex * kMaxChannels) + channelindex )
58 }
59 return offset;
60 }
61
62
63/********************************************************/
65{
66 Bool_t fEventIsGood=kTRUE;
67 Bool_t bStatus;
68 if (bEVENTCUTMODE>0){//Global switch to ON/OFF event cuts set at the event cut file
69
70 if (bDEBUG)
71 QwWarning<<" QwQWVK_Channel "<<GetElementName()<<" "<<GetNumberOfSamples()<<QwLog::endl;
72
73 // Sample size check
74 bStatus = MatchNumberOfSamples(fNumberOfSamples_map);//compare the default sample size with no.of samples read by the module
75 if (!bStatus) {
77 }
78
79 // Check SW and HW return the same sum
80 bStatus = (GetRawHardwareSum() == GetRawSoftwareSum());
81 //fEventIsGood = bStatus;
82 if (!bStatus) {
84 }
85
86
87
88 //check sequence number
90 if (fSequenceNo_Counter==0 || GetSequenceNumber()==0){//starting the data run
92 }
93
94 if (!MatchSequenceNumber(fSequenceNo_Prev)){//we have a sequence number error
95 fEventIsGood=kFALSE;
97 if (bDEBUG) QwWarning<<" QwQWVK_Channel "<<GetElementName()<<" Sequence number previous value = "<<fSequenceNo_Prev<<" Current value= "<< GetSequenceNumber()<<QwLog::endl;
98 }
99
101
102 //Checking for HW_sum is returning same value.
104 //std::cout<<" BCM hardware sum is different "<<std::endl;
107 }else
108 fADC_Same_NumEvt++;//hw_sum is same increment the counter
109
110 //check for the hw_sum is giving the same value
111 if (fADC_Same_NumEvt>0){//we have ADC stuck with same value
112 if (bDEBUG) QwWarning<<" BCM hardware sum is same for more than "<<fADC_Same_NumEvt<<" time consecutively "<<QwLog::endl;
114 }
115
116 //check for the hw_sum is zero
117 if (GetRawHardwareSum()==0){
119 }
120 if (!fEventIsGood)
121 fSequenceNo_Counter=0;//resetting the counter after ApplyHWChecks() a failure
122
124 if (bDEBUG)
125 QwWarning << this->GetElementName()<<" "<<GetRawHardwareSum() << "Saturating MollerADC invoked! " <<TMath::Abs(GetRawHardwareSum())*kMollerADC_VoltsPerBit/fNumberOfSamples<<" Limit "<<GetMollerADCSaturationLimt() << QwLog::endl;
127 }
128
129 }
130 else {
131 fGoodEventCount = 1;
132 fErrorFlag = 0;
133 }
134
135 return fErrorFlag;
136}
137
138
139/********************************************************/
142 fErrorCount_sample++; //increment the hw error counter
144 fErrorCount_SW_HW++; //increment the hw error counter
146 fErrorCount_Sequence++; //increment the hw error counter
148 fErrorCount_SameHW++; //increment the hw error counter
150 fErrorCount_ZeroHW++; //increment the hw error counter
152 fErrorCount_HWSat++; //increment the hw saturation error counter
155 fNumEvtsWithEventCutsRejected++; //increment the event cut error counter
156 }
157}
158
159/********************************************************/
160
161void QwMollerADC_Channel::InitializeChannel(TString name, TString datatosave)
162{
163 SetElementName(name);
164 SetDataToSave(datatosave);
167
168 kFoundPedestal = 0;
169 kFoundGain = 0;
170
171 fPedestal = 0.0;
172 fCalibrationFactor = 1.0;
173
174 fBlocksPerEvent = 4;
175
176 fTreeArrayIndex = 0;
178
180
184
185 // Use internal random variable by default
187
188 // Mock drifts
189 fMockDriftAmplitude.clear();
190 fMockDriftFrequency.clear();
191 fMockDriftPhase.clear();
192
193 // Mock asymmetries
194 fMockAsymmetry = 0.0;
195 fMockGaussianMean = 0.0;
196 fMockGaussianSigma = 0.0;
197
198 // Event cuts
199 fULimit=-1;
200 fLLimit=1;
202
203 fErrorFlag=0; //Initialize the error flag
204 fErrorConfigFlag=0; //Initialize the error config. flag
205
206 //init error counters//
213
218
219 fGoodEventCount = 0;
220
221 bEVENTCUTMODE = 0;
222
223 return;
224}
225
226/********************************************************/
227
228void QwMollerADC_Channel::InitializeChannel(TString subsystem, TString instrumenttype, TString name, TString datatosave){
229 InitializeChannel(name,datatosave);
230 SetSubsystemName(subsystem);
231 SetModuleType(instrumenttype);
232 //PrintInfo();
233}
234
236 UInt_t value = 0;
237 if (paramfile.ReturnValue("sample_size",value)){
239 } else {
240 QwWarning << "MollerADC Channel "
241 << GetElementName()
242 << " cannot set the default sample size."
243 << QwLog::endl;
244 }
245};
246
247
249{
250 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
251 fBlock_raw[i] = 0;
252 fBlockSumSq_raw[i] = 0;
253 fBlock_min[i] = 0;
254 fBlock_max[i] = 0;
255 fBlock[i] = 0.0;
256 fBlockM2[i] = 0.0;
257 fBlockError[i] = 0.0;
258 }
261 fHardwareBlockSum = 0.0;
264 fSequenceNumber = 0;
266 fGoodEventCount = 0;
267 fErrorFlag=0;
268 return;
269}
270
271void QwMollerADC_Channel::RandomizeEventData(int helicity, double time)
272{
273 // updated to calculate the drift for each block individually
274 Double_t drift = 0.0;
275 for (Int_t i = 0; i < fBlocksPerEvent; i++){
276 drift = 0.0;
277 if (i >= 1){
279 }
280 for (UInt_t i = 0; i < fMockDriftFrequency.size(); i++) {
281 drift += fMockDriftAmplitude[i] * sin(2.0 * Qw::pi * fMockDriftFrequency[i] * time + fMockDriftPhase[i]);
282 //std::cout << "Drift: " << drift << std::endl;
283 }
284 }
285
286 // Calculate signal
287 fHardwareBlockSum = 0.0;
288 fHardwareBlockSumM2 = 0.0; // second moment is zero for single events
289 fBlock_max[4] = kMinInt;
290 fBlock_min[4] = kMaxInt;
291
292 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
293 double tmpvar = GetRandomValue();
294
295 fBlock[i] = fMockGaussianMean + drift;
296
298 fBlock[i] += helicity*fMockAsymmetry;
299 } else {
300 fBlock[i] *= 1.0 + helicity*fMockAsymmetry;
301 }
302 fBlock[i] += fMockGaussianSigma*tmpvar*sqrt(fBlocksPerEvent);
303 fBlockM2[i] = 0.0; // second moment is zero for single events
305
306 }
308 fSequenceNumber = 0;
310 // SetEventData(block);
311 // delete block;
312 return;
313}
314
316
317 fHardwareBlockSum = 0.0;
318 fHardwareBlockSumM2 = 0.0; // second moment is zero for single events
319 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
320
321 fBlock[i] += resolution*sqrt(fBlocksPerEvent) * GetRandomValue();
322
323 fBlockM2[i] = 0.0; // second moment is zero for single events
325 }
326 // std::cout << std::endl;
328
330 // SetRawEventData();
331 return;
332}
333
334void QwMollerADC_Channel::SetHardwareSum(Double_t hwsum, UInt_t sequencenumber)
335{
336 Double_t* block = new Double_t[fBlocksPerEvent];
337 for (Int_t i = 0; i < fBlocksPerEvent; i++){
338 block[i] = hwsum / fBlocksPerEvent;
339 }
340 SetEventData(block);
341 delete[] block;
342 return;
343}
344
345
346// SetEventData() is used by the mock data generator to turn "model"
347// data values into their equivalent raw data. It should be used
348// nowhere else. -- pking, 2010-09-16
349
350void QwMollerADC_Channel::SetEventData(Double_t* block, UInt_t sequencenumber)
351{
352 fHardwareBlockSum = 0.0;
353 fHardwareBlockSumM2 = 0.0; // second moment is zero for single events
354 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
355 fBlock[i] = block[i];
356 fBlockM2[i] = 0.0; // second moment is zero for single events
357 fHardwareBlockSum += block[i];
358 }
360
361 fSequenceNumber = sequencenumber;
363
364// Double_t thispedestal = 0.0;
365// thispedestal = fPedestal * fNumberOfSamples;
366
368 return;
369}
370
371__attribute__((no_sanitize("signed-integer-overflow")))
372void QwMollerADC_Channel::SetRawEventData(){
373 fNumberOfSamples = fNumberOfSamples_map;
374 fHardwareBlockSum_raw = 0;
375// Double_t hwsum_test = 0.0;
376// std::cout << "*******In QwMollerADC_Channel::SetRawEventData for channel:\t" << this->GetElementName() << std::endl;
377 for (Int_t i = 0; i < fBlocksPerEvent; i++)
378 {
379 Double_t block_raw = (fBlock[i] / fCalibrationFactor + fPedestal) * fNumberOfSamples / (fBlocksPerEvent * 1.0);
380 if (std::abs(block_raw) >= pow(2,29)) {
381 block_raw = std::copysign(pow(2,29)-1, block_raw);
382 QwWarning << "QwMollerADC_Channel::SetRawEventData: Overflow in conversion to raw data for channel "
383 << this->GetElementName() << ": ("
384 << "fBlock[i] = " << fBlock[i] << " / "
385 << "fCalibrationFactor = " << fCalibrationFactor << " + "
386 << "fPedestal = " << fPedestal << ") * "
387 << "fNumberOfSamples = " << fNumberOfSamples << " / "
388 << "fBlocksPerEvent = " << fBlocksPerEvent << ". "
389 << "Capping value to " << block_raw << "."
390 << QwLog::endl;
391 }
392 fBlock_raw[i] = Int_t(block_raw);
393 fHardwareBlockSum_raw += fBlock_raw[i];
394
395 double_t block = fBlock[i] / fCalibrationFactor;
396 double_t sigma = fMockGaussianSigma / fCalibrationFactor;
397 fBlockSumSq_raw[i] = (sigma*sigma + block*block)*fNumberOfSamples_map / (fBlocksPerEvent * 1.0);
398 fBlock_min[i] = (block - 3.0 * sigma) * double_t(fNumberOfSamples_map) / (fBlocksPerEvent * 1.0);
399 fBlock_max[i] = (block + 3.0 * sigma) * double_t(fNumberOfSamples_map) / (fBlocksPerEvent * 1.0);
400
401 fBlockSumSq_raw[4] += fBlockSumSq_raw[i];
402 fBlock_min[4] = TMath::Min(fBlock_min[i],fBlock_min[4]);
403 fBlock_max[4] = TMath::Max(fBlock_max[i],fBlock_max[4]);
404 }
405
406
407
408 fSoftwareBlockSum_raw = fHardwareBlockSum_raw;
409
410 return;
411}
412
413void QwMollerADC_Channel::EncodeEventData(std::vector<UInt_t> &buffer)
414{
415 Long_t localbuf[kWordsPerChannel] = {0};
416
417 if (IsNameEmpty()) {
418 // This channel is not used, but is present in the data stream.
419 // Skip over this data.
420 } else {
421 // localbuf[4] = 0;
422 for (Int_t i = 0; i < 4; i++) {
423 localbuf[i*5] = fBlock_raw[i];
424 localbuf[i*5+1] = fBlockSumSq_raw[i] & 0xffffffff;
425 localbuf[i*5+2] = fBlockSumSq_raw[i] >> 32;
426 localbuf[i*5+3] = fBlock_min[i];
427 localbuf[i*5+4] = fBlock_max[i];
428
429 // localbuf[4] += localbuf[i]; // fHardwareBlockSum_raw
430 }
431 // The following causes many rounding errors and skips due to the check
432 // that fHardwareBlockSum_raw == fSoftwareBlockSum_raw in IsGoodEvent().
433 localbuf[20] = fHardwareBlockSum_raw;
434 localbuf[21] = fBlockSumSq_raw[4] & 0xffffffff;
435 localbuf[22] = fBlockSumSq_raw[4] >> 32;
436 localbuf[23] = fBlock_min[4];
437 localbuf[24] = fBlock_max[4];
438 localbuf[25] = (fNumberOfSamples << 16 & 0xFFFF0000)
439 | (fSequenceNumber << 8 & 0x0000FF00);
440
441 for (Int_t i = 0; i < kWordsPerChannel; i++){
442 buffer.push_back(localbuf[i]);
443 }
444 }
445}
446
447
448
449Int_t QwMollerADC_Channel::ProcessEvBuffer(UInt_t* buffer, UInt_t num_words_left, UInt_t index)
450{
451 UInt_t words_read = 0;
452 UInt_t localbuf[kWordsPerChannel] = {0};
453 // The conversion from UInt_t to Double_t discards the sign, so we need an intermediate
454 // static_cast from UInt_t to Int_t.
455 Int_t localbuf_signed[kWordsPerChannel] = {0};
456
457 if (IsNameEmpty()){
458 // This channel is not used, but is present in the data stream.
459 // Skip over this data.
460 words_read = fNumberOfDataWords;
461 } else if (num_words_left >= fNumberOfDataWords)
462 {
463 for (Int_t i=0; i<kWordsPerChannel; i++){
464 localbuf[i] = buffer[i];
465 localbuf_signed[i] = static_cast<Int_t>(localbuf[i]);
466 }
467
469 for (Int_t i=0; i<fBlocksPerEvent; i++){
470 fBlock_raw[i] = localbuf_signed[i*5];
471 fBlockSumSq_raw[i] = localbuf_signed[i*5+1];
472 fBlockSumSq_raw[i] += Long64_t (localbuf_signed[i*5+2]) << 32;
473 fBlock_min[i] = localbuf_signed[i*5+3];
474 fBlock_max[i] = localbuf_signed[i*5+4];
476 }
477 fHardwareBlockSum_raw = localbuf_signed[20];
478
479 /* Permanent change in the structure of the 6th word of the ADC readout.
480 * The upper 16 bits are the number of samples, and the upper 8 of the
481 * lower 16 are the sequence number. This matches the structure of
482 * the ADC readout in block read mode, and now also in register read mode.
483 * P.King, 2007sep04.
484 */
485 fSequenceNumber = (localbuf[25]>>8) & 0xFF;
486 fNumberOfSamples = (localbuf[25]>>16) & 0xFFFF;
487
488 words_read = fNumberOfDataWords;
489
490 } else
491 {
492 std::cerr << "QwMollerADC_Channel::ProcessEvBuffer: Not enough words!"
493 << std::endl;
494 }
495 return words_read;
496}
497
498
499
501{
502 if (fNumberOfSamples == 0 && fHardwareBlockSum_raw == 0) {
503 // There isn't valid data for this channel. Just flag it and
504 // move on.
505 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
506 fBlock[i] = 0.0;
507 fBlockM2[i] = 0.0;
508 }
509 fHardwareBlockSum = 0.0;
512 } else if (fNumberOfSamples == 0) {
513 // This is probably a more serious problem.
514 QwWarning << "QwMollerADC_Channel::ProcessEvent: Channel "
515 << this->GetElementName().Data()
516 << " has fNumberOfSamples==0 but has valid data in the hardware sum. "
517 << "Flag this as an error."
518 << QwLog::endl;
519 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
520 fBlock[i] = 0.0;
521 fBlockM2[i] = 0.0;
522 }
523 fHardwareBlockSum = 0.0;
526 } else {
527 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
529 fBlockM2[i] = 0.0; // second moment is zero for single events
530 }
532 fHardwareBlockSumM2 = 0.0; // second moment is zero for single events
533 }
534 return;
535}
536
538{
539 //Double_t avgVolts = (fBlock[0]+fBlock[1]+fBlock[2]+fBlock[3])*kMollerADC_VoltsPerBit/fNumberOfSamples;
541 //std::cout<<"QwMollerADC_Channel::GetAverageVolts() = "<<avgVolts<<std::endl;
542 return avgVolts;
543
544}
545
547{
548 std::cout<<"***************************************"<<"\n";
549 std::cout<<"Subsystem "<<GetSubsystemName()<<"\n"<<"\n";
550 std::cout<<"Beam Instrument Type: "<<GetModuleType()<<"\n"<<"\n";
551 std::cout<<"QwMollerADC channel: "<<GetElementName()<<"\n"<<"\n";
552 std::cout<<"fPedestal= "<< fPedestal<<"\n";
553 std::cout<<"fCalibrationFactor= "<<fCalibrationFactor<<"\n";
554 std::cout<<"fBlocksPerEvent= "<<fBlocksPerEvent<<"\n"<<"\n";
555 std::cout<<"fSequenceNumber= "<<fSequenceNumber<<"\n";
556 std::cout<<"fNumberOfSamples= "<<fNumberOfSamples<<"\n";
557 std::cout<<"fBlock_raw ";
558
559 for (Int_t i = 0; i < fBlocksPerEvent; i++)
560 std::cout << " : " << fBlock_raw[i];
561 std::cout<<"\n";
562 std::cout<<"fHardwareBlockSum_raw= "<<fHardwareBlockSum_raw<<"\n";
563 std::cout<<"fSoftwareBlockSum_raw= "<<fSoftwareBlockSum_raw<<"\n";
564 std::cout<<"fBlock ";
565 for (Int_t i = 0; i < fBlocksPerEvent; i++)
566 std::cout << " : " <<std::setprecision(8) << fBlock[i];
567 std::cout << std::endl;
568
569 std::cout << "fHardwareBlockSum = "<<std::setprecision(8) <<fHardwareBlockSum << std::endl;
570 std::cout << "fHardwareBlockSumM2 = "<<fHardwareBlockSumM2 << std::endl;
571 std::cout << "fHardwareBlockSumError = "<<fHardwareBlockSumError << std::endl;
572
573 return;
574}
575
576void QwMollerADC_Channel::ConstructHistograms(TDirectory *folder, TString &prefix)
577{
578 // If we have defined a subdirectory in the ROOT file, then change into it.
579 if (folder != NULL) folder->cd();
580
581 if (IsNameEmpty()){
582 // This channel is not used, so skip filling the histograms.
583 } else {
584 // Now create the histograms.
585 SetDataToSaveByPrefix(prefix);
586
587 TString basename = prefix + GetElementName();
588
589 if(fDataToSave==kRaw)
590 {
591 fHistograms.resize(8+2+1, NULL);
592 size_t index=0;
593 for (Int_t i=0; i<fBlocksPerEvent; i++){
594 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_block%d_raw",i));
595 fHistograms[index+1] = gQwHists.Construct1DHist(basename+Form("_block%d",i));
596 index += 2;
597 }
598 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_hw_raw"));
599 fHistograms[index+1] = gQwHists.Construct1DHist(basename+Form("_hw"));
600 index += 2;
601 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_sw-hw_raw"));
602 }
603 else if(fDataToSave==kDerived)
604 {
605 fHistograms.resize(4+1+1, NULL);
606 Int_t index=0;
607 for (Int_t i=0; i<fBlocksPerEvent; i++){
608 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_block%d",i));
609 index += 1;
610 }
611 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_hw"));
612 index += 1;
613 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_dev_err"));
614 index += 1;
615 }
616 else
617 {
618 // this is not recognized
619 }
620
621 }
622}
623
625{
626 Int_t index=0;
627
628 if (IsNameEmpty())
629 {
630 // This channel is not used, so skip creating the histograms.
631 } else
632 {
633 if(fDataToSave==kRaw)
634 {
635 for (Int_t i=0; i<fBlocksPerEvent; i++)
636 {
637 if (fHistograms[index] != NULL && (fErrorFlag)==0)
638 fHistograms[index]->Fill(this->GetRawBlockValue(i));
639 if (fHistograms[index+1] != NULL && (fErrorFlag)==0)
640 fHistograms[index+1]->Fill(this->GetBlockValue(i));
641 index+=2;
642 }
643 if (fHistograms[index] != NULL && (fErrorFlag)==0)
644 fHistograms[index]->Fill(this->GetRawHardwareSum());
645 if (fHistograms[index+1] != NULL && (fErrorFlag)==0)
646 fHistograms[index+1]->Fill(this->GetHardwareSum());
647 index+=2;
648 if (fHistograms[index] != NULL && (fErrorFlag)==0)
649 fHistograms[index]->Fill(this->GetRawSoftwareSum()-this->GetRawHardwareSum());
650 }
651 else if(fDataToSave==kDerived)
652 {
653 for (Int_t i=0; i<fBlocksPerEvent; i++)
654 {
655 if (fHistograms[index] != NULL && (fErrorFlag)==0)
656 fHistograms[index]->Fill(this->GetBlockValue(i));
657 index+=1;
658 }
659 if (fHistograms[index] != NULL && (fErrorFlag)==0)
660 fHistograms[index]->Fill(this->GetHardwareSum());
661 index+=1;
662 if (fHistograms[index] != NULL){
664 fHistograms[index]->Fill(kErrorFlag_sample);
666 fHistograms[index]->Fill(kErrorFlag_SW_HW);
668 fHistograms[index]->Fill(kErrorFlag_Sequence);
670 fHistograms[index]->Fill(kErrorFlag_ZeroHW);
672 fHistograms[index]->Fill(kErrorFlag_VQWK_Sat);
674 fHistograms[index]->Fill(kErrorFlag_SameHW);
675 }
676
677 }
678
679 }
680}
681
683{
684 // This channel is not used, so skip setting up the tree.
685 if (IsNameEmpty()) return;
686
687 // Decide what to store based on prefix
688 SetDataToSaveByPrefix(prefix);
689
690 TString basename = prefix(0, (prefix.First("|") >= 0)? prefix.First("|"): prefix.Length()) + GetElementName();
691 fTreeArrayIndex = values.size();
692
693 TString list = "";
694
695 bHw_sum = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "hw_sum");
696 bHw_sum_raw = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "hw_sum_raw");
697 bBlock = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "block");
698 bBlock_raw = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "block_raw");
699 bNum_samples = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "num_samples");
700 bDevice_Error_Code = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "Device_Error_Code");
701 bSequence_number = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "sequence_number");
702
703 if (bHw_sum) {
704 values.push_back("hw_sum", 'D');
705 if (fDataToSave == kMoments) {
706 values.push_back("hw_sum_m2", 'D');
707 values.push_back("hw_sum_err", 'D');
708 }
709 }
710
711 if (bBlock) {
712 values.push_back("block0", 'D');
713 values.push_back("block1", 'D');
714 values.push_back("block2", 'D');
715 values.push_back("block3", 'D');
716 }
717
718 if (bNum_samples) {
719 values.push_back("num_samples", 'i');
720 }
721
722 if (bDevice_Error_Code) {
723 values.push_back("Device_Error_Code", 'i');
724 }
725
726 if (fDataToSave == kRaw) {
727 if (bHw_sum_raw) {
728 values.push_back("hw_sum_raw", 'I');
729 }
730 if (bBlock_raw) {
731 values.push_back("block0_raw", 'I');
732 values.push_back("block1_raw", 'I');
733 values.push_back("block2_raw", 'I');
734 values.push_back("block3_raw", 'I');
735 }
736
737 for (int i = 0; i < 4; i++) {
738 if (bBlock_raw) {
739 values.push_back(Form("SumSq_%d", i), 'L');
740 values.push_back(Form("RawMin_%d", i), 'I');
741 values.push_back(Form("RawMax_%d", i), 'I');
742 }
743 }
744
745 if (bSequence_number) {
746 values.push_back("sequence_number", 'i');
747 }
748 }
749
750 std::string leaf_list = values.LeafList(fTreeArrayIndex);
751
753
754 if (gQwHists.MatchDeviceParamsFromList(basename.Data())
757
758 // This is for the RT mode
759 if (leaf_list == "hw_sum/D")
760 leaf_list = basename+"/D";
761
762 if (kDEBUG)
763 QwMessage << "base name " << basename << " List " << leaf_list << QwLog::endl;
764
765 tree->Branch(basename, &(values[fTreeArrayIndex]), leaf_list.c_str());
766 }
767
768 if (kDEBUG) {
769 std::cerr << "QwMollerADC_Channel::ConstructBranchAndVector: fTreeArrayIndex==" << fTreeArrayIndex
770 << "; fTreeArrayNumEntries==" << fTreeArrayNumEntries
771 << "; values.size()==" << values.size()
772 << "; list==" << leaf_list
773 << std::endl;
774 }
775}
776
777void QwMollerADC_Channel::ConstructBranch(TTree *tree, TString &prefix)
778{
779 // This channel is not used, so skip setting up the tree.
780 if (IsNameEmpty()) return;
781
782 TString basename = prefix + GetElementName();
783 tree->Branch(basename,&fHardwareBlockSum,basename+"/D");
784 if (kDEBUG){
785 std::cerr << "QwMollerADC_Channel::ConstructBranchAndVector: fTreeArrayIndex==" << fTreeArrayIndex
786 << "; fTreeArrayNumEntries==" << fTreeArrayNumEntries
787 << std::endl;
788 }
789}
790
791
793{
794 if (IsNameEmpty()) {
795 // This channel is not used, so skip filling the tree vector.
796 } else if (fTreeArrayNumEntries <= 0) {
797 if (bDEBUG) std::cerr << "QwMollerADC_Channel::FillTreeVector: fTreeArrayNumEntries=="
798 << fTreeArrayNumEntries << std::endl;
799 } else if (values.size() < fTreeArrayIndex+fTreeArrayNumEntries){
800 if (bDEBUG) std::cerr << "QwMollerADC_Channel::FillTreeVector: values.size()=="
801 << values.size()
802 << "; fTreeArrayIndex+fTreeArrayNumEntries=="
804 << std::endl;
805 } else {
806
807 UInt_t index = fTreeArrayIndex;
808
809 // hw_sum
810 if (bHw_sum) {
811 values.SetValue(index++, this->GetHardwareSum());
812 if (fDataToSave == kMoments) {
813 values.SetValue(index++, this->GetHardwareSumM2());
814 values.SetValue(index++, this->GetHardwareSumError());
815 }
816 }
817
818 if (bBlock) {
819 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
820 // blocki
821 values.SetValue(index++, this->GetBlockValue(i));
822 }
823 }
824
825 // num_samples
826 if (bNum_samples)
827 values.SetValue(index++, (fDataToSave == kMoments)? this->fGoodEventCount: this->fNumberOfSamples);
828 // Device_Error_Code
830 values.SetValue(index++, this->fErrorFlag);
831
832 if (fDataToSave == kRaw)
833 {
834 // hw_sum_raw
835 if (bHw_sum_raw)
836 values.SetValue(index++, this->GetRawHardwareSum());
837
838 if (bBlock_raw) {
839 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
840 // blocki_raw
841 values.SetValue(index++, this->GetRawBlockValue(i));
842 }
843 }
844
845 if (bBlock_raw) {
846 for (int i = 0; i < 4; i++) {
847 values.SetValue(index++, fBlockSumSq_raw[i]);
848 values.SetValue(index++, fBlock_min[i]);
849 values.SetValue(index++, fBlock_max[i]);
850 }
851 }
852 // sequence_number
854 values.SetValue(index++, this->fSequenceNumber);
855 }
856 }
857}
858
859#ifdef HAS_RNTUPLE_SUPPORT
860void QwMollerADC_Channel::ConstructNTupleAndVector(std::unique_ptr<ROOT::RNTupleModel>& model, TString& prefix, std::vector<Double_t>& values, std::vector<std::shared_ptr<Double_t>>& fieldPtrs)
861{
862 //For rntuple
863 if (IsNameEmpty()) {
864 // This channel is not used, so skip setting up the RNTuple.
865 } else {
866 // Decide what to store based on prefix
867 SetDataToSaveByPrefix(prefix);
868
869 // Set the boolean flags just like in ConstructBranchAndVector
875 bDevice_Error_Code = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "Device_Error_Code");
877
878 // For kMoments mode (running sum trees), enable all statistical fields regardless of histogram configuration
879 if (fDataToSave == kMoments) {
880 bHw_sum = true;
881 bBlock = true;
882 bNum_samples = true;
883 bDevice_Error_Code = true;
884 }
885
886 TString basename = prefix(0, (prefix.First("|") >= 0)? prefix.First("|"): prefix.Length()) + GetElementName();
887 fTreeArrayIndex = values.size();
888
889 // For derived data (yield_, asym_, diff_), only store the main value to match TTree format
890 if (fDataToSave == kDerived) {
891 // Only store the main hardware sum value, just like the original tree
892 values.resize(values.size() + 1, 0.0);
893 fieldPtrs.push_back(model->MakeField<Double_t>(basename.Data()));
895 return;
896 }
897
898 // For moments data (stat prefix), use the same structure as TTree to get exact field count match
899 if (fDataToSave == kMoments) {
900 // Create the same structure as TTree kMoments mode
901 if (bHw_sum) {
902 values.push_back(0.0);
903 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_hw_sum").Data()));
904 values.push_back(0.0);
905 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_hw_sum_m2").Data()));
906 values.push_back(0.0);
907 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_hw_sum_err").Data()));
908 }
909
910 if (bBlock) {
911 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
912 values.push_back(0.0);
913 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_block%d", i)).Data()));
914 }
915 }
916
917 if (bNum_samples) {
918 values.push_back(0.0);
919 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_num_samples").Data()));
920 }
921
922 if (bDevice_Error_Code) {
923 values.push_back(0.0);
924 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_Device_Error_Code").Data()));
925 }
926
927 fTreeArrayNumEntries = values.size() - fTreeArrayIndex;
928 return;
929 }
930
931 // For raw data, use the full detailed format
932 // Calculate how many elements we need to avoid multiple push_back calls
933 size_t numElements = 0;
934
935 // Count elements based on what will be saved
936 if (bHw_sum) {
937 numElements += 1; // hw_sum
938 }
939 if (bBlock) numElements += fBlocksPerEvent; // blocks
940 if (bNum_samples) numElements += 1; // num_samples
941 if (bDevice_Error_Code) numElements += 1; // error code
942
943 if (fDataToSave == kRaw) {
944 if (bHw_sum_raw) numElements += 1; // hw_sum_raw
945 if (bBlock_raw) numElements += fBlocksPerEvent; // block_raw
946 numElements += 16; // fBlockSumSq_raw (4*4)
947 if (bSequence_number) numElements += 1; // sequence_number
948 }
949
950 // Resize vectors once to avoid reallocation
951 size_t oldSize = values.size();
952 values.resize(oldSize + numElements, 0.0);
953 fieldPtrs.reserve(fieldPtrs.size() + numElements);
954
955 // Add fields in the same order as FillTreeVector
956 // hw_sum
957 if (bHw_sum) {
958 fieldPtrs.push_back(model->MakeField<Double_t>(basename.Data()));
959 }
960
961 if (bBlock) {
962 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
963 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_block%d", i)).Data()));
964 }
965 }
966
967 // num_samples
968 if (bNum_samples) {
969 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_num_samples").Data()));
970 }
971
972 // Device_Error_Code
973 if (bDevice_Error_Code) {
974 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_Device_Error_Code").Data()));
975 }
976
977 if (fDataToSave == kRaw) {
978 // hw_sum_raw
979 if (bHw_sum_raw) {
980 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_raw").Data()));
981 }
982
983 if (bBlock_raw) {
984 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
985 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_block%d_raw", i)).Data()));
986 }
987 }
988
989 for(int i = 0; i < 4; i++){
990 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_sumsq%d_low", i)).Data()));
991 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_sumsq%d_high", i)).Data()));
992 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_min%d", i)).Data()));
993 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_max%d", i)).Data()));
994 }
995
996 // sequence_number
997 if (bSequence_number) {
998 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_sequence_number").Data()));
999 }
1000 }
1001
1002 fTreeArrayNumEntries = values.size() - fTreeArrayIndex;
1003 }
1004}
1005
1006void QwMollerADC_Channel::FillNTupleVector(std::vector<Double_t>& values) const
1007{
1008 if (IsNameEmpty()) {
1009 // This channel is not used, so skip filling.
1010 } else if (fTreeArrayNumEntries <= 0) {
1011 if (bDEBUG) std::cerr << "QwMollerADC_Channel::FillNTupleVector: fTreeArrayNumEntries=="
1012 << fTreeArrayNumEntries << std::endl;
1013 } else if (values.size() < fTreeArrayIndex+fTreeArrayNumEntries){
1014 if (bDEBUG) std::cerr << "QwMollerADC_Channel::FillNTupleVector: values.size()=="
1015 << values.size()
1016 << "; fTreeArrayIndex+fTreeArrayNumEntries=="
1018 << std::endl;
1019 } else {
1020
1021 UInt_t index = fTreeArrayIndex;
1022
1023 // For derived data (yield_, asym_, diff_), only fill the main value to match TTree format
1024 if (fDataToSave == kDerived) {
1025 values[index] = this->GetHardwareSum();
1026 return;
1027 }
1028
1029
1030 // For raw data, use the full detailed format
1031 // hw_sum
1032 if (bHw_sum) {
1033 values[index++] = this->GetHardwareSum();
1034 }
1035
1036 if (bBlock) {
1037 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1038 // blocki
1039 values[index++] = this->GetBlockValue(i);
1040 }
1041 }
1042
1043 // num_samples
1044 if (bNum_samples)
1045 values[index++] = fDataToSave == kMoments ? this->fGoodEventCount : this->fNumberOfSamples;
1046
1047 // Device_Error_Code
1049 values[index++] = this->fErrorFlag;
1050
1051 if (fDataToSave == kRaw)
1052 {
1053 // hw_sum_raw
1054 if (bHw_sum_raw)
1055 values[index++] = this->GetRawHardwareSum();
1056
1057 if (bBlock_raw) {
1058 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1059 // blocki_raw
1060 values[index++] = this->GetRawBlockValue(i);
1061 }
1062 }
1063
1064 for(int i = 0; i < 4; i++){
1065 values[index++] = fBlockSumSq_raw[i] & 0xffffffff;
1066 values[index++] = fBlockSumSq_raw[i] >> 32;
1067 values[index++] = fBlock_min[i];
1068 values[index++] = fBlock_max[i];
1069 }
1070 // sequence_number
1071 if (bSequence_number)
1072 values[index++] = this->fSequenceNumber;
1073 }
1074 }
1075}
1076#endif // HAS_RNTUPLE_SUPPORT
1077
1079{
1080 if(this ==&value) return *this;
1081
1082 if (!IsNameEmpty()) {
1084 for (Int_t i=0; i<fBlocksPerEvent; i++){
1085 this->fBlock[i] = value.fBlock[i];
1086 this->fBlockM2[i] = value.fBlockM2[i];
1087 }
1091 this->fNumberOfSamples = value.fNumberOfSamples;
1092 this->fSequenceNumber = value.fSequenceNumber;
1093
1094 if (this->fDataToSave == kRaw){
1095 for (Int_t i=0; i<fBlocksPerEvent; i++){
1096 this->fBlock_raw[i] = value.fBlock_raw[i];
1097 this->fBlockSumSq_raw[i] = value.fBlockSumSq_raw[i];
1098 this->fBlock_min[i] = value.fBlock_min[i];
1099 this->fBlock_max[i] = value.fBlock_max[i];
1100 }
1103 }
1104 }
1105 return *this;
1106}
1107
1109 Double_t scale)
1110{
1111 if(this == &value) return;
1112
1113 if (!IsNameEmpty()) {
1114 for (Int_t i=0; i<fBlocksPerEvent; i++){
1115 this->fBlock[i] = value.fBlock[i] * scale;
1116 this->fBlockM2[i] = value.fBlockM2[i] * scale * scale;
1117
1118 }
1119 this->fHardwareBlockSum = value.fHardwareBlockSum * scale;
1120 this->fHardwareBlockSumM2 = value.fHardwareBlockSumM2 * scale * scale;
1121 this->fHardwareBlockSumError = value.fHardwareBlockSumError; // Keep this?
1122 this->fGoodEventCount = value.fGoodEventCount;
1123 this->fNumberOfSamples = value.fNumberOfSamples;
1124 this->fSequenceNumber = value.fSequenceNumber;
1125 this->fErrorFlag = value.fErrorFlag;
1126 }
1127}
1128
1130{
1131 const QwMollerADC_Channel* tmpptr;
1132 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1133 if (tmpptr!=NULL){
1134 *this = *tmpptr;
1135 } else {
1136 TString loc="Standard exception from QwMollerADC_Channel::AssignValueFrom = "
1137 +valueptr->GetElementName()+" is an incompatible type.";
1138 throw std::invalid_argument(loc.Data());
1139 }
1140}
1142{
1143 const QwMollerADC_Channel* tmpptr;
1144 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1145 if (tmpptr!=NULL){
1146 *this += *tmpptr;
1147 } else {
1148 TString loc="Standard exception from QwMollerADC_Channel::AddValueFrom = "
1149 +valueptr->GetElementName()+" is an incompatible type.";
1150 throw std::invalid_argument(loc.Data());
1151 }
1152}
1154{
1155 const QwMollerADC_Channel* tmpptr;
1156 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1157 if (tmpptr!=NULL){
1158 *this -= *tmpptr;
1159 } else {
1160 TString loc="Standard exception from QwMollerADC_Channel::SubtractValueFrom = "
1161 +valueptr->GetElementName()+" is an incompatible type.";
1162 throw std::invalid_argument(loc.Data());
1163 }
1164}
1166{
1167 const QwMollerADC_Channel* tmpptr;
1168 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1169 if (tmpptr!=NULL){
1170 *this *= *tmpptr;
1171 } else {
1172 TString loc="Standard exception from QwMollerADC_Channel::MultiplyBy = "
1173 +valueptr->GetElementName()+" is an incompatible type.";
1174 throw std::invalid_argument(loc.Data());
1175 }
1176}
1178{
1179 const QwMollerADC_Channel* tmpptr;
1180 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1181 if (tmpptr!=NULL){
1182 *this /= *tmpptr;
1183 } else {
1184 TString loc="Standard exception from QwMollerADC_Channel::DivideBy = "
1185 +valueptr->GetElementName()+" is an incompatible type.";
1186 throw std::invalid_argument(loc.Data());
1187 }
1188}
1189
1190
1192{
1193 QwMollerADC_Channel result = *this;
1194 result += value;
1195 return result;
1196}
1197
1199{
1200
1201 if (!IsNameEmpty()) {
1202 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1203 this->fBlock[i] += value.fBlock[i];
1204 this->fBlockM2[i] = 0.0;
1205 }
1206 this->fHardwareBlockSum += value.fHardwareBlockSum;
1207 this->fHardwareBlockSumM2 = 0.0;
1208 this->fNumberOfSamples += value.fNumberOfSamples;
1209 this->fSequenceNumber = 0;
1210 this->fErrorFlag |= (value.fErrorFlag);
1211
1212 }
1213
1214 return *this;
1215}
1216
1218{
1219 QwMollerADC_Channel result = *this;
1220 result -= value;
1221 return result;
1222}
1223
1225{
1226 if (!IsNameEmpty()){
1227 for (Int_t i=0; i<fBlocksPerEvent; i++){
1228 this->fBlock[i] -= value.fBlock[i];
1229 this->fBlockM2[i] = 0.0;
1230 }
1231 this->fHardwareBlockSum -= value.fHardwareBlockSum;
1232 this->fHardwareBlockSumM2 = 0.0;
1233 this->fNumberOfSamples += value.fNumberOfSamples;
1234 this->fSequenceNumber = 0;
1235 this->fErrorFlag |= (value.fErrorFlag);
1236 }
1237
1238 return *this;
1239}
1240
1242{
1243 QwMollerADC_Channel result = *this;
1244 result *= value;
1245 return result;
1246}
1247
1249{
1250 if (!IsNameEmpty()){
1251 for (Int_t i=0; i<fBlocksPerEvent; i++){
1252 this->fBlock[i] *= value.fBlock[i];
1253 this->fBlockM2[i] = 0.0;
1254 }
1255 this->fHardwareBlockSum *= value.fHardwareBlockSum;
1256 this->fHardwareBlockSumM2 = 0.0;
1257 this->fNumberOfSamples *= value.fNumberOfSamples;
1258 this->fSequenceNumber = 0;
1259 this->fErrorFlag |= (value.fErrorFlag);
1260 }
1261
1262 return *this;
1263}
1264
1266{
1267 const QwMollerADC_Channel* tmpptr;
1268 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(&source);
1269 if (tmpptr!=NULL){
1270 *this += *tmpptr;
1271 } else {
1272 TString loc="Standard exception from QwMollerADC_Channel::operator+= "
1273 +source.GetElementName()+" "
1274 +this->GetElementName()+" are not of the same type";
1275 throw(std::invalid_argument(loc.Data()));
1276 }
1277 return *this;
1278}
1280{
1281 const QwMollerADC_Channel* tmpptr;
1282 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(&source);
1283 if (tmpptr!=NULL){
1284 *this -= *tmpptr;
1285 } else {
1286 TString loc="Standard exception from QwMollerADC_Channel::operator-= "
1287 +source.GetElementName()+" "
1288 +this->GetElementName()+" are not of the same type";
1289 throw(std::invalid_argument(loc.Data()));
1290 }
1291 return *this;
1292}
1294{
1295 const QwMollerADC_Channel* tmpptr;
1296 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(&source);
1297 if (tmpptr!=NULL){
1298 *this *= *tmpptr;
1299 } else {
1300 TString loc="Standard exception from QwMollerADC_Channel::operator*= "
1301 +source.GetElementName()+" "
1302 +this->GetElementName()+" are not of the same type";
1303 throw(std::invalid_argument(loc.Data()));
1304 }
1305 return *this;
1306}
1308{
1309 const QwMollerADC_Channel* tmpptr;
1310 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(&source);
1311 if (tmpptr!=NULL){
1312 *this /= *tmpptr;
1313 } else {
1314 TString loc="Standard exception from QwMollerADC_Channel::operator/= "
1315 +source.GetElementName()+" "
1316 +this->GetElementName()+" are not of the same type";
1317 throw(std::invalid_argument(loc.Data()));
1318 }
1319 return *this;
1320}
1321
1322
1324{
1325 *this = value1;
1326 *this += value2;
1327}
1328
1330{
1331 *this = value1;
1332 *this -= value2;
1333}
1334
1336{
1337 if (!IsNameEmpty()) {
1338 *this = numer;
1339 *this /= denom;
1340
1342 fSequenceNumber = 0;
1344 fErrorFlag = (numer.fErrorFlag|denom.fErrorFlag);
1345 }
1346}
1347
1349{
1350 // In this function, leave the "raw" variables untouched.
1351 //
1352 Double_t ratio;
1353 Double_t variance;
1354 if (!IsNameEmpty()) {
1355 // The variances are calculated using the following formula:
1356 // Var[ratio] = ratio^2 (Var[numer] / numer^2 + Var[denom] / denom^2)
1357 //
1358 // This requires that both the numerator and denominator are non-zero!
1359 //
1360 for (Int_t i = 0; i < 4; i++) {
1361 if (this->fBlock[i] != 0.0 && denom.fBlock[i] != 0.0){
1362 ratio = (this->fBlock[i]) / (denom.fBlock[i]);
1363 variance = ratio * ratio *
1364 (this->fBlockM2[i] / this->fBlock[i] / this->fBlock[i]
1365 + denom.fBlockM2[i] / denom.fBlock[i] / denom.fBlock[i]);
1366 fBlock[i] = ratio;
1367 fBlockM2[i] = variance;
1368 } else if (this->fBlock[i] == 0.0) {
1369 this->fBlock[i] = 0.0;
1370 this->fBlockM2[i] = 0.0;
1371 } else {
1372 QwVerbose << "Attempting to divide by zero block in "
1374 fBlock[i] = 0.0;
1375 fBlockM2[i] = 0.0;
1376 }
1377 }
1378 if (this->fHardwareBlockSum != 0.0 && denom.fHardwareBlockSum != 0.0){
1379 ratio = (this->fHardwareBlockSum) / (denom.fHardwareBlockSum);
1380 variance = ratio * ratio *
1383 fHardwareBlockSum = ratio;
1384 fHardwareBlockSumM2 = variance;
1385 } else if (this->fHardwareBlockSum == 0.0) {
1386 fHardwareBlockSum = 0.0;
1387 fHardwareBlockSumM2 = 0.0;
1388 } else {
1389 QwVerbose << "Attempting to divide by zero sum in "
1391 fHardwareBlockSumM2 = 0.0;
1392 }
1393 // Remaining variables
1394 // Don't change fNumberOfSamples, fSequenceNumber, fGoodEventCount,
1395 // 'OR' the HW error codes in the fErrorFlag values together.
1396 fErrorFlag |= (denom.fErrorFlag);//mix only the hardware error codes
1397 }
1398
1399 // Nanny
1401 QwWarning << "Angry Nanny: NaN detected in " << GetElementName() << QwLog::endl;
1402
1403 return *this;
1404}
1405
1406//--------------------------------------------------------------------------------------------
1407
1409{
1410 if (!IsNameEmpty()) {
1411 this->fHardwareBlockSum = 0.0;
1412 for (Int_t i=0; i<fBlocksPerEvent; i++) {
1413 this->fBlock[i] = atan(value.fBlock[i]);
1414 this->fHardwareBlockSum += this->fBlock[i];
1415 }
1417 }
1418
1419 return;
1420}
1421
1422//--------------------------------------------------------------------------------------------
1424{
1425 if (!IsNameEmpty()){
1426 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1427 this->fBlock[i] = (value1.fBlock[i]) * (value2.fBlock[i]);
1428 // For a single event the second moment is still zero
1429 this->fBlockM2[i] = 0.0;
1430 }
1431
1432 // For a single event the second moment is still zero
1433 this->fHardwareBlockSumM2 = 0.0;
1435 this->fNumberOfSamples = value1.fNumberOfSamples;
1436 this->fSequenceNumber = 0;
1437 this->fErrorFlag = (value1.fErrorFlag|value2.fErrorFlag);
1438 }
1439 return;
1440}
1441
1442/**
1443This function will add a offset to the hw_sum and add the same offset for blocks.
1444 */
1446{
1447 if (!IsNameEmpty()){
1448 fHardwareBlockSum += offset;
1449 for (Int_t i=0; i<fBlocksPerEvent; i++)
1450 fBlock[i] += offset;
1451 }
1452 return;
1453}
1454
1455void QwMollerADC_Channel::Scale(Double_t scale)
1456{
1457 if (!IsNameEmpty()){
1458 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1459 fBlock[i] *= scale;
1460 fBlockM2[i] *= scale * scale;
1461 }
1462 fHardwareBlockSum *= scale;
1463 fHardwareBlockSumM2 *= scale * scale;
1464 }
1465}
1466
1467
1469{
1470 *this /= denom;
1471}
1472
1473
1474
1475
1476
1477
1478/** Moments and uncertainty calculation on the running sums and averages
1479 * The calculation of the first and second moments of the running sum is not
1480 * completely straightforward due to numerical instabilities associated with
1481 * small variances and large average values. The naive computation taking
1482 * the difference of the square of the average and the average of the squares
1483 * leads to the subtraction of two very large numbers to get a small number.
1484 *
1485 * Alternative algorithms (including for higher order moments) are supplied in
1486 * Pebay, Philippe (2008), "Formulas for Robust, One-Pass Parallel Computation
1487 * of Covariances and Arbitrary-Order Statistical Moments", Technical Report
1488 * SAND2008-6212, Sandia National Laboratories.
1489 * http://infoserve.sandia.gov/sand_doc/2008/086212.pdf
1490 *
1491 * In the following formulas the moments \f$ M^1 \f$ and \f$ M^2 \f$ are defined
1492 * \f{eqnarray}
1493 * M^1 & = & \frac{1}{n} \sum^n y \\
1494 * M^2 & = & \sum^n (y - \mu)
1495 * \f}
1496 *
1497 * Recurrence relations for the addition of a single event:
1498 * \f{eqnarray}
1499 * M^1_n & = & M^1_{n-1} + \frac{y - M^1_{n-1}}{n} \\
1500 * M^2_n & = & M^2_{n-1} + (y - M^1_{n-1})(y - M^1_n)
1501 * \f}
1502 *
1503 * For the addition of an already accumulated sum:
1504 * \f{eqnarray}
1505 * M^1 & = & M^1_1 + n_2 \frac{M^1_2 - M^1_1}{n} \\
1506 * M^2 & = & M^2_1 + M^2_2 + n_1 n_2 \frac{(M^1_2 - M^1_1)^2}{n}
1507 * \f}
1508 *
1509 * In these recursive formulas we start from \f$ M^1 = y \f$ and \f$ M^2 = 0 \f$.
1510 *
1511 * To calculate the mean and standard deviation we use
1512 * \f{eqnarray}
1513 * \mu & = & M^1 \\
1514 * \sigma^2 & = & \frac{1}{n} M^2
1515 * \f}
1516 * The standard deviation is a biased estimator, but this is what ROOT uses.
1517 * Better would be to divide by \f$ (n-1) \f$.
1518 *
1519 * We use the formulas provided there for the calculation of the first and
1520 * second moments (i.e. average and variance).
1521 */
1522// Accumulate the running moments M1 and M2.
1523// See header for parameter and return documentation.
1524void QwMollerADC_Channel::AccumulateRunningSum(const QwMollerADC_Channel& value, Int_t count, Int_t ErrorMask)
1525{
1526 /*
1527 note:
1528 The AccumulateRunningSum is called on a dedicated subsystem array object and
1529 for the standard running avg computations we only need value.fErrorFlag==0
1530 events to be included in the running avg. So the "berror" conditions is only
1531 used for the stability check purposes.
1532
1533 The need for this check below came due to fact that when routine
1534 DeaccumulateRunningSum is called the errorflag is updated with
1535 the kBeamStabilityError flag (+ configuration flags for global errors) and
1536 need to make sure we remove this flag and any configuration flags before
1537 checking the (fErrorFlag != 0) condition
1538
1539 See how the stability check is implemented in the QwEventRing class
1540
1541 Rakitha
1542 */
1543
1544 if(count==0){
1545 count = value.fGoodEventCount;
1546 }
1547
1548 Int_t n1 = fGoodEventCount;
1549 Int_t n2 = count;
1550
1551 // If there are no good events, check the error flag
1552 if (n2 == 0 && (value.fErrorFlag == 0)) {
1553 n2 = 1;
1554 }
1555
1556 // If a single event is removed from the sum, check all but stability fail flags
1557 if (n2 == -1) {
1558 if ((value.fErrorFlag & ErrorMask) == 0) {
1559 n2 = -1;
1560 } else {
1561 n2 = 0;
1562 }
1563 }
1564
1565 if (ErrorMask == kPreserveError){
1566 //n = 1;
1567 if (n2 == 0) {
1568 n2 = 1;
1569 }
1570 if (count == -1) {
1571 n2 = -1;
1572 }
1573 }
1574
1575 // New total number of good events
1576 Int_t n = n1 + n2;
1577
1578 // Set up variables
1579 Double_t M11 = fHardwareBlockSum;
1580 Double_t M12 = value.fHardwareBlockSum;
1581 Double_t M22 = value.fHardwareBlockSumM2;
1582
1583 //if(this->GetElementName() == "bcm_an_ds3" && ErrorMask == kPreserveError){QwError << "count=" << fGoodEventCount << " n=" << n << QwLog::endl; }
1584 if (n2 == 0) {
1585 // no good events for addition
1586 return;
1587 } else if (n2 == -1) {
1588 // simple version for removal of single event from the sum
1590 if (n > 1) {
1591 fHardwareBlockSum -= (M12 - M11) / n;
1592 fHardwareBlockSumM2 -= (M12 - M11)
1593 * (M12 - fHardwareBlockSum); // note: using updated mean
1594 // and for individual blocks
1595 for (Int_t i = 0; i < 4; i++) {
1596 M11 = fBlock[i];
1597 M12 = value.fBlock[i];
1598 M22 = value.fBlockM2[i];
1599 fBlock[i] -= (M12 - M11) / n;
1600 fBlockM2[i] -= (M12 - M11) * (M12 - fBlock[i]); // note: using updated mean
1601 }
1602 } else if (n == 1) {
1603 fHardwareBlockSum -= (M12 - M11) / n;
1604 fHardwareBlockSumM2 -= (M12 - M11)
1605 * (M12 - fHardwareBlockSum); // note: using updated mean
1606 if (fabs(fHardwareBlockSumM2) < 10.*std::numeric_limits<double>::epsilon())
1607 fHardwareBlockSumM2 = 0; // rounding
1608 // and for individual blocks
1609 for (Int_t i = 0; i < 4; i++) {
1610 M11 = fBlock[i];
1611 M12 = value.fBlock[i];
1612 M22 = value.fBlockM2[i];
1613 fBlock[i] -= (M12 - M11) / n;
1614 fBlockM2[i] -= (M12 - M11) * (M12 - fBlock[i]); // note: using updated mean
1615 if (fabs(fBlockM2[i]) < 10.*std::numeric_limits<double>::epsilon())
1616 fBlockM2[i] = 0; // rounding
1617 }
1618 } else if (n == 0) {
1619 fHardwareBlockSum -= M12;
1620 fHardwareBlockSumM2 -= M22;
1621 if (fabs(fHardwareBlockSum) < 10.*std::numeric_limits<double>::epsilon())
1622 fHardwareBlockSum = 0; // rounding
1623 if (fabs(fHardwareBlockSumM2) < 10.*std::numeric_limits<double>::epsilon())
1624 fHardwareBlockSumM2 = 0; // rounding
1625 // and for individual blocks
1626 for (Int_t i = 0; i < 4; i++) {
1627 M11 = fBlock[i];
1628 M12 = value.fBlock[i];
1629 M22 = value.fBlockM2[i];
1630 fBlock[i] -= M12;
1631 fBlockM2[i] -= M22;
1632 if (fabs(fBlock[i]) < 10.*std::numeric_limits<double>::epsilon())
1633 fBlock[i] = 0; // rounding
1634 if (fabs(fBlockM2[i]) < 10.*std::numeric_limits<double>::epsilon())
1635 fBlockM2[i] = 0; // rounding
1636 }
1637 } else {
1638 QwWarning << "Running sum has deaccumulated to negative good events." << QwLog::endl;
1639 }
1640 } else if (n2 == 1) {
1641 // simple version for addition of single event
1643 fHardwareBlockSum += (M12 - M11) / n;
1644 fHardwareBlockSumM2 += (M12 - M11)
1645 * (M12 - fHardwareBlockSum); // note: using updated mean
1646 // and for individual blocks
1647 for (Int_t i = 0; i < 4; i++) {
1648 M11 = fBlock[i];
1649 M12 = value.fBlock[i];
1650 M22 = value.fBlockM2[i];
1651 fBlock[i] += (M12 - M11) / n;
1652 fBlockM2[i] += (M12 - M11) * (M12 - fBlock[i]); // note: using updated mean
1653 }
1654 } else if (n2 > 1) {
1655 // general version for addition of multi-event sets
1656 fGoodEventCount += n2;
1657 fHardwareBlockSum += n2 * (M12 - M11) / n;
1658 fHardwareBlockSumM2 += M22 + n1 * n2 * (M12 - M11) * (M12 - M11) / n;
1659 // and for individual blocks
1660 for (Int_t i = 0; i < 4; i++) {
1661 M11 = fBlock[i];
1662 M12 = value.fBlock[i];
1663 M22 = value.fBlockM2[i];
1664 fBlock[i] += n2 * (M12 - M11) / n;
1665 fBlockM2[i] += M22 + n1 * n2 * (M12 - M11) * (M12 - M11) / n;
1666 }
1667 }
1668
1669 // Nanny
1671 QwWarning << "Angry Nanny: NaN detected in " << GetElementName() << QwLog::endl;
1672}
1673
1674
1676{
1677 if (fGoodEventCount <= 0)
1678 {
1679 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1680 fBlockError[i] = 0.0;
1681 }
1683 }
1684 else
1685 {
1686 // We use a biased estimator by dividing by n. Use (n - 1) to get the
1687 // unbiased estimator for the standard deviation.
1688 //
1689 // Note we want to calculate the error here, not sigma:
1690 // sigma = sqrt(M2 / n);
1691 // error = sigma / sqrt (n) = sqrt(M2) / n;
1692 for (Int_t i = 0; i < fBlocksPerEvent; i++)
1693 fBlockError[i] = sqrt(fBlockM2[i]) / fGoodEventCount;
1695
1696 // Stability check 83951872
1698 // check to see the channel has stability cut activated in the event cut file
1699 if (GetValueWidth() > fStability){
1700 // if the width is greater than the stability required flag the event
1702 } else
1703 fErrorFlag = 0;
1704 }
1705 }
1706}
1707
1708
1710{
1711 QwMessage << std::setprecision(8)
1712 << std::setw(18) << std::left << GetSubsystemName() << " "
1713 << std::setw(18) << std::left << GetModuleType() << " "
1714 << std::setw(18) << std::left << GetElementName() << " "
1715 << std::setw(12) << std::left << GetHardwareSum() << " +/- "
1716 << std::setw(12) << std::left << GetHardwareSumError() << " sig "
1717 << std::setw(12) << std::left << GetHardwareSumWidth() << " "
1718 << std::setw(10) << std::left << GetGoodEventCount() << " "
1719 << std::setw(12) << std::left << GetBlockValue(0) << " +/- "
1720 << std::setw(12) << std::left << GetBlockErrorValue(0) << " "
1721 << std::setw(12) << std::left << GetBlockValue(1) << " +/- "
1722 << std::setw(12) << std::left << GetBlockErrorValue(1) << " "
1723 << std::setw(12) << std::left << GetBlockValue(2) << " +/- "
1724 << std::setw(12) << std::left << GetBlockErrorValue(2) << " "
1725 << std::setw(12) << std::left << GetBlockValue(3) << " +/- "
1726 << std::setw(12) << std::left << GetBlockErrorValue(3) << " "
1727 << std::setw(12) << std::left << fGoodEventCount << " "
1728 << QwLog::endl;
1729 /*
1730 //for Debudding
1731 << std::setw(12) << std::left << fErrorFlag << " err "
1732 << std::setw(12) << std::left << fErrorConfigFlag << " c-err "
1733
1734 */
1735}
1736
1737std::ostream& operator<< (std::ostream& stream, const QwMollerADC_Channel& channel)
1738{
1739 stream << channel.GetHardwareSum();
1740 return stream;
1741}
1742
1743/**
1744 * Blind this channel as an asymmetry
1745 * @param blinder Blinder
1746 */
1748{
1749 if (!IsNameEmpty()) {
1750 if (blinder->IsBlinderOkay() && ((fErrorFlag)==0) ){
1751 for (Int_t i = 0; i < fBlocksPerEvent; i++)
1752 blinder->BlindValue(fBlock[i]);
1753 blinder->BlindValue(fHardwareBlockSum);
1754 } else {
1756 for (Int_t i = 0; i < fBlocksPerEvent; i++)
1759 }
1760 }
1761 return;
1762}
1763
1764/**
1765 * Blind this channel as a difference with specified yield
1766 * @param blinder Blinder
1767 * @param yield Corresponding yield
1768 */
1770{
1771 if (!IsNameEmpty()) {
1772 if (blinder->IsBlinderOkay() && ((fErrorFlag) ==0) ){
1773 for (Int_t i = 0; i < fBlocksPerEvent; i++)
1774 blinder->BlindValue(fBlock[i], yield.fBlock[i]);
1776 } else {
1777 blinder->ModifyThisErrorCode(fErrorFlag);//update the HW error code
1778 for (Int_t i = 0; i < fBlocksPerEvent; i++)
1781 }
1782 }
1783 return;
1784}
1785
1787{
1788
1789 Bool_t status = kTRUE;
1790 if (!IsNameEmpty()){
1791 status = (fSequenceNumber==seqnum);
1792 }
1793 return status;
1794}
1795
1797{
1798 Bool_t status = kTRUE;
1799 if (!IsNameEmpty()){
1800 status = (fNumberOfSamples==numsamp);
1801 if (! status){
1802 if (bDEBUG)
1803 std::cerr << "QwMollerADC_Channel::MatchNumberOfSamples: Channel "
1804 << GetElementName()
1805 << " had fNumberOfSamples==" << fNumberOfSamples
1806 << " and was supposed to have " << numsamp
1807 << std::endl;
1808 // PrintChannel();
1809 }
1810 }
1811 return status;
1812}
1813
1814Bool_t QwMollerADC_Channel::ApplySingleEventCuts(Double_t LL,Double_t UL)//only check to see HW_Sum is within these given limits
1815{
1816 Bool_t status = kFALSE;
1817
1818 if (UL < LL){
1819 status=kTRUE;
1820 } else if (GetHardwareSum()<=UL && GetHardwareSum()>=LL){
1821 if ((fErrorFlag & kPreserveError)!=0)
1822 status=kTRUE;
1823 else
1824 status=kFALSE;//If the device HW is failed
1825 }
1826 std::cout<<(this->fErrorFlag & kPreserveError)<<std::endl;
1827 return status;
1828}
1829
1830Bool_t QwMollerADC_Channel::ApplySingleEventCuts()//This will check the limits and update event_flags and error counters
1831{
1832 Bool_t status;
1833
1834 if (bEVENTCUTMODE>=2){//Global switch to ON/OFF event cuts set at the event cut file
1835
1836 if (fULimit < fLLimit){
1837 status=kTRUE;
1838 } else if (GetHardwareSum()<=fULimit && GetHardwareSum()>=fLLimit){
1839 if ((fErrorFlag)==0)
1840 status=kTRUE;
1841 else
1842 status=kFALSE;//If the device HW is failed
1843 }
1844 else{
1845 if (GetHardwareSum()> fULimit)
1847 else
1849 status=kFALSE;
1850 }
1851
1852 if (bEVENTCUTMODE==3){
1853 status=kTRUE; //Update the event cut fail flag but pass the event.
1854 }
1855
1856
1857 }
1858 else{
1859 status=kTRUE;
1860 //fErrorFlag=0;//we need to keep the device error codes
1861 }
1862
1863 return status;
1864}
1865
1867{
1868 TString message;
1869 message = Form("%30s","Device name");
1870 message += Form("%9s", "HW Sat");
1871 message += Form("%9s", "Sample");
1872 message += Form("%9s", "SW_HW");
1873 message += Form("%9s", "Sequence");
1874 message += Form("%9s", "SameHW");
1875 message += Form("%9s", "ZeroHW");
1876 message += Form("%9s", "EventCut");
1877 QwMessage << "---------------------------------------------------------------------------------------------" << QwLog::endl;
1878 QwMessage << message << QwLog::endl;
1879 QwMessage << "---------------------------------------------------------------------------------------------" << QwLog::endl;
1880 return;
1881}
1882
1884{
1885 QwMessage << "---------------------------------------------------------------------------------------------" << QwLog::endl;
1886 return;
1887}
1888
1890{
1891 TString message;
1893 message = Form("%30s", GetElementName().Data());
1894 message += Form("%9d", fErrorCount_HWSat);
1895 message += Form("%9d", fErrorCount_sample);
1896 message += Form("%9d", fErrorCount_SW_HW);
1897 message += Form("%9d", fErrorCount_Sequence);
1898 message += Form("%9d", fErrorCount_SameHW);
1899 message += Form("%9d", fErrorCount_ZeroHW);
1900 message += Form("%9d", fNumEvtsWithEventCutsRejected);
1901
1902 if((fDataToSave == kRaw) && (!kFoundPedestal||!kFoundGain)){
1903 message += " >>>>> No Pedestal or Gain in map file";
1904 }
1905
1906 QwMessage << message << QwLog::endl;
1907 }
1908 return;
1909}
1910
1911void QwMollerADC_Channel::ScaledAdd(Double_t scale, const VQwHardwareChannel *value)
1912{
1913 const QwMollerADC_Channel* input = dynamic_cast<const QwMollerADC_Channel*>(value);
1914
1915 // follows same steps as += but w/ scaling factor
1916 if(input!=NULL && !IsNameEmpty()){
1917 // QwWarning << "Adding " << input->GetElementName()
1918 // << " to " << GetElementName()
1919 // << " with scale factor " << scale
1920 // << QwLog::endl;
1921 // PrintValue();
1922 // input->PrintValue();
1923 for(Int_t i = 0; i < fBlocksPerEvent; i++){
1924 this -> fBlock[i] += scale * input->fBlock[i];
1925 this -> fBlockM2[i] = 0.0;
1926 }
1927 this -> fHardwareBlockSum += scale * input->fHardwareBlockSum;
1928 this -> fHardwareBlockSumM2 = 0.0;
1929 this -> fNumberOfSamples += input->fNumberOfSamples;
1930 this -> fSequenceNumber = 0;
1931 this -> fErrorFlag |= (input->fErrorFlag);
1932 } else if (input == NULL && value != NULL) {
1933 TString loc="Standard exception from QwMollerADC_Channel::ScaledAdd "
1934 +value->GetElementName()+" "
1935 +this->GetElementName()+" are not of the same type";
1936 throw(std::invalid_argument(loc.Data()));
1937 }
1938}
1939
1941 const QwMollerADC_Channel* tmpptr;
1942 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1943 if (tmpptr!=NULL){
1947 } else {
1948 TString loc="Standard exception from QwMollerADC_Channel::CopyParameters"
1949 +valueptr->GetElementName()+" "
1950 +this->GetElementName()+" are not of the same type";
1951 throw(std::invalid_argument(loc.Data()));
1952 }
1953};
1954
1955#ifdef __USE_DATABASE__
1956void QwMollerADC_Channel::AddErrEntriesToList(std::vector<QwErrDBInterface> &row_list)
1957{
1958
1959 QwErrDBInterface row;
1960 TString name = GetElementName();
1961
1962 row.Reset();
1963 row.SetDeviceName(name);
1964 row.SetErrorCodeId(1);
1966 row_list.push_back(row);
1967
1968 row.Reset();
1969 row.SetDeviceName(name);
1970 row.SetErrorCodeId(2);
1972 row_list.push_back(row);
1973
1974 row.Reset();
1975 row.SetDeviceName(name);
1976 row.SetErrorCodeId(3);
1978 row_list.push_back(row);
1979
1980
1981 row.Reset();
1982 row.SetDeviceName(name);
1983 row.SetErrorCodeId(4);
1985 row_list.push_back(row);
1986
1987
1988 row.Reset();
1989 row.SetDeviceName(name);
1990 row.SetErrorCodeId(5);
1992 row_list.push_back(row);
1993
1994 row.Reset();
1995 row.SetDeviceName(name);
1996 row.SetErrorCodeId(6);
1998 row_list.push_back(row);
1999
2000
2001 row.Reset();
2002 row.SetDeviceName(name);
2003 row.SetErrorCodeId(7);
2005 row_list.push_back(row);
2006 return;
2007
2008}
2009#endif
Physical units and constants for Qweak analysis.
Helper functions and utilities for ROOT histogram management.
QwHistogramHelper gQwHists
Globally defined instance of the QwHistogramHelper class.
A logfile class, based on an identical class in the Hermes analyzer.
#define QwVerbose
Predefined log drain for verbose messages.
Definition QwLog.h:54
#define QwError
Predefined log drain for errors.
Definition QwLog.h:39
#define QwWarning
Predefined log drain for warnings.
Definition QwLog.h:44
#define QwMessage
Predefined log drain for regular messages.
Definition QwLog.h:49
Decoding and management for Moller ADC channels (6x32-bit datawords)
static const UInt_t kBeamStabilityError
Definition QwTypes.h:180
static const UInt_t kErrorFlag_ZeroHW
Definition QwTypes.h:164
static const UInt_t kStabilityCut
Definition QwTypes.h:184
static const UInt_t kErrorFlag_EventCut_L
Definition QwTypes.h:165
static const UInt_t kErrorFlag_EventCut_U
Definition QwTypes.h:166
static const UInt_t kErrorFlag_SW_HW
Definition QwTypes.h:161
static const UInt_t kErrorFlag_sample
Definition QwTypes.h:160
static const UInt_t kPreserveError
Definition QwTypes.h:186
static const UInt_t kErrorFlag_VQWK_Sat
Definition QwTypes.h:159
static const UInt_t kErrorFlag_SameHW
Definition QwTypes.h:163
static const UInt_t kErrorFlag_Sequence
Definition QwTypes.h:162
Database interface for QwIntegrationPMT and subsystems.
std::ostream & operator<<(std::ostream &stream, const QwMollerADC_Channel &channel)
__attribute__((no_sanitize("signed-integer-overflow"))) void QwMollerADC_Channel
A class for blinding data, adapted from G0 blinder class.
static const double pi
Angles: base unit is radian.
Definition QwUnits.h:107
static const double us
Definition QwUnits.h:78
std::vector< TH1_ptr > fHistograms
Histograms associated with this data element.
std::vector< Double_t > fMockDriftAmplitude
Harmonic drift amplitude.
std::vector< Double_t > fMockDriftFrequency
Harmonic drift frequency.
Double_t fMockAsymmetry
Helicity asymmetry.
bool fUseExternalRandomVariable
Flag to use an externally provided normal random variable.
Double_t fMockGaussianSigma
Sigma of normal distribution.
Double_t fMockGaussianMean
Mean of normal distribution.
std::vector< Double_t > fMockDriftPhase
Harmonic drift phase.
Double_t GetRandomValue()
bool fCalcMockDataAsDiff
void SetN(UInt_t in)
void SetDeviceName(TString &in)
void SetErrorCodeId(UInt_t in)
Bool_t MatchVQWKElementFromList(const std::string &subsystemname, const std::string &moduletype, const std::string &devicename)
static std::ostream & endl(std::ostream &)
End of the line.
Definition QwLog.cc:297
Concrete hardware channel for Moller ADC modules (6x32-bit words)
Int_t GetRawSoftwareSum() const
Int_t ProcessEvBuffer(UInt_t *buffer, UInt_t num_words_left, UInt_t index=0) override
Decode the event data from a CODA buffer.
Double_t GetHardwareSumM2() const
const QwMollerADC_Channel operator*(const QwMollerADC_Channel &value) const
void AssignValueFrom(const VQwDataElement *valueptr) override
Int_t fErrorCount_SW_HW
HW_sum==SW_sum check.
VQwHardwareChannel & operator/=(const VQwHardwareChannel &input) override
void AddChannelOffset(Double_t Offset)
void SetHardwareSum(Double_t hwsum, UInt_t sequencenumber=0)
static void PrintErrorCounterHead()
void LoadChannelParameters(QwParameterFile &paramfile) override
QwMollerADC_Channel & operator+=(const QwMollerADC_Channel &value)
UInt_t fSequenceNumber
Event sequence number for this channel.
void RandomizeEventData(int helicity=0.0, double time=0.0) override
Internally generate random event data.
static const Bool_t kDEBUG
QwMollerADC_Channel & operator=(const QwMollerADC_Channel &value)
Double_t fPrev_HardwareBlockSum
Previous Module-based sum of the four sub-blocks.
QwMollerADC_Channel & operator*=(const QwMollerADC_Channel &value)
const QwMollerADC_Channel operator-(const QwMollerADC_Channel &value) const
Bool_t ApplySingleEventCuts() override
void MultiplyBy(const VQwHardwareChannel *valueptr) override
Double_t fBlockError[4]
Uncertainty on the sub-block.
void PrintValue() const override
Print single line of value and error of this data element.
void ScaledAdd(Double_t scale, const VQwHardwareChannel *value) override
void Sum(const QwMollerADC_Channel &value1, const QwMollerADC_Channel &value2)
void ProcessEvent() override
Process the event data according to pedestal and calibration factor.
Int_t fSequenceNo_Counter
Internal counter to keep track of the sequence number.
Int_t GetRawBlockValue(size_t blocknum) const
QwMollerADC_Channel & operator-=(const QwMollerADC_Channel &value)
void PrintErrorCounters() const override
report number of events failed due to HW and event cut failure
Bool_t MatchSequenceNumber(size_t seqnum)
Double_t fHardwareBlockSum
Module-based sum of the four sub-blocks.
void InitializeChannel(TString name, TString datatosave) override
Initialize the fields in this object.
Double_t GetBlockErrorValue(size_t blocknum) const
Int_t fErrorCount_sample
for sample size check
static const Int_t kMaxChannels
UInt_t fNumberOfSamples_map
Number of samples in the expected to read through the module. This value is set in the QwBeamline map...
void SetDefaultSampleSize(size_t num_samples_map)
void Blind(const QwBlinder *blinder)
Blind this channel as an asymmetry.
Int_t fErrorCount_ZeroHW
check to see ADC returning zero
void ArcTan(const QwMollerADC_Channel &value)
void DivideBy(const VQwHardwareChannel *valueptr) override
Int_t fNumEvtsWithEventCutsRejected
Counts the Event cut rejected events.
void SetEventData(Double_t *block, UInt_t sequencenumber=0)
void Scale(Double_t Offset) override
Double_t GetMollerADCSaturationLimt()
Int_t fErrorCount_HWSat
check to see ADC channel is saturated
void Ratio(const QwMollerADC_Channel &numer, const QwMollerADC_Channel &denom)
void CopyParameters(const VQwHardwareChannel *valueptr) override
void SetRawEventData() override
Int_t fSoftwareBlockSum_raw
Sum of the data in the four sub-blocks raw.
Int_t fBlock_raw[4]
Array of the sub-block data as read from the module.
static const Double_t kTimePerSample
void EncodeEventData(std::vector< UInt_t > &buffer) override
Encode the event data into a CODA buffer.
void AddValueFrom(const VQwHardwareChannel *valueptr) override
static Int_t GetBufferOffset(Int_t moduleindex, Int_t channelindex)
Int_t fErrorCount_SameHW
check to see ADC returning same HW value
void FillHistograms() override
Fill the histograms for this data element.
Double_t fBlockM2[4]
Second moment of the sub-block.
Int_t GetRawHardwareSum() const
Int_t ApplyHWChecks() override
Int_t fErrorCount_Sequence
sequence number check
static void PrintErrorCounterTail()
Int_t fHardwareBlockSum_raw
Module-based sum of the four sub-blocks as read from the module.
void ConstructHistograms(TDirectory *folder, TString &prefix) override
Construct the histograms for this data element.
UInt_t fPreviousSequenceNumber
Previous event sequence number for this channel.
static const Int_t kWordsPerChannel
Double_t GetValueWidth() const
void IncrementErrorCounters() override
Double_t fHardwareBlockSumError
Uncertainty on the hardware sum.
Double_t GetBlockValue(size_t blocknum) const
Double_t fBlock[4]
Array of the sub-block data.
void PrintInfo() const override
Print multiple lines of information about this data element.
void SubtractValueFrom(const VQwHardwareChannel *valueptr) override
void ConstructBranchAndVector(TTree *tree, TString &prefix, QwRootTreeBranchVector &values) override
Double_t GetHardwareSum() const
void FillTreeVector(QwRootTreeBranchVector &values) const override
Int_t fADC_Same_NumEvt
Keep track of how many events with same ADC value returned.
size_t GetNumberOfSamples() const
void CalculateRunningAverage() override
void AccumulateRunningSum(const QwMollerADC_Channel &value, Int_t count=0, Int_t ErrorMask=0xFFFFFFF)
const QwMollerADC_Channel operator+(const QwMollerADC_Channel &value) const
static const Bool_t bDEBUG
debugging display purposes
Double_t GetHardwareSumWidth() const
Double_t GetAverageVolts() const
Int_t fSequenceNo_Prev
Keep the sequence number of the last event.
void Product(const QwMollerADC_Channel &value1, const QwMollerADC_Channel &value2)
void AssignScaledValue(const QwMollerADC_Channel &value, Double_t scale)
void SmearByResolution(double resolution) override
Double_t fHardwareBlockSumM2
Second moment of the hardware sum.
static const Double_t kMollerADC_VoltsPerBit
void ClearEventData() override
Clear the event data in this element.
void Difference(const QwMollerADC_Channel &value1, const QwMollerADC_Channel &value2)
size_t GetSequenceNumber() const
UInt_t fNumberOfSamples
Number of samples read through the module.
Bool_t MatchNumberOfSamples(size_t numsamp)
Double_t GetHardwareSumError() const
void ConstructBranch(TTree *tree, TString &prefix) override
Configuration file parser with flexible tokenization and search capabilities.
Bool_t ReturnValue(const std::string keyname, T &retvalue)
A helper class to manage a vector of branch entries for ROOT trees.
Definition QwRootFile.h:55
size_type size() const noexcept
Definition QwRootFile.h:83
std::string LeafList(size_type start_index=0) const
Definition QwRootFile.h:230
void push_back(const std::string &name, const char type='D')
Definition QwRootFile.h:197
void SetValue(size_type index, Double_t val)
Definition QwRootFile.h:110
UInt_t fGoodEventCount
Number of good events accumulated in this element.
VQwDataElement()
Default constructor.
UInt_t fErrorConfigFlag
contains the global/local/stability flags
void SetSubsystemName(TString sysname)
Set the name of the inheriting subsystem name.
virtual const TString & GetElementName() const
Get the name of this element.
UInt_t fErrorFlag
This the standard error code generated for the channel that contains the global/local/stability flags...
void SetElementName(const TString &name)
Set the name of this element.
Bool_t IsNameEmpty() const
Is the name of this element empty?
TString GetSubsystemName() const
Return the name of the inheriting subsystem name.
UInt_t GetGoodEventCount() const
TString GetModuleType() const
Return the type of the beam instrument.
void SetModuleType(TString ModuleType)
set the type of the beam instrument
void SetDataToSave(TString datatosave)
Set the flag indicating if raw or derived values are in this data element.
void SetNumberOfSubElements(const size_t elements)
Set the number of data words in this data element.
VQwHardwareChannel & operator=(const VQwHardwareChannel &value)
Arithmetic assignment operator: Should only copy event-based data.
void SetNumberOfDataWords(const UInt_t &numwords)
Set the number of data words in this data element.
virtual void AddErrEntriesToList(std::vector< QwErrDBInterface > &)
UInt_t fNumberOfDataWords
Number of raw data words in this data element.
void SetDataToSaveByPrefix(const TString &prefix)
Set the flag indicating if raw or derived values are in this data element based on prefix.
Data blinding utilities for parity violation analysis.
Definition QwBlinder.h:57
const Bool_t & IsBlinderOkay() const
Definition QwBlinder.h:206
void ModifyThisErrorCode(UInt_t &errorcode) const
Definition QwBlinder.h:119
void BlindValue(Double_t &value) const
Asymmetry blinding.
Definition QwBlinder.h:124
static constexpr const Double_t kValue_BlinderFail
Definition QwBlinder.h:79