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#include <cmath>
12
13// Qweak headers
14#include "QwLog.h"
15#include "QwUnits.h"
16#include "QwBlinder.h"
17#include "QwHistogramHelper.h"
18#ifdef __USE_DATABASE__
19#include "QwDBInterface.h"
20#endif
21
22const Bool_t QwMollerADC_Channel::kDEBUG = kFALSE;
23
28
29const Double_t QwMollerADC_Channel::kTimePerSample = (2.0/30.0) * Qw::us; //2.0 originally
30
31/*! Conversion factor to translate the average bit count in an ADC
32 * channel into average voltage.
33 * The base factor is roughly 76 uV per count, and zero counts corresponds
34 * to zero voltage.
35 * Store as the exact value for 20 V range, 18 bit ADC.
36 */
37const Double_t QwMollerADC_Channel::kMollerADC_VoltsPerBit = (20./(1<<18));
38
39/*! Static member function to return the word offset within a data buffer
40 * given the module number index and the channel number index.
41 * @param moduleindex Module index within this buffer; counts from zero
42 * @param channelindex Channel index within this module; counts from zero
43 * @return The number of words offset to the beginning of this
44 * channel's data from the beginning of the MollerADC buffer.
45 */
46Int_t QwMollerADC_Channel::GetBufferOffset(Int_t moduleindex, Int_t channelindex){
47 Int_t offset = -1;
48 const Int_t channels_per_module = GetChannelsPerModule();
49 if (moduleindex<0 ){
50 QwError << "QwMollerADC_Channel::GetBufferOffset: Invalid module index,"
51 << moduleindex
52 << ". Must be zero or greater."
53 << QwLog::endl;
54 } else if (channelindex<0 || channelindex>=channels_per_module){
55 QwError << "QwMollerADC_Channel::GetBufferOffset: Invalid channel index,"
56 << channelindex
57 << ". Must be in range [0," << channels_per_module - 1 << "]."
58 << QwLog::endl;
59 } else {
60 offset = GetModuleHeaderWords()
61 + ( (moduleindex * channels_per_module) + channelindex )
63 }
64 return offset;
65 }
66
67
68/********************************************************/
70{
71 Bool_t fEventIsGood=kTRUE;
72 Bool_t bStatus;
73 if (bEVENTCUTMODE>0){//Global switch to ON/OFF event cuts set at the event cut file
74
75 if (bDEBUG)
76 QwWarning<<" QwQWVK_Channel "<<GetElementName()<<" "<<GetNumberOfSamples()<<QwLog::endl;
77
78
79 // Sample size check
80 bStatus = MatchNumberOfSamples(fNumberOfSamples_map);//compare the default sample size with no.of samples read by the module
81 if (!bStatus) {
83 }
84
85 // Check SW and HW return the same sum
86 bStatus = (GetRawHardwareSum() == GetRawSoftwareSum());
87 //fEventIsGood = bStatus;
88 if (!bStatus) {
90 }
91
92
93
94 //check sequence number
96 if (fSequenceNo_Counter==0 || GetSequenceNumber()==0){//starting the data run
98 }
99
100 if (!MatchSequenceNumber(fSequenceNo_Prev)){//we have a sequence number error
101 fEventIsGood=kFALSE;
103 if (bDEBUG) QwWarning<<" QwQWVK_Channel "<<GetElementName()<<" Sequence number previous value = "<<fSequenceNo_Prev<<" Current value= "<< GetSequenceNumber()<<QwLog::endl;
104 }
105
107
108 //Checking for HW_sum is returning same value.
110 //std::cout<<" BCM hardware sum is different "<<std::endl;
113 }else
114 fADC_Same_NumEvt++;//hw_sum is same increment the counter
115
116 //check for the hw_sum is giving the same value
117 if (fADC_Same_NumEvt>0){//we have ADC stuck with same value
118 if (bDEBUG) QwWarning<<" BCM hardware sum is same for more than "<<fADC_Same_NumEvt<<" time consecutively "<<QwLog::endl;
120 }
121
122 //check for the hw_sum is zero
123 if (GetRawHardwareSum()==0){
125 }
126 if (!fEventIsGood)
127 fSequenceNo_Counter=0;//resetting the counter after ApplyHWChecks() a failure
128
130 if (bDEBUG)
131 QwWarning << this->GetElementName()<<" "<<GetRawHardwareSum() << "Saturating MollerADC invoked! " <<TMath::Abs(GetRawHardwareSum())*kMollerADC_VoltsPerBit/fNumberOfSamples<<" Limit "<<GetMollerADCSaturationLimt() << QwLog::endl;
133 }
134
135 }
136 else {
137 fGoodEventCount = 1;
138 fErrorFlag = 0;
139 }
140
141 return fErrorFlag;
142}
143
144
145/********************************************************/
148 fErrorCount_sample++; //increment the hw error counter
150 fErrorCount_SW_HW++; //increment the hw error counter
152 fErrorCount_Sequence++; //increment the hw error counter
154 fErrorCount_SameHW++; //increment the hw error counter
156 fErrorCount_ZeroHW++; //increment the hw error counter
158 fErrorCount_HWSat++; //increment the hw saturation error counter
161 fNumEvtsWithEventCutsRejected++; //increment the event cut error counter
162 }
163}
164
165/********************************************************/
166
167void QwMollerADC_Channel::InitializeChannel(TString name, TString datatosave)
168{
169 SetElementName(name);
170 SetDataToSave(datatosave);
171 SetNumberOfDataWords(GetWordsPerChannel()); //was formerly SetNumberOfDataWords(kWordsPerChannel);
173
174 kFoundPedestal = 0;
175 kFoundGain = 0;
176
177 fPedestal = 0.0;
178 fCalibrationFactor = 1.0;
179
181
182
183
184 fTreeArrayIndex = 0;
186
188
192//added this
193 fRegionNumber = 0;
199 // Use internal random variable by default
201
202 // Mock drifts
203 fMockDriftAmplitude.clear();
204 fMockDriftFrequency.clear();
205 fMockDriftPhase.clear();
206
207 // Mock asymmetries
208 fMockAsymmetry = 0.0;
209 fMockGaussianMean = 0.0;
210 fMockGaussianSigma = 0.0;
211
212 // Event cuts
213 fULimit=-1;
214 fLLimit=1;
216
217 fErrorFlag=0; //Initialize the error flag
218 fErrorConfigFlag=0; //Initialize the error config. flag
219
220 //init error counters//
227
232
233 fGoodEventCount = 0;
234
235 bEVENTCUTMODE = 0;
236
237 return;
238}
239
240/********************************************************/
241
242void QwMollerADC_Channel::InitializeChannel(TString subsystem, TString instrumenttype, TString name, TString datatosave){
243 InitializeChannel(name,datatosave);
244 SetSubsystemName(subsystem);
245 SetModuleType(instrumenttype);
246 //PrintInfo();
247}
248
250{
251 switch (fDecodeMode) {
252 case kOldMock:
254 case kNewReshuffled:
256 }
257
259}
260
262{
263 switch (fDecodeMode) {
264 case kOldMock:
266 case kNewReshuffled:
268 }
269
271}
272
274{
275 switch (fDecodeMode) {
276 case kOldMock:
277 return 0;
278 case kNewReshuffled:
279 return kModuleHeaderWords;
280 }
281
282 return 0;
283}
284
286{
287 switch (fDecodeMode) {
288 case kOldMock:
290 case kNewReshuffled:
292 }
293
295}
296
298{
299 if (input != static_cast<UInt_t>(kOldMock)
300 && input != static_cast<UInt_t>(kNewReshuffled)) {
301 QwError << "QwMollerADC_Channel::SetDecodeMode: Invalid "
302 << "MOLLERADC_decode_mode " << input
303 << ". Valid values are 0 (old mock) and 1 (new reshuffled)."
304 << QwLog::endl;
305 throw std::runtime_error("Invalid MOLLERADC_decode_mode");
306 }
307
308 const EDecodeMode requested_mode = static_cast<EDecodeMode>(input);
309 if (fDecodeModeHasBeenSet && requested_mode != fDecodeMode) {
310 QwError << "QwMollerADC_Channel::SetDecodeMode: Inconsistent "
311 << "MOLLERADC_decode_mode. First mode was "
312 << static_cast<UInt_t>(fDecodeMode)
313 << ", but a later map/config requested " << input
314 << ". Mixed MOLLERADC decode modes are not supported "
315 << "in one datastream." << QwLog::endl;
316 throw std::runtime_error("Inconsistent MOLLERADC_decode_mode");
317 }
318
319 fDecodeMode = requested_mode;
320 fDecodeModeHasBeenSet = kTRUE;
321}
322
324 UInt_t value = 0;
325 if (paramfile.ReturnValue("molleradc_decode_mode", value)
326 || paramfile.ReturnValue("decode_mode", value)) {
327 SetDecodeMode(value);
329 }
330
331 if (paramfile.ReturnValue("sample_size", value)) {
333 } else {
334 QwWarning << "MollerADC Channel "
335 << GetElementName()
336 << " cannot set the default sample size."
337 << QwLog::endl;
338 }
339
340 UInt_t NumberOfBlocks = 0;
341
342 if (paramfile.ReturnValue("NumberOfBlocks", NumberOfBlocks)
343 || paramfile.ReturnValue("numberofblocks", NumberOfBlocks)) {
344 if (NumberOfBlocks > static_cast<UInt_t>(kMaxBlock)) {
345 QwWarning << "MollerADC Channel " << GetElementName()
346 << ": NumberOfBlocks (" << NumberOfBlocks
347 << ") is greater than kMaxBlock (" << kMaxBlock
348 << ") and has been forced to kMaxBlock."
349 << QwLog::endl;
350 NumberOfBlocks = kMaxBlock;
351 }
352 if (NumberOfBlocks == 0) {
353 QwWarning << "MollerADC Channel " << GetElementName()
354 << ": NumberOfBlocks is zero. Defaulting to "
355 << GetDefaultBlocksPerEvent() << "."
356 << QwLog::endl;
357 NumberOfBlocks = GetDefaultBlocksPerEvent();
358 }
359 fBlocksPerEvent = NumberOfBlocks;
360 } else {
362 }
363};
364
365
367{
368 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
369 fBlock_raw[i] = 0;
370 fBlockSumSq_raw[i] = 0;
371 fBlock_min[i] = 0;
372 fBlock_max[i] = 0;
373 fBlock[i] = 0.0;
374 fBlockM2[i] = 0.0;
375 fBlockError[i] = 0.0;
376 fBlockSample[i] = 0;
377 fBlockRMS[i] = 0.0;
378 }
381 fHardwareBlockSum = 0.0;
385 fSequenceNumber = 0;
387
388 fGoodEventCount = 0;
389 fErrorFlag=0;
390 return;
391}
392
393void QwMollerADC_Channel::RandomizeEventData(int helicity, double time)
394{
395 // updated to calculate the drift for each block individually
396 Double_t drift = 0.0;
397 for (Int_t i = 0; i < fBlocksPerEvent; i++){
398 drift = 0.0;
399 if (i >= 1){
401 }
402 for (UInt_t i = 0; i < fMockDriftFrequency.size(); i++) {
403 drift += fMockDriftAmplitude[i] * sin(2.0 * Qw::pi * fMockDriftFrequency[i] * time + fMockDriftPhase[i]);
404 //std::cout << "Drift: " << drift << std::endl;
405 }
406 }
407
408 // Calculate signal
409 fHardwareBlockSum = 0.0;
410 fHardwareBlockSumM2 = 0.0; // second moment is zero for single events
411 fBlock_max[4] = kMinInt;
412 fBlock_min[4] = kMaxInt;
413
414 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
415 double tmpvar = GetRandomValue();
416
417 fBlock[i] = fMockGaussianMean + drift;
418
420 fBlock[i] += helicity*fMockAsymmetry;
421 } else {
422 fBlock[i] *= 1.0 + helicity*fMockAsymmetry;
423 }
424 fBlock[i] += fMockGaussianSigma*tmpvar*sqrt(fBlocksPerEvent);
425 fBlockM2[i] = 0.0; // second moment is zero for single events
427
428 }
430 fSequenceNumber = 0;
432 // SetEventData(block);
433 // delete block;
434 return;
435}
436
438
439 fHardwareBlockSum = 0.0;
440 fHardwareBlockSumM2 = 0.0; // second moment is zero for single events
441 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
442
443 fBlock[i] += resolution*sqrt(fBlocksPerEvent) * GetRandomValue();
444
445 fBlockM2[i] = 0.0; // second moment is zero for single events
447 }
448 // std::cout << std::endl;
450
452 // SetRawEventData();
453 return;
454}
455
456void QwMollerADC_Channel::SetHardwareSum(Double_t hwsum, UInt_t sequencenumber)
457{
458 Double_t* block = new Double_t[fBlocksPerEvent];
459 for (Int_t i = 0; i < fBlocksPerEvent; i++){
460 block[i] = hwsum / fBlocksPerEvent;
461 }
462 SetEventData(block);
463 delete[] block;
464 return;
465}
466
467
468// SetEventData() is used by the mock data generator to turn "model"
469// data values into their equivalent raw data. It should be used
470// nowhere else. -- pking, 2010-09-16
471
472void QwMollerADC_Channel::SetEventData(Double_t* block, UInt_t sequencenumber)
473{
474 fHardwareBlockSum = 0.0;
475 fHardwareBlockSumM2 = 0.0; // second moment is zero for single events
476 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
477 fBlock[i] = block[i];
478 fBlockM2[i] = 0.0; // second moment is zero for single events
479 fHardwareBlockSum += block[i];
480 }
482
483 fSequenceNumber = sequencenumber;
485
486// Double_t thispedestal = 0.0;
487// thispedestal = fPedestal * fNumberOfSamples;
488
490 return;
491}
492
493__attribute__((no_sanitize("signed-integer-overflow")))
494void QwMollerADC_Channel::SetRawEventData(){
495 fNumberOfSamples = fNumberOfSamples_map;
496 fHardwareBlockSum_raw = 0;
497// Double_t hwsum_test = 0.0;
498// std::cout << "*******In QwMollerADC_Channel::SetRawEventData for channel:\t" << this->GetElementName() << std::endl;
499 for (Int_t i = 0; i < fBlocksPerEvent; i++)
500 {
501 Double_t block_raw = (fBlock[i] / fCalibrationFactor + fPedestal) * fNumberOfSamples / (fBlocksPerEvent * 1.0);
502 if (std::abs(block_raw) >= pow(2,29)) {
503 block_raw = std::copysign(pow(2,29)-1, block_raw);
504 QwWarning << "QwMollerADC_Channel::SetRawEventData: Overflow in conversion to raw data for channel "
505 << this->GetElementName() << ": ("
506 << "fBlock[i] = " << fBlock[i] << " / "
507 << "fCalibrationFactor = " << fCalibrationFactor << " + "
508 << "fPedestal = " << fPedestal << ") * "
509 << "fNumberOfSamples = " << fNumberOfSamples << " / "
510 << "fBlocksPerEvent = " << fBlocksPerEvent << ". "
511 << "Capping value to " << block_raw << "."
512 << QwLog::endl;
513 }
514 fBlock_raw[i] = Int_t(block_raw);
515 fHardwareBlockSum_raw += fBlock_raw[i];
516
517 double_t block = fBlock[i] / fCalibrationFactor;
518 double_t sigma = fMockGaussianSigma / fCalibrationFactor;
519 fBlockSumSq_raw[i] = (sigma*sigma + block*block)*fNumberOfSamples_map / (fBlocksPerEvent * 1.0);
520 fBlock_min[i] = (block - 3.0 * sigma) * double_t(fNumberOfSamples_map) / (fBlocksPerEvent * 1.0);
521 fBlock_max[i] = (block + 3.0 * sigma) * double_t(fNumberOfSamples_map) / (fBlocksPerEvent * 1.0);
522
523 fBlockSumSq_raw[4] += fBlockSumSq_raw[i];
524 fBlock_min[4] = TMath::Min(fBlock_min[i],fBlock_min[4]);
525 fBlock_max[4] = TMath::Max(fBlock_max[i],fBlock_max[4]);
526 }
527
528
529
530 fSoftwareBlockSum_raw = fHardwareBlockSum_raw;
531
532 return;
533}
534
535void QwMollerADC_Channel::EncodeEventData(std::vector<UInt_t> &buffer)
536{
537 Long_t localbuf[kOldMockWordsPerChannel] = {0};
538
539 if (IsNameEmpty()) {
540 // This channel is not used, but is present in the data stream.
541 // Skip over this data.
542 } else {
543 // localbuf[4] = 0;
544 for (Int_t i = 0; i < 4; i++) {
545 localbuf[i*5] = fBlock_raw[i];
546 localbuf[i*5+1] = fBlockSumSq_raw[i] & 0xffffffff;
547 localbuf[i*5+2] = fBlockSumSq_raw[i] >> 32;
548 localbuf[i*5+3] = fBlock_min[i];
549 localbuf[i*5+4] = fBlock_max[i];
550
551 // localbuf[4] += localbuf[i]; // fHardwareBlockSum_raw
552 }
553 // The following causes many rounding errors and skips due to the check
554 // that fHardwareBlockSum_raw == fSoftwareBlockSum_raw in IsGoodEvent().
555 localbuf[20] = fHardwareBlockSum_raw;
556 localbuf[21] = fBlockSumSq_raw[4] & 0xffffffff;
557 localbuf[22] = fBlockSumSq_raw[4] >> 32;
558 localbuf[23] = fBlock_min[4];
559 localbuf[24] = fBlock_max[4];
560 localbuf[25] = (fNumberOfSamples << 16 & 0xFFFF0000)
561 | (fSequenceNumber << 8 & 0x0000FF00);
562
563 for (Int_t i = 0; i < kOldMockWordsPerChannel; i++){
564 buffer.push_back(localbuf[i]);
565 }
566 }
567 return;
568}
569
570Int_t QwMollerADC_Channel::ProcessEvBuffer(UInt_t* buffer, UInt_t num_words_left, UInt_t index)
571{
572Int_t retval;
573if (fDecodeMode == kOldMock){
574retval=ProcessEvBuffer_oldmock(buffer, num_words_left, index);
575} else {
576retval=ProcessEvBuffer_newreshuffled(buffer, num_words_left, index);
577}
578return retval;
579}
580
581Int_t QwMollerADC_Channel::ProcessEvBuffer_oldmock(UInt_t* buffer, UInt_t num_words_left, UInt_t index)
582{
583 UInt_t words_read = 0;
584 UInt_t raw_u32[kOldMockWordsPerChannel] = {0};
585 // The conversion from UInt_t to Double_t discards the sign, so we need an intermediate
586 // static_cast from UInt_t to Int_t.
587 Int_t raw_i32[kOldMockWordsPerChannel] = {0};
588
589 if (IsNameEmpty()){
590 return fNumberOfDataWords;
591 }
592
593 if (num_words_left < fNumberOfDataWords)
594 {
595 std::cerr << "QwMollerADC_Channel::ProcessEvBuffer_oldmock: "
596 << "Not enough words for old mock MOLLER ADC channel "
597 << GetElementName()
598 << " "
599 << "(need " << fNumberOfDataWords
600 << ", have " << num_words_left << ")!"
601 << std::endl;
602 return 0;
603}
604
605//copy local channel words
606
607 for (Int_t i=0; i<kOldMockWordsPerChannel; i++){
608 raw_u32[i] = buffer[i];
609 raw_i32[i] = static_cast<Int_t>(raw_u32[i]);
610 }
611
613
614 for (Int_t blockindex = 0; blockindex < fBlocksPerEvent; blockindex++) {
615 const Int_t base = blockindex * 5;
616
617 Int_t ch_sum_block = raw_i32[base];
618 Long64_t ch_sumsq_block = static_cast<Long64_t>(raw_i32[base + 1]);
619 ch_sumsq_block += static_cast<Long64_t>(raw_i32[base + 2]) << 32;
620
621 Int_t ch_min_20 = raw_i32[base + 3];
622 Int_t ch_max_20 = raw_i32[base + 4];
623
624 fBlock_raw[blockindex] = ch_sum_block;
625 fBlockSumSq_raw[blockindex] = ch_sumsq_block;
626 fBlock_min[blockindex] = ch_min_20;
627 fBlock_max[blockindex] = ch_max_20;
628
629 fSoftwareBlockSum_raw += ch_sum_block;
630}
631
632 // Old mock hardware/window sum
633 Long64_t ch_sum_win = static_cast<Long64_t>(raw_i32[20]);
634 fHardwareBlockSum_raw = ch_sum_win;
635
636 /*
637 * Permanent change in the structure of the 6th word of the ADC readout.
638 * The upper 16 bits are the number of samples, and the upper 8 of the
639 * lower 16 are the sequence number.
640 */
641 UInt_t ch_misc = raw_u32[25];
642
643 fSequenceNumber = (ch_misc >> 8) & 0xFF;
644 fNumberOfSamples = (ch_misc >> 16) & 0xFFFF;
645 if (fNumberOfSamples == 0) {
647 }
648 const UInt_t block_samples =
650 for (Int_t blockindex = 0; blockindex < fBlocksPerEvent; blockindex++) {
651 fBlockSample[blockindex] = block_samples;
652 }
653
654 words_read = fNumberOfDataWords;
655
656 return words_read;
657}
658
660 UInt_t num_words_left,
661 UInt_t index)
662{
663/* static int debug_counter = 0;
664
665 if (debug_counter < 20) { // limit output
666 std::cout << "[DEBUG] Entering QwMollerADC_Channel::ProcessEvBuffer for channel: "
667 << GetElementName()
668 << " | words_left=" << num_words_left
669 << " | index=" << index
670 << std::endl;
671 }
672 debug_counter++; */
673 // small debug counter
674 //static int debug_event_counter = 0;
675
676 // Each channel now has 7×64-bit words = 14×32-bit words
677 const UInt_t need_u32 = kNewReshuffledWordsPerChannel; // = 14
678
679 // If this channel slot is unused, just skip the words
680 if (IsNameEmpty()) {
681 return need_u32;
682 }
683
684 // Basic safety check
685 if (num_words_left < need_u32) {
686 std::cerr
687 << "QwMollerADC_Channel::ProcessEvBuffer: Not enough words for "
688 << "MOLLER ADC integrating mode channel (need "
689 << need_u32 << ", have " << num_words_left << ")!\n";
690 return 0;
691 }
692
693
694 // CODA packs each 64-bit word as big-endian into two 32-bit words:
695 // p[1] = high 32 bits, p[0] = low 32 bits
696 auto read_be64_from_u32 = [&](UInt_t* p)->uint64_t {
697 uint64_t hi = static_cast<uint64_t>(p[1]);
698 uint64_t lo = static_cast<uint64_t>(p[0]);
699 uint64_t be64 = (hi << 32) | lo; // big-endian 64-bit
700 return be64;
701 };
702
703 UInt_t* p = buffer;
704
705 // ---------- 7 × 64-bit channel words (already at channel offset) ----------
706 // Naming follows the MOLLER ADC manual (integrating mode)
707 uint64_t ch_misc = read_be64_from_u32(p + 0);
708 uint64_t ch_sample_count_win = read_be64_from_u32(p + 2);
709 int64_t ch_sum_win = static_cast<int64_t>(read_be64_from_u32(p + 4));
710 uint64_t ch_sumsq_win = read_be64_from_u32(p + 6);
711 uint64_t ch_sample_count_block = read_be64_from_u32(p + 8);
712 int64_t ch_sum_block = static_cast<int64_t>(read_be64_from_u32(p + 10));
713 uint64_t ch_sumsq_block = read_be64_from_u32(p + 12);
714
715if (ch_sample_count_block == 0) {
716 std::cerr << "QwMollerADC_Channel::ProcessEvBuffer: "
717 << "ch_sample_count_block == 0, cannot compute blockindex!\n";
718 return need_u32;
719}
720
721//int blockindex = static_cast<int>(ch_sample_count_win / ch_sample_count_block) - 1;
722int blockindex = static_cast<int>(std::round(static_cast<double>(ch_sample_count_win) / ch_sample_count_block) - 1.0);
723
724 //---------- Optional debug print for a few events ----------
725 // if (debug_event_counter < 10) {
726 // std::cout << "\n=== MOLLER ADC Channel Debug Event " << debug_event_counter << " ===\n";
727 // std::cout << " fBlockSample(before) = " << fBlockSample[blockindex] << "\n";
728 // std::cout << "ch_misc = 0x" << std::hex << ch_misc << "\n";
729 // std::cout << "blockindex(before) = " << blockindex << "\n";
730 // std::cout << "ch_sample_count_win = 0x" << ch_sample_count_win << "\n";
731 // std::cout << "ch_sum_win = 0x" << ch_sum_win << "\n";
732 // std::cout << "ch_sumsq_win = 0x" << ch_sumsq_win << "\n";
733 // std::cout << "ch_sample_count_block = 0x" << ch_sample_count_block << "\n";
734 // std::cout << "ch_sum_block = 0x" << ch_sum_block << "\n";
735 // std::cout << "ch_sumsq_block = 0x" << ch_sumsq_block << std::dec << "\n";
736
737 // std::cout << "---------------------------------------\n";
738 // }
739
740 // ---------- Decode 20-bit signed min/max from ch_misc ----------
741 // [39:20] = max (signed 20-bit)
742 // [19:0] = min (signed 20-bit)
743 auto sign_extend20 = [](int32_t v20)->int32_t {
744 v20 &= 0xFFFFF; // keep lower 20 bits
745 if (v20 & 0x80000) { // if sign bit set
746 v20 |= ~0xFFFFF; // extend sign to 32 bits
747 }
748 return v20;
749 };
750
751 int32_t ch_min_20 = sign_extend20(
752 static_cast<int32_t>((ch_misc >> 20) & 0xFFFFF));
753 int32_t ch_max_20 = sign_extend20(
754 static_cast<int32_t>( ch_misc & 0xFFFFF));
755
756
757 fNumberOfSamples = static_cast<UInt_t>(ch_sample_count_win);
758 fHardwareBlockSum_raw = (ch_sum_win);
759
760
761if (blockindex < 0 || blockindex >= kMaxBlock) {
762 std::cerr << "QwMollerADC_Channel::ProcessEvBuffer: "
763 << "Computed bad blockindex = " << blockindex
764 << " (kMaxBlock = " << kMaxBlock << ")\n";
765 return need_u32;
766}
767// Debug print: show which block index is being filled
768// if (debug_event_counter < 10) {
769// std::cout << "[DEBUG] Filling blockindex = " << blockindex
770// << " (win_count=" << ch_sample_count_win
771// << ", block_count=" << ch_sample_count_block << ")\n";
772
773// std::cout << " sum_block = 0x" << std::hex << ch_sum_block << std::dec << "\n"
774// << " sumsq_block = 0x" << std::hex << ch_sumsq_block << std::dec << "\n"
775// << " min_20 = " << ch_min_20 << "\n"
776// << " max_20 = " << ch_max_20 << "\n"
777// << "--------------------------------------------------------\n";
778// }
779// Figure out which subblock we're reading
780
781 if (blockindex == 0) {
782 fSoftwareBlockSum_raw = (ch_sum_block);
783} else {
784 fSoftwareBlockSum_raw += (ch_sum_block);
785}
786
787fBlock_raw[blockindex] = (ch_sum_block);
788fBlockSample[blockindex] = static_cast<UInt_t>(ch_sample_count_block);
789fBlockSumSq_raw[blockindex] = static_cast<Long64_t>(ch_sumsq_block);
790fBlock_min[blockindex] = ch_min_20;
791fBlock_max[blockindex] = ch_max_20;
792
793long double win_mean = 0.0L;
794long double win_mean_sq = 0.0L;
795long double win_var = 0.0L;
796
797double block_mean = 0.0;
798double block_mean_sq = 0.0;
799double block_var = 0.0;
800
801// Window RMS
802if (ch_sample_count_win > 0) {
803 win_mean = static_cast<double>(ch_sum_win) / static_cast<double>(ch_sample_count_win);
804 win_mean_sq = static_cast<double>(ch_sumsq_win) / static_cast<double>(ch_sample_count_win);
805 win_var = win_mean_sq - win_mean * win_mean;
806 if (win_var < 0.0) win_var = 0.0;
807 fHardwareBlockSumRMS = std::sqrt(win_var);
808} else {
810}
811
812// Block RMS
813if (ch_sample_count_block > 0) {
814 block_mean = static_cast<double>(ch_sum_block) / static_cast<double>(ch_sample_count_block);
815 block_mean_sq = static_cast<double>(ch_sumsq_block) / static_cast<double>(ch_sample_count_block);
816 block_var = block_mean_sq - block_mean * block_mean;
817 if (block_var < 0.0) block_var = 0.0;
818 fBlockRMS[blockindex] = std::sqrt(block_var);
819} else {
820 fBlockRMS[blockindex] = 0.0;
821}
822
823// static int rms_debug_counter = 0;
824// if (rms_debug_counter < 10) {
825// std::cout << "\n=== RMS DEBUG Event " << rms_debug_counter << " ===\n"
826// << "ch_sample_count_win = " << ch_sample_count_win << "\n"
827// << "ch_sum_win = " << ch_sum_win << "\n"
828// << "ch_sumsq_win = " << ch_sumsq_win << "\n"
829// << "fHardwareBlockSumRMS = " << fHardwareBlockSumRMS << "\n"
830// << "blockindex = " << blockindex << "\n"
831// << "ch_sample_count_block = " << ch_sample_count_block << "\n"
832// << "ch_sum_block = " << ch_sum_block << "\n"
833// << "ch_sumsq_block = " << ch_sumsq_block << "\n"
834// << "fBlockRMS[" << blockindex << "] = " << fBlockRMS[blockindex] << "\n";
835// std::cout << std::setprecision(15)
836// << "win_mean = " << win_mean << "\n"
837// << "win_mean_sq = " << win_mean_sq << "\n"
838// << "win_var = " << win_var << "\n"
839// << "block_mean = " << block_mean << "\n"
840// << "block_mean_sq = " << block_mean_sq << "\n"
841// << "block_var = " << block_var << "\n";
842// }
843// rms_debug_counter++;
844
845
846// if (debug_event_counter < 10) {
847// std::cout << " fBlockSample(after) = " << fBlockSample[blockindex] << "\n";
848// std::cout << "blockindex(after) = " << blockindex << "\n";
849
850// }
851
852// debug_event_counter++;
853
854 return need_u32;
855}
856
857
858
859
861{
862 if (fNumberOfSamples == 0 && fHardwareBlockSum_raw == 0) {
863 // There isn't valid data for this channel. Just flag it and
864 // move on.
865 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
866 fBlock[i] = 0.0;
867 fBlockM2[i] = 0.0;
868 }
869 fHardwareBlockSum = 0.0;
872 } else if (fNumberOfSamples == 0) {
873 // This is probably a more serious problem.
874 QwWarning << "QwMollerADC_Channel::ProcessEvent: Channel "
875 << this->GetElementName().Data()
876 << " has fNumberOfSamples==0 but has valid data in the hardware sum. "
877 << "Flag this as an error."
878 << QwLog::endl;
879 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
880 fBlock[i] = 0.0;
881 fBlockM2[i] = 0.0;
882 }
883 fHardwareBlockSum = 0.0;
886 } else {
887 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
888 fBlock[i] = fCalibrationFactor * ( (1.0 * fBlock_raw[i] / fBlockSample[i]) - fPedestal );
889 fBlockM2[i] = 0.0; // second moment is zero for single events
890 }
892 fHardwareBlockSumM2 = 0.0; // second moment is zero for single events
893 }
894 return;
895}
896
897
899{
900 //Double_t avgVolts = (fBlock[0]+fBlock[1]+fBlock[2]+fBlock[3])*kMollerADC_VoltsPerBit/fNumberOfSamples;
902 //std::cout<<"QwMollerADC_Channel::GetAverageVolts() = "<<avgVolts<<std::endl;
903 return avgVolts;
904
905}
906
908{
909 std::cout<<"***************************************"<<"\n";
910 std::cout<<"Subsystem "<<GetSubsystemName()<<"\n"<<"\n";
911 std::cout<<"Beam Instrument Type: "<<GetModuleType()<<"\n"<<"\n";
912 std::cout<<"QwMollerADC channel: "<<GetElementName()<<"\n"<<"\n";
913 std::cout<<"fPedestal= "<< fPedestal<<"\n";
914 std::cout<<"fCalibrationFactor= "<<fCalibrationFactor<<"\n";
915 std::cout<<"fBlocksPerEvent= "<<fBlocksPerEvent<<"\n"<<"\n";
916 std::cout<<"fSequenceNumber= "<<fSequenceNumber<<"\n";
917 std::cout<<"fNumberOfSamples= "<<fNumberOfSamples<<"\n";
918 std::cout<<"fBlock_raw ";
919
920 for (Int_t i = 0; i < fBlocksPerEvent; i++)
921 std::cout << " : " << fBlock_raw[i];
922 std::cout<<"\n";
923 std::cout<<"fHardwareBlockSum_raw= "<<fHardwareBlockSum_raw<<"\n";
924 std::cout<<"fSoftwareBlockSum_raw= "<<fSoftwareBlockSum_raw<<"\n";
925 std::cout<<"fBlock ";
926 for (Int_t i = 0; i < fBlocksPerEvent; i++)
927 std::cout << " : " <<std::setprecision(8) << fBlock[i];
928 std::cout << std::endl;
929
930 std::cout << "fHardwareBlockSum = "<<std::setprecision(8) <<fHardwareBlockSum << std::endl;
931 std::cout << "fHardwareBlockSumM2 = "<<fHardwareBlockSumM2 << std::endl;
932 std::cout << "fHardwareBlockSumError = "<<fHardwareBlockSumError << std::endl;
933
934 return;
935}
936
937void QwMollerADC_Channel::ConstructHistograms(TDirectory *folder, TString &prefix)
938{
939 // If we have defined a subdirectory in the ROOT file, then change into it.
940 if (folder != NULL) folder->cd();
941
942 if (IsNameEmpty()){
943 // This channel is not used, so skip filling the histograms.
944 } else {
945 // Now create the histograms.
946 SetDataToSaveByPrefix(prefix);
947
948 TString basename = prefix + GetElementName();
949
950 if(fDataToSave==kRaw)
951 {
952 fHistograms.resize(2*fBlocksPerEvent+2+1, NULL);
953 size_t index=0;
954 for (Int_t i=0; i<fBlocksPerEvent; i++){
955 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_block%d_raw",i));
956 fHistograms[index+1] = gQwHists.Construct1DHist(basename+Form("_block%d",i));
957 index += 2;
958 }
959 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_hw_raw"));
960 fHistograms[index+1] = gQwHists.Construct1DHist(basename+Form("_hw"));
961 index += 2;
962 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_sw-hw_raw"));
963 }
964 else if(fDataToSave==kDerived)
965 {
966 fHistograms.resize(fBlocksPerEvent+1+1, NULL);
967 Int_t index=0;
968 for (Int_t i=0; i<fBlocksPerEvent; i++){
969 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_block%d",i));
970 index += 1;
971 }
972 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_hw"));
973 index += 1;
974 fHistograms[index] = gQwHists.Construct1DHist(basename+Form("_dev_err"));
975 index += 1;
976 }
977 else
978 {
979 // this is not recognized
980 }
981
982 }
983}
984
986{
987 Int_t index=0;
988
989 if (IsNameEmpty())
990 {
991 // This channel is not used, so skip creating the histograms.
992 } else
993 {
994 if(fDataToSave==kRaw)
995 {
996 for (Int_t i=0; i<fBlocksPerEvent; i++)
997 {
998 if (fHistograms[index] != NULL && (fErrorFlag)==0)
999 fHistograms[index]->Fill(this->GetRawBlockValue(i));
1000 if (fHistograms[index+1] != NULL && (fErrorFlag)==0)
1001 fHistograms[index+1]->Fill(this->GetBlockValue(i));
1002 index+=2;
1003 }
1004 if (fHistograms[index] != NULL && (fErrorFlag)==0)
1005 fHistograms[index]->Fill(this->GetRawHardwareSum());
1006 if (fHistograms[index+1] != NULL && (fErrorFlag)==0)
1007 fHistograms[index+1]->Fill(this->GetHardwareSum());
1008 index+=2;
1009 if (fHistograms[index] != NULL && (fErrorFlag)==0)
1010 fHistograms[index]->Fill(this->GetRawSoftwareSum()-this->GetRawHardwareSum());
1011 }
1012 else if(fDataToSave==kDerived)
1013 {
1014 for (Int_t i=0; i<fBlocksPerEvent; i++)
1015 {
1016 if (fHistograms[index] != NULL && (fErrorFlag)==0)
1017 fHistograms[index]->Fill(this->GetBlockValue(i));
1018 index+=1;
1019 }
1020 if (fHistograms[index] != NULL && (fErrorFlag)==0)
1021 fHistograms[index]->Fill(this->GetHardwareSum());
1022 index+=1;
1023 if (fHistograms[index] != NULL){
1025 fHistograms[index]->Fill(kErrorFlag_sample);
1027 fHistograms[index]->Fill(kErrorFlag_SW_HW);
1029 fHistograms[index]->Fill(kErrorFlag_Sequence);
1031 fHistograms[index]->Fill(kErrorFlag_ZeroHW);
1033 fHistograms[index]->Fill(kErrorFlag_VQWK_Sat);
1035 fHistograms[index]->Fill(kErrorFlag_SameHW);
1036 }
1037
1038 }
1039
1040 }
1041}
1042
1044{
1045 // This channel is not used, so skip setting up the tree.
1046 if (IsNameEmpty()) return;
1047
1048 // Decide what to store based on prefix
1049 SetDataToSaveByPrefix(prefix);
1050
1051 TString basename = prefix(0, (prefix.First("|") >= 0)? prefix.First("|"): prefix.Length()) + GetElementName();
1052 fTreeArrayIndex = values.size();
1053
1054 TString list = "";
1055
1056 bHw_sum = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "hw_sum");
1057 bHw_sum_raw = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "hw_sum_raw");
1058 bBlock = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "block");
1059 bBlock_raw = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "block_raw");
1060 bNum_samples = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "num_samples");
1061 bDevice_Error_Code = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "Device_Error_Code");
1062 bSequence_number = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "sequence_number");
1063 const Bool_t save_new_decoder_fields = (fDecodeMode == kNewReshuffled);
1064
1065 if (bHw_sum) {
1066 values.push_back("hw_sum", 'D');
1067 if (save_new_decoder_fields) {
1068 values.push_back("hw_sum_rms", 'D');
1069 }
1070 if (fDataToSave == kMoments) {
1071 values.push_back("hw_sum_m2", 'D');
1072 values.push_back("hw_sum_err", 'D');
1073 }
1074 }
1075
1076 if (bBlock) {
1077 for (int i = 0; i < fBlocksPerEvent; i++) {
1078 values.push_back(Form("block%d", i), 'D');
1079 if (save_new_decoder_fields) {
1080 values.push_back(Form("block%d_rms", i), 'D');
1081 }
1082 }
1083 }
1084
1085 if (bNum_samples) {
1086 values.push_back("num_samples", 'i');
1087 }
1088
1089 if (save_new_decoder_fields) {
1090 values.push_back("region_number", 'D');
1091 values.push_back("region_timestamp", 'D');
1092 values.push_back("header_num_words", 'D');
1093 values.push_back("header_block_number", 'D');
1094 values.push_back("header_packet_count", 'D');
1095 values.push_back("header_tsamples", 'D');
1096 }
1097
1098 if (bDevice_Error_Code) {
1099 values.push_back("Device_Error_Code", 'i');
1100 }
1101
1102 if (fDataToSave == kRaw) {
1103 if (bHw_sum_raw) {
1104 values.push_back("hw_sum_raw", save_new_decoder_fields ? 'L' : 'I');
1105 }
1106 if (bBlock_raw) {
1107 for (int i = 0; i < fBlocksPerEvent; i++) {
1108 values.push_back(Form("block%d_raw",i), save_new_decoder_fields ? 'L' : 'I');
1109 }
1110
1111 }
1112
1113 if (bBlock_raw) {
1114 for (int i = 0; i < fBlocksPerEvent; i++) {
1115 values.push_back(Form("SumSq_%d", i), 'L');
1116 values.push_back(Form("RawMin_%d", i), 'I');
1117 values.push_back(Form("RawMax_%d", i), 'I');
1118 }
1119 }
1120
1121 if (bSequence_number) {
1122 values.push_back("sequence_number", 'i');
1123 }
1124 }
1125
1126 std::string leaf_list = values.LeafList(fTreeArrayIndex);
1127
1129
1130 if (gQwHists.MatchDeviceParamsFromList(basename.Data())
1133
1134 // This is for the RT mode
1135 if (leaf_list == "hw_sum/D")
1136 leaf_list = basename+"/D";
1137
1138 if (kDEBUG)
1139 QwMessage << "base name " << basename << " List " << leaf_list << QwLog::endl;
1140
1141 tree->Branch(basename, &(values[fTreeArrayIndex]), leaf_list.c_str());
1142 }
1143
1144 if (kDEBUG) {
1145 std::cerr << "QwMollerADC_Channel::ConstructBranchAndVector: fTreeArrayIndex==" << fTreeArrayIndex
1146 << "; fTreeArrayNumEntries==" << fTreeArrayNumEntries
1147 << "; values.size()==" << values.size()
1148 << "; list==" << leaf_list
1149 << std::endl;
1150 }
1151}
1152
1153void QwMollerADC_Channel::ConstructBranch(TTree *tree, TString &prefix)
1154{
1155 // This channel is not used, so skip setting up the tree.
1156 if (IsNameEmpty()) return;
1157
1158 TString basename = prefix + GetElementName();
1159 tree->Branch(basename,&fHardwareBlockSum,basename+"/D");
1160 if (kDEBUG){
1161 std::cerr << "QwMollerADC_Channel::ConstructBranchAndVector: fTreeArrayIndex==" << fTreeArrayIndex
1162 << "; fTreeArrayNumEntries==" << fTreeArrayNumEntries
1163 << std::endl;
1164 }
1165}
1166
1167
1169{
1170
1171
1172 if (IsNameEmpty()) {
1173 // This channel is not used, so skip filling the tree vector.
1174 } else if (fTreeArrayNumEntries <= 0) {
1175 if (bDEBUG) std::cerr << "QwMollerADC_Channel::FillTreeVector: fTreeArrayNumEntries=="
1176 << fTreeArrayNumEntries << std::endl;
1177 } else if (values.size() < fTreeArrayIndex+fTreeArrayNumEntries){
1178 if (bDEBUG) std::cerr << "QwMollerADC_Channel::FillTreeVector: values.size()=="
1179 << values.size()
1180 << "; fTreeArrayIndex+fTreeArrayNumEntries=="
1182 << std::endl;
1183 } else {
1184
1185 UInt_t index = fTreeArrayIndex;
1186 const Bool_t save_new_decoder_fields = (fDecodeMode == kNewReshuffled);
1187
1188 // hw_sum
1189 if (bHw_sum) {
1190 values.SetValue(index++, this->GetHardwareSum());
1191 if (save_new_decoder_fields) {
1192 values.SetValue(index++, this->GetHardwareSumRMS());
1193 }
1194 if (fDataToSave == kMoments) {
1195 values.SetValue(index++, this->GetHardwareSumM2());
1196 values.SetValue(index++, this->GetHardwareSumError());
1197 }
1198 }
1199
1200 if (bBlock) {
1201 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1202 values.SetValue(index++, this->GetBlockValue(i));
1203 if (save_new_decoder_fields) {
1204 values.SetValue(index++, this->GetBlockRMS(i));
1205 }
1206 }
1207 }
1208
1209 // num_samples
1210 if (bNum_samples)
1211 values.SetValue(index++, (fDataToSave == kMoments)? this->fGoodEventCount: this->fNumberOfSamples);
1212
1213 if (save_new_decoder_fields) {
1214 values.SetValue(index++, static_cast<Double_t>(this->fRegionNumber));
1215 values.SetValue(index++, static_cast<Double_t>(this->fRegionTimestamp));
1216 values.SetValue(index++, static_cast<Double_t>(this->fHeaderNumWords));
1217 values.SetValue(index++, static_cast<Double_t>(this->fHeaderBlockNumber));
1218 values.SetValue(index++, static_cast<Double_t>(this->fHeaderPacketCount));
1219 values.SetValue(index++, static_cast<Double_t>(this->fHeaderTSamples));
1220 }
1221
1222 // Device_Error_Code
1224 values.SetValue(index++, this->fErrorFlag);
1225
1226 if (fDataToSave == kRaw)
1227 {
1228 // hw_sum_raw
1229 if (bHw_sum_raw) {
1230 if (save_new_decoder_fields) {
1231 values.SetValue(index++, this->fHardwareBlockSum_raw);
1232 } else {
1233 values.SetValue(index++, this->GetRawHardwareSum());
1234 }
1235 }
1236
1237 if (bBlock_raw) {
1238 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1239 // blocki_raw
1240 if (save_new_decoder_fields) {
1241 values.SetValue(index++, this->fBlock_raw[i]);
1242 } else {
1243 values.SetValue(index++, this->GetRawBlockValue(i));
1244 }
1245 }
1246 }
1247
1248 if (bBlock_raw) {
1249 for (int i = 0; i < fBlocksPerEvent; i++) {
1250 values.SetValue(index++, fBlockSumSq_raw[i]);
1251 values.SetValue(index++, fBlock_min[i]);
1252 values.SetValue(index++, fBlock_max[i]);
1253 }
1254 }
1255 // sequence_number
1256 if (bSequence_number)
1257 values.SetValue(index++, this->fSequenceNumber);
1258 }
1259 }
1260 /*static int fill_debug_counter = 0;
1261if (fill_debug_counter < 10) {
1262 std::cout << "\n=== FILLTREE DEBUG Event " << fill_debug_counter << " ===\n"
1263 << "GetHardwareSumRMS() = " << this->GetHardwareSumRMS() << "\n"
1264 << "GetBlockRMS(0) = " << this->GetBlockRMS(0) << std::endl;
1265}
1266fill_debug_counter++; */
1267}
1268
1269#ifdef HAS_RNTUPLE_SUPPORT
1270void QwMollerADC_Channel::ConstructNTupleAndVector(std::unique_ptr<ROOT::RNTupleModel>& model, TString& prefix, std::vector<Double_t>& values, std::vector<std::shared_ptr<Double_t>>& fieldPtrs)
1271{
1272 //For rntuple
1273 if (IsNameEmpty()) {
1274 // This channel is not used, so skip setting up the RNTuple.
1275 } else {
1276 // Decide what to store based on prefix
1277 SetDataToSaveByPrefix(prefix);
1278
1279 // Set the boolean flags just like in ConstructBranchAndVector
1285 bDevice_Error_Code = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "Device_Error_Code");
1286 bSequence_number = gQwHists.MatchVQWKElementFromList(GetSubsystemName().Data(), GetModuleType().Data(), "sequence_number");
1287
1288 // For kMoments mode (running sum trees), enable all statistical fields regardless of histogram configuration
1289 if (fDataToSave == kMoments) {
1290 bHw_sum = true;
1291 bBlock = true;
1292 bNum_samples = true;
1293 bDevice_Error_Code = true;
1294 }
1295
1296 TString basename = prefix(0, (prefix.First("|") >= 0)? prefix.First("|"): prefix.Length()) + GetElementName();
1297 fTreeArrayIndex = values.size();
1298
1299 // For derived data (yield_, asym_, diff_), store with _hw_sum suffix for consistency
1300 if (fDataToSave == kDerived) {
1301 // Store the main hardware sum value with explicit _hw_sum suffix
1302 values.resize(values.size() + 1, 0.0);
1303 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_hw_sum").Data()));
1305 return;
1306 }
1307
1308 // For moments data (stat prefix), use the same structure as TTree to get exact field count match
1309 if (fDataToSave == kMoments) {
1310 // Create the same structure as TTree kMoments mode
1311 if (bHw_sum) {
1312 values.push_back(0.0);
1313 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_hw_sum").Data()));
1314 values.push_back(0.0);
1315 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_hw_sum_m2").Data()));
1316 values.push_back(0.0);
1317 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_hw_sum_err").Data()));
1318 }
1319
1320 if (bBlock) {
1321 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1322 values.push_back(0.0);
1323 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_block%d", i)).Data()));
1324 }
1325 }
1326
1327 if (bNum_samples) {
1328 values.push_back(0.0);
1329 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_num_samples").Data()));
1330 }
1331
1332 if (bDevice_Error_Code) {
1333 values.push_back(0.0);
1334 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_Device_Error_Code").Data()));
1335 }
1336
1337 fTreeArrayNumEntries = values.size() - fTreeArrayIndex;
1338 return;
1339 }
1340
1341 // For raw data, use the full detailed format
1342 // Calculate how many elements we need to avoid multiple push_back calls
1343 size_t numElements = 0;
1344
1345 // Count elements based on what will be saved
1346 if (bHw_sum) {
1347 numElements += 1; // hw_sum
1348 }
1349 if (bBlock) numElements += fBlocksPerEvent; // blocks
1350 if (bNum_samples) numElements += 1; // num_samples
1351 if (bDevice_Error_Code) numElements += 1; // error code
1352
1353 if (fDataToSave == kRaw) {
1354 if (bHw_sum_raw) numElements += 1; // hw_sum_raw
1355 if (bBlock_raw) numElements += fBlocksPerEvent; // block_raw
1356 numElements += 4*fBlocksPerEvent; // fBlockSumSq_raw (4*fBlocksPerEvent)
1357 if (bSequence_number) numElements += 1; // sequence_number
1358 }
1359
1360 // Resize vectors once to avoid reallocation
1361 size_t oldSize = values.size();
1362 values.resize(oldSize + numElements, 0.0);
1363 fieldPtrs.reserve(fieldPtrs.size() + numElements);
1364
1365 // Add fields in the same order as FillTreeVector
1366 // hw_sum
1367 if (bHw_sum) {
1368 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_hw_sum").Data()));
1369 }
1370
1371 if (bBlock) {
1372 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1373 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_block%d", i)).Data()));
1374 }
1375 }
1376
1377 // num_samples
1378 if (bNum_samples) {
1379 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_num_samples").Data()));
1380 }
1381
1382 // Device_Error_Code
1383 if (bDevice_Error_Code) {
1384 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_Device_Error_Code").Data()));
1385 }
1386
1387 if (fDataToSave == kRaw) {
1388 // hw_sum_raw
1389 if (bHw_sum_raw) {
1390 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_hw_sum_raw").Data()));
1391 }
1392
1393 if (bBlock_raw) {
1394 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1395 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_block%d_raw", i)).Data()));
1396 }
1397 }
1398
1399 for(int i = 0; i < fBlocksPerEvent; i++){
1400 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_sumsq%d_low", i)).Data()));
1401 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_sumsq%d_high", i)).Data()));
1402 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_min%d", i)).Data()));
1403 fieldPtrs.push_back(model->MakeField<Double_t>((basename + Form("_max%d", i)).Data()));
1404 }
1405
1406 // sequence_number
1407 if (bSequence_number) {
1408 fieldPtrs.push_back(model->MakeField<Double_t>((basename + "_sequence_number").Data()));
1409 }
1410 }
1411
1412 fTreeArrayNumEntries = values.size() - fTreeArrayIndex;
1413 }
1414}
1415
1416void QwMollerADC_Channel::FillNTupleVector(std::vector<Double_t>& values) const
1417{
1418 if (IsNameEmpty()) {
1419 // This channel is not used, so skip filling.
1420 } else if (fTreeArrayNumEntries <= 0) {
1421 if (bDEBUG) std::cerr << "QwMollerADC_Channel::FillNTupleVector: fTreeArrayNumEntries=="
1422 << fTreeArrayNumEntries << std::endl;
1423 } else if (values.size() < fTreeArrayIndex+fTreeArrayNumEntries){
1424 if (bDEBUG) std::cerr << "QwMollerADC_Channel::FillNTupleVector: values.size()=="
1425 << values.size()
1426 << "; fTreeArrayIndex+fTreeArrayNumEntries=="
1428 << std::endl;
1429 } else {
1430
1431 UInt_t index = fTreeArrayIndex;
1432
1433 // For derived data (yield_, asym_, diff_), only fill the main value to match TTree format
1434 if (fDataToSave == kDerived) {
1435 values[index] = this->GetHardwareSum();
1436 return;
1437 }
1438
1439
1440 // For raw data, use the full detailed format
1441 // hw_sum
1442 if (bHw_sum) {
1443 values[index++] = this->GetHardwareSum();
1444 }
1445
1446 if (bBlock) {
1447 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1448 // blocki
1449 values[index++] = this->GetBlockValue(i);
1450 }
1451 }
1452
1453 // num_samples
1454 if (bNum_samples)
1455 values[index++] = fDataToSave == kMoments ? this->fGoodEventCount : this->fNumberOfSamples;
1456
1457 // Device_Error_Code
1459 values[index++] = this->fErrorFlag;
1460
1461 if (fDataToSave == kRaw)
1462 {
1463 // hw_sum_raw
1464 if (bHw_sum_raw)
1465 values[index++] = this->GetRawHardwareSum();
1466
1467 if (bBlock_raw) {
1468 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1469 // blocki_raw
1470 values[index++] = this->GetRawBlockValue(i);
1471 }
1472 }
1473
1474 for(int i = 0; i < fBlocksPerEvent; i++){
1475 values[index++] = fBlockSumSq_raw[i] & 0xffffffff;
1476 values[index++] = fBlockSumSq_raw[i] >> 32;
1477 values[index++] = fBlock_min[i];
1478 values[index++] = fBlock_max[i];
1479 }
1480 // sequence_number
1481 if (bSequence_number)
1482 values[index++] = this->fSequenceNumber;
1483 }
1484 }
1485}
1486#endif // HAS_RNTUPLE_SUPPORT
1487
1489{
1490 if(this ==&value) return *this;
1491
1492 if (!IsNameEmpty()) {
1494 for (Int_t i=0; i<fBlocksPerEvent; i++){
1495 this->fBlock[i] = value.fBlock[i];
1496 this->fBlockM2[i] = value.fBlockM2[i];
1497 this->fBlockRMS[i] = value.fBlockRMS[i]; // I added this
1498 }
1499
1503 this->fHardwareBlockSumRMS = value.fHardwareBlockSumRMS; // I added this
1504 this->fNumberOfSamples = value.fNumberOfSamples;
1505 this->fSequenceNumber = value.fSequenceNumber;
1506 //added this
1507this->fRegionNumber = value.fRegionNumber;
1509this->fHeaderNumWords = value.fHeaderNumWords;
1512this->fHeaderTSamples = value.fHeaderTSamples;
1513
1514
1515 if (this->fDataToSave == kRaw){
1516 for (Int_t i=0; i<fBlocksPerEvent; i++){
1517 this->fBlock_raw[i] = value.fBlock_raw[i];
1518 this->fBlockSumSq_raw[i] = value.fBlockSumSq_raw[i];
1519 this->fBlock_min[i] = value.fBlock_min[i];
1520 this->fBlock_max[i] = value.fBlock_max[i];
1521 this->fBlockSample[i] = value.fBlockSample[i]; // I added this
1522 }
1525 }
1526 }
1527 return *this;
1528}
1529
1531 Double_t scale)
1532{
1533 if(this == &value) return;
1534
1535 if (!IsNameEmpty()) {
1536 for (Int_t i=0; i<fBlocksPerEvent; i++){
1537 this->fBlock[i] = value.fBlock[i] * scale;
1538 this->fBlockM2[i] = value.fBlockM2[i] * scale * scale;
1539
1540 }
1541 this->fHardwareBlockSum = value.fHardwareBlockSum * scale;
1542 this->fHardwareBlockSumM2 = value.fHardwareBlockSumM2 * scale * scale;
1543 this->fHardwareBlockSumError = value.fHardwareBlockSumError; // Keep this?
1544 this->fGoodEventCount = value.fGoodEventCount;
1545 this->fNumberOfSamples = value.fNumberOfSamples;
1546 this->fSequenceNumber = value.fSequenceNumber;
1547 this->fErrorFlag = value.fErrorFlag;
1548 }
1549}
1550
1552{
1553 const QwMollerADC_Channel* tmpptr;
1554 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1555 if (tmpptr!=NULL){
1556 *this = *tmpptr;
1557 } else {
1558 TString loc="Standard exception from QwMollerADC_Channel::AssignValueFrom = "
1559 +valueptr->GetElementName()+" is an incompatible type.";
1560 throw std::invalid_argument(loc.Data());
1561 }
1562}
1564{
1565 const QwMollerADC_Channel* tmpptr;
1566 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1567 if (tmpptr!=NULL){
1568 *this += *tmpptr;
1569 } else {
1570 TString loc="Standard exception from QwMollerADC_Channel::AddValueFrom = "
1571 +valueptr->GetElementName()+" is an incompatible type.";
1572 throw std::invalid_argument(loc.Data());
1573 }
1574}
1576{
1577 const QwMollerADC_Channel* tmpptr;
1578 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1579 if (tmpptr!=NULL){
1580 *this -= *tmpptr;
1581 } else {
1582 TString loc="Standard exception from QwMollerADC_Channel::SubtractValueFrom = "
1583 +valueptr->GetElementName()+" is an incompatible type.";
1584 throw std::invalid_argument(loc.Data());
1585 }
1586}
1588{
1589 const QwMollerADC_Channel* tmpptr;
1590 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1591 if (tmpptr!=NULL){
1592 *this *= *tmpptr;
1593 } else {
1594 TString loc="Standard exception from QwMollerADC_Channel::MultiplyBy = "
1595 +valueptr->GetElementName()+" is an incompatible type.";
1596 throw std::invalid_argument(loc.Data());
1597 }
1598}
1600{
1601 const QwMollerADC_Channel* tmpptr;
1602 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
1603 if (tmpptr!=NULL){
1604 *this /= *tmpptr;
1605 } else {
1606 TString loc="Standard exception from QwMollerADC_Channel::DivideBy = "
1607 +valueptr->GetElementName()+" is an incompatible type.";
1608 throw std::invalid_argument(loc.Data());
1609 }
1610}
1611
1612
1614{
1615 QwMollerADC_Channel result = *this;
1616 result += value;
1617 return result;
1618}
1619
1621{
1622
1623 if (!IsNameEmpty()) {
1624 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1625 this->fBlock[i] += value.fBlock[i];
1626 this->fBlockM2[i] = 0.0;
1627 }
1628 this->fHardwareBlockSum += value.fHardwareBlockSum;
1629 this->fHardwareBlockSumM2 = 0.0;
1630 this->fNumberOfSamples += value.fNumberOfSamples;
1631 this->fSequenceNumber = 0;
1632 this->fErrorFlag |= (value.fErrorFlag);
1633 //added this
1634this->fRegionNumber = value.fRegionNumber;
1636this->fHeaderNumWords = value.fHeaderNumWords;
1639this->fHeaderTSamples = value.fHeaderTSamples;
1640 }
1641
1642 return *this;
1643}
1644
1646{
1647 QwMollerADC_Channel result = *this;
1648 result -= value;
1649 return result;
1650}
1651
1653{
1654 if (!IsNameEmpty()){
1655 for (Int_t i=0; i<fBlocksPerEvent; i++){
1656 this->fBlock[i] -= value.fBlock[i];
1657 this->fBlockM2[i] = 0.0;
1658 }
1659 this->fHardwareBlockSum -= value.fHardwareBlockSum;
1660 this->fHardwareBlockSumM2 = 0.0;
1661 this->fNumberOfSamples += value.fNumberOfSamples;
1662 this->fSequenceNumber = 0;
1663 this->fErrorFlag |= (value.fErrorFlag);
1664 //added this
1665this->fRegionNumber = value.fRegionNumber;
1667this->fHeaderNumWords = value.fHeaderNumWords;
1670this->fHeaderTSamples = value.fHeaderTSamples;
1671 }
1672
1673 return *this;
1674}
1675
1677{
1678 QwMollerADC_Channel result = *this;
1679 result *= value;
1680 return result;
1681}
1682
1684{
1685 if (!IsNameEmpty()){
1686 for (Int_t i=0; i<fBlocksPerEvent; i++){
1687 this->fBlock[i] *= value.fBlock[i];
1688 this->fBlockM2[i] = 0.0;
1689 }
1690 this->fHardwareBlockSum *= value.fHardwareBlockSum;
1691 this->fHardwareBlockSumM2 = 0.0;
1692 this->fNumberOfSamples *= value.fNumberOfSamples;
1693 this->fSequenceNumber = 0;
1694 this->fErrorFlag |= (value.fErrorFlag);
1695 //added this
1696this->fRegionNumber = value.fRegionNumber;
1698this->fHeaderNumWords = value.fHeaderNumWords;
1701this->fHeaderTSamples = value.fHeaderTSamples;
1702 }
1703
1704 return *this;
1705}
1706
1708{
1709 const QwMollerADC_Channel* tmpptr;
1710 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(&source);
1711 if (tmpptr!=NULL){
1712 *this += *tmpptr;
1713 } else {
1714 TString loc="Standard exception from QwMollerADC_Channel::operator+= "
1715 +source.GetElementName()+" "
1716 +this->GetElementName()+" are not of the same type";
1717 throw(std::invalid_argument(loc.Data()));
1718 }
1719 return *this;
1720}
1722{
1723 const QwMollerADC_Channel* tmpptr;
1724 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(&source);
1725 if (tmpptr!=NULL){
1726 *this -= *tmpptr;
1727 } else {
1728 TString loc="Standard exception from QwMollerADC_Channel::operator-= "
1729 +source.GetElementName()+" "
1730 +this->GetElementName()+" are not of the same type";
1731 throw(std::invalid_argument(loc.Data()));
1732 }
1733 return *this;
1734}
1736{
1737 const QwMollerADC_Channel* tmpptr;
1738 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(&source);
1739 if (tmpptr!=NULL){
1740 *this *= *tmpptr;
1741 } else {
1742 TString loc="Standard exception from QwMollerADC_Channel::operator*= "
1743 +source.GetElementName()+" "
1744 +this->GetElementName()+" are not of the same type";
1745 throw(std::invalid_argument(loc.Data()));
1746 }
1747 return *this;
1748}
1750{
1751 const QwMollerADC_Channel* tmpptr;
1752 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(&source);
1753 if (tmpptr!=NULL){
1754 *this /= *tmpptr;
1755 } else {
1756 TString loc="Standard exception from QwMollerADC_Channel::operator/= "
1757 +source.GetElementName()+" "
1758 +this->GetElementName()+" are not of the same type";
1759 throw(std::invalid_argument(loc.Data()));
1760 }
1761 return *this;
1762}
1763
1764
1766{
1767 *this = value1;
1768 *this += value2;
1769}
1770
1772{
1773 *this = value1;
1774 *this -= value2;
1775}
1776
1778{
1779 if (!IsNameEmpty()) {
1780 *this = numer;
1781 *this /= denom;
1782
1784 fSequenceNumber = 0;
1786 fErrorFlag = (numer.fErrorFlag|denom.fErrorFlag);
1787 }
1788}
1789
1791{
1792 // In this function, leave the "raw" variables untouched.
1793 //
1794 Double_t ratio;
1795 Double_t variance;
1796 if (!IsNameEmpty()) {
1797 // The variances are calculated using the following formula:
1798 // Var[ratio] = ratio^2 (Var[numer] / numer^2 + Var[denom] / denom^2)
1799 //
1800 // This requires that both the numerator and denominator are non-zero!
1801 //
1802 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1803 if (this->fBlock[i] != 0.0 && denom.fBlock[i] != 0.0){
1804 ratio = (this->fBlock[i]) / (denom.fBlock[i]);
1805 variance = ratio * ratio *
1806 (this->fBlockM2[i] / this->fBlock[i] / this->fBlock[i]
1807 + denom.fBlockM2[i] / denom.fBlock[i] / denom.fBlock[i]);
1808 fBlock[i] = ratio;
1809 fBlockM2[i] = variance;
1810 } else if (this->fBlock[i] == 0.0) {
1811 this->fBlock[i] = 0.0;
1812 this->fBlockM2[i] = 0.0;
1813 } else {
1814 QwVerbose << "Attempting to divide by zero block in "
1816 fBlock[i] = 0.0;
1817 fBlockM2[i] = 0.0;
1818 }
1819 }
1820 if (this->fHardwareBlockSum != 0.0 && denom.fHardwareBlockSum != 0.0){
1821 ratio = (this->fHardwareBlockSum) / (denom.fHardwareBlockSum);
1822 variance = ratio * ratio *
1825 fHardwareBlockSum = ratio;
1826 fHardwareBlockSumM2 = variance;
1827 } else if (this->fHardwareBlockSum == 0.0) {
1828 fHardwareBlockSum = 0.0;
1829 fHardwareBlockSumM2 = 0.0;
1830 } else {
1831 QwVerbose << "Attempting to divide by zero sum in "
1833 fHardwareBlockSumM2 = 0.0;
1834 }
1835 // Remaining variables
1836 // Don't change fNumberOfSamples, fSequenceNumber, fGoodEventCount,
1837 // 'OR' the HW error codes in the fErrorFlag values together.
1838 fErrorFlag |= (denom.fErrorFlag);//mix only the hardware error codes
1839 }
1840// added this
1841this->fRegionNumber = denom.fRegionNumber;
1843this->fHeaderNumWords = denom.fHeaderNumWords;
1846this->fHeaderTSamples = denom.fHeaderTSamples;
1847 // Nanny
1849 QwWarning << "Angry Nanny: NaN detected in " << GetElementName() << QwLog::endl;
1850
1851 return *this;
1852}
1853
1854//--------------------------------------------------------------------------------------------
1855
1857{
1858 if (!IsNameEmpty()) {
1859 this->fHardwareBlockSum = 0.0;
1860 for (Int_t i=0; i<fBlocksPerEvent; i++) {
1861 this->fBlock[i] = atan(value.fBlock[i]);
1862 this->fHardwareBlockSum += this->fBlock[i];
1863 }
1865 }
1866
1867 return;
1868}
1869
1870//--------------------------------------------------------------------------------------------
1872{
1873 if (!IsNameEmpty()){
1874 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1875 this->fBlock[i] = (value1.fBlock[i]) * (value2.fBlock[i]);
1876 // For a single event the second moment is still zero
1877 this->fBlockM2[i] = 0.0;
1878 }
1879
1880 // For a single event the second moment is still zero
1881 this->fHardwareBlockSumM2 = 0.0;
1883 this->fNumberOfSamples = value1.fNumberOfSamples;
1884 this->fSequenceNumber = 0;
1885 this->fErrorFlag = (value1.fErrorFlag|value2.fErrorFlag);
1886 }
1887 return;
1888}
1889
1890/**
1891This function will add a offset to the hw_sum and add the same offset for blocks.
1892 */
1894{
1895 if (!IsNameEmpty()){
1896 fHardwareBlockSum += offset;
1897 for (Int_t i=0; i<fBlocksPerEvent; i++)
1898 fBlock[i] += offset;
1899 }
1900 return;
1901}
1902
1903void QwMollerADC_Channel::Scale(Double_t scale)
1904{
1905 if (!IsNameEmpty()){
1906 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
1907 fBlock[i] *= scale;
1908 fBlockM2[i] *= scale * scale;
1909 }
1910 fHardwareBlockSum *= scale;
1911 fHardwareBlockSumM2 *= scale * scale;
1912 }
1913}
1914
1915
1917{
1918 *this /= denom;
1919}
1920
1921
1922
1923
1924
1925
1926/** Moments and uncertainty calculation on the running sums and averages
1927 * The calculation of the first and second moments of the running sum is not
1928 * completely straightforward due to numerical instabilities associated with
1929 * small variances and large average values. The naive computation taking
1930 * the difference of the square of the average and the average of the squares
1931 * leads to the subtraction of two very large numbers to get a small number.
1932 *
1933 * Alternative algorithms (including for higher order moments) are supplied in
1934 * Pebay, Philippe (2008), "Formulas for Robust, One-Pass Parallel Computation
1935 * of Covariances and Arbitrary-Order Statistical Moments", Technical Report
1936 * SAND2008-6212, Sandia National Laboratories.
1937 * http://infoserve.sandia.gov/sand_doc/2008/086212.pdf
1938 *
1939 * In the following formulas the moments \f$ M^1 \f$ and \f$ M^2 \f$ are defined
1940 * \f{eqnarray}
1941 * M^1 & = & \frac{1}{n} \sum^n y \\
1942 * M^2 & = & \sum^n (y - \mu)
1943 * \f}
1944 *
1945 * Recurrence relations for the addition of a single event:
1946 * \f{eqnarray}
1947 * M^1_n & = & M^1_{n-1} + \frac{y - M^1_{n-1}}{n} \\
1948 * M^2_n & = & M^2_{n-1} + (y - M^1_{n-1})(y - M^1_n)
1949 * \f}
1950 *
1951 * For the addition of an already accumulated sum:
1952 * \f{eqnarray}
1953 * M^1 & = & M^1_1 + n_2 \frac{M^1_2 - M^1_1}{n} \\
1954 * M^2 & = & M^2_1 + M^2_2 + n_1 n_2 \frac{(M^1_2 - M^1_1)^2}{n}
1955 * \f}
1956 *
1957 * In these recursive formulas we start from \f$ M^1 = y \f$ and \f$ M^2 = 0 \f$.
1958 *
1959 * To calculate the mean and standard deviation we use
1960 * \f{eqnarray}
1961 * \mu & = & M^1 \\
1962 * \sigma^2 & = & \frac{1}{n} M^2
1963 * \f}
1964 * The standard deviation is a biased estimator, but this is what ROOT uses.
1965 * Better would be to divide by \f$ (n-1) \f$.
1966 *
1967 * We use the formulas provided there for the calculation of the first and
1968 * second moments (i.e. average and variance).
1969 */
1970// Accumulate the running moments M1 and M2.
1971// See header for parameter and return documentation.
1972void QwMollerADC_Channel::AccumulateRunningSum(const QwMollerADC_Channel& value, Int_t count, Int_t ErrorMask)
1973{
1974 /*
1975 note:
1976 The AccumulateRunningSum is called on a dedicated subsystem array object and
1977 for the standard running avg computations we only need value.fErrorFlag==0
1978 events to be included in the running avg. So the "berror" conditions is only
1979 used for the stability check purposes.
1980
1981 The need for this check below came due to fact that when routine
1982 DeaccumulateRunningSum is called the errorflag is updated with
1983 the kBeamStabilityError flag (+ configuration flags for global errors) and
1984 need to make sure we remove this flag and any configuration flags before
1985 checking the (fErrorFlag != 0) condition
1986
1987 See how the stability check is implemented in the QwEventRing class
1988
1989 Rakitha
1990 */
1991
1992 if(count==0){
1993 count = value.fGoodEventCount;
1994 }
1995
1996 Int_t n1 = fGoodEventCount;
1997 Int_t n2 = count;
1998
1999 // If there are no good events, check the error flag
2000 if (n2 == 0 && (value.fErrorFlag == 0)) {
2001 n2 = 1;
2002 }
2003
2004 // If a single event is removed from the sum, check all but stability fail flags
2005 if (n2 == -1) {
2006 if ((value.fErrorFlag & ErrorMask) == 0) {
2007 n2 = -1;
2008 } else {
2009 n2 = 0;
2010 }
2011 }
2012
2013 if (ErrorMask == kPreserveError){
2014 //n = 1;
2015 if (n2 == 0) {
2016 n2 = 1;
2017 }
2018 if (count == -1) {
2019 n2 = -1;
2020 }
2021 }
2022
2023 // New total number of good events
2024 Int_t n = n1 + n2;
2025
2026 // Set up variables
2027 Double_t M11 = fHardwareBlockSum;
2028 Double_t M12 = value.fHardwareBlockSum;
2029 Double_t M22 = value.fHardwareBlockSumM2;
2030
2031 //if(this->GetElementName() == "bcm_an_ds3" && ErrorMask == kPreserveError){QwError << "count=" << fGoodEventCount << " n=" << n << QwLog::endl; }
2032 if (n2 == 0) {
2033 // no good events for addition
2034 return;
2035 } else if (n2 == -1) {
2036 // simple version for removal of single event from the sum
2038 if (n > 1) {
2039 fHardwareBlockSum -= (M12 - M11) / n;
2040 fHardwareBlockSumM2 -= (M12 - M11)
2041 * (M12 - fHardwareBlockSum); // note: using updated mean
2042 // and for individual blocks
2043 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
2044 M11 = fBlock[i];
2045 M12 = value.fBlock[i];
2046 M22 = value.fBlockM2[i];
2047 fBlock[i] -= (M12 - M11) / n;
2048 fBlockM2[i] -= (M12 - M11) * (M12 - fBlock[i]); // note: using updated mean
2049 }
2050 } else if (n == 1) {
2051 fHardwareBlockSum -= (M12 - M11) / n;
2052 fHardwareBlockSumM2 -= (M12 - M11)
2053 * (M12 - fHardwareBlockSum); // note: using updated mean
2054 if (fabs(fHardwareBlockSumM2) < 10.*std::numeric_limits<double>::epsilon())
2055 fHardwareBlockSumM2 = 0; // rounding
2056 // and for individual blocks
2057 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
2058 M11 = fBlock[i];
2059 M12 = value.fBlock[i];
2060 M22 = value.fBlockM2[i];
2061 fBlock[i] -= (M12 - M11) / n;
2062 fBlockM2[i] -= (M12 - M11) * (M12 - fBlock[i]); // note: using updated mean
2063 if (fabs(fBlockM2[i]) < 10.*std::numeric_limits<double>::epsilon())
2064 fBlockM2[i] = 0; // rounding
2065 }
2066 } else if (n == 0) {
2067 fHardwareBlockSum -= M12;
2068 fHardwareBlockSumM2 -= M22;
2069 if (fabs(fHardwareBlockSum) < 10.*std::numeric_limits<double>::epsilon())
2070 fHardwareBlockSum = 0; // rounding
2071 if (fabs(fHardwareBlockSumM2) < 10.*std::numeric_limits<double>::epsilon())
2072 fHardwareBlockSumM2 = 0; // rounding
2073 // and for individual blocks
2074 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
2075 M11 = fBlock[i];
2076 M12 = value.fBlock[i];
2077 M22 = value.fBlockM2[i];
2078 fBlock[i] -= M12;
2079 fBlockM2[i] -= M22;
2080 if (fabs(fBlock[i]) < 10.*std::numeric_limits<double>::epsilon())
2081 fBlock[i] = 0; // rounding
2082 if (fabs(fBlockM2[i]) < 10.*std::numeric_limits<double>::epsilon())
2083 fBlockM2[i] = 0; // rounding
2084 }
2085 } else {
2086 QwWarning << "Running sum has deaccumulated to negative good events." << QwLog::endl;
2087 }
2088 } else if (n2 == 1) {
2089 // simple version for addition of single event
2091 fHardwareBlockSum += (M12 - M11) / n;
2092 fHardwareBlockSumM2 += (M12 - M11)
2093 * (M12 - fHardwareBlockSum); // note: using updated mean
2094 // and for individual blocks
2095 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
2096 M11 = fBlock[i];
2097 M12 = value.fBlock[i];
2098 M22 = value.fBlockM2[i];
2099 fBlock[i] += (M12 - M11) / n;
2100 fBlockM2[i] += (M12 - M11) * (M12 - fBlock[i]); // note: using updated mean
2101 }
2102 } else if (n2 > 1) {
2103 // general version for addition of multi-event sets
2104 fGoodEventCount += n2;
2105 fHardwareBlockSum += n2 * (M12 - M11) / n;
2106 fHardwareBlockSumM2 += M22 + n1 * n2 * (M12 - M11) * (M12 - M11) / n;
2107 // and for individual blocks
2108 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
2109 M11 = fBlock[i];
2110 M12 = value.fBlock[i];
2111 M22 = value.fBlockM2[i];
2112 fBlock[i] += n2 * (M12 - M11) / n;
2113 fBlockM2[i] += M22 + n1 * n2 * (M12 - M11) * (M12 - M11) / n;
2114 }
2115 }
2116
2117 // Nanny
2119 QwWarning << "Angry Nanny: NaN detected in " << GetElementName() << QwLog::endl;
2120}
2121
2122
2124{
2125 if (fGoodEventCount <= 0)
2126 {
2127 for (Int_t i = 0; i < fBlocksPerEvent; i++) {
2128 fBlockError[i] = 0.0;
2129 }
2131 }
2132 else
2133 {
2134 // We use a biased estimator by dividing by n. Use (n - 1) to get the
2135 // unbiased estimator for the standard deviation.
2136 //
2137 // Note we want to calculate the error here, not sigma:
2138 // sigma = sqrt(M2 / n);
2139 // error = sigma / sqrt (n) = sqrt(M2) / n;
2140 for (Int_t i = 0; i < fBlocksPerEvent; i++)
2141 fBlockError[i] = sqrt(fBlockM2[i]) / fGoodEventCount;
2143
2144 // Stability check 83951872
2146 // check to see the channel has stability cut activated in the event cut file
2147 if (GetValueWidth() > fStability){
2148 // if the width is greater than the stability required flag the event
2150 } else
2151 fErrorFlag = 0;
2152 }
2153 }
2154}
2155
2156
2158{
2159 QwMessage << std::setprecision(8)
2160 << std::setw(18) << std::left << GetSubsystemName() << " "
2161 << std::setw(18) << std::left << GetModuleType() << " "
2162 << std::setw(18) << std::left << GetElementName() << " "
2163 << std::setw(12) << std::left << GetHardwareSum() << " +/- "
2164 << std::setw(12) << std::left << GetHardwareSumError() << " sig "
2165 << std::setw(12) << std::left << GetHardwareSumWidth() << " "
2166 << std::setw(10) << std::left << GetGoodEventCount() << " "
2167 << std::setw(12) << std::left << GetBlockValue(0) << " +/- "
2168 << std::setw(12) << std::left << GetBlockErrorValue(0) << " "
2169 << std::setw(12) << std::left << GetBlockValue(1) << " +/- "
2170 << std::setw(12) << std::left << GetBlockErrorValue(1) << " "
2171 << std::setw(12) << std::left << GetBlockValue(2) << " +/- "
2172 << std::setw(12) << std::left << GetBlockErrorValue(2) << " "
2173 << std::setw(12) << std::left << GetBlockValue(3) << " +/- "
2174 << std::setw(12) << std::left << GetBlockErrorValue(3) << " "
2175 << std::setw(12) << std::left << fGoodEventCount << " "
2176 << QwLog::endl;
2177 /*
2178 //for Debudding
2179 << std::setw(12) << std::left << fErrorFlag << " err "
2180 << std::setw(12) << std::left << fErrorConfigFlag << " c-err "
2181
2182 */
2183}
2184
2185std::ostream& operator<< (std::ostream& stream, const QwMollerADC_Channel& channel)
2186{
2187 stream << channel.GetHardwareSum();
2188 return stream;
2189}
2190
2191/**
2192 * Blind this channel as an asymmetry
2193 * @param blinder Blinder
2194 */
2196{
2197 if (!IsNameEmpty()) {
2198 if (blinder->IsBlinderOkay() && ((fErrorFlag)==0) ){
2199 for (Int_t i = 0; i < fBlocksPerEvent; i++)
2200 blinder->BlindValue(fBlock[i]);
2201 blinder->BlindValue(fHardwareBlockSum);
2202 } else {
2204 for (Int_t i = 0; i < fBlocksPerEvent; i++)
2207 }
2208 }
2209 return;
2210}
2211
2212/**
2213 * Blind this channel as a difference with specified yield
2214 * @param blinder Blinder
2215 * @param yield Corresponding yield
2216 */
2218{
2219 if (!IsNameEmpty()) {
2220 if (blinder->IsBlinderOkay() && ((fErrorFlag) ==0) ){
2221 for (Int_t i = 0; i < fBlocksPerEvent; i++)
2222 blinder->BlindValue(fBlock[i], yield.fBlock[i]);
2224 } else {
2225 blinder->ModifyThisErrorCode(fErrorFlag);//update the HW error code
2226 for (Int_t i = 0; i < fBlocksPerEvent; i++)
2229 }
2230 }
2231 return;
2232}
2233
2235{
2236
2237 Bool_t status = kTRUE;
2238 if (!IsNameEmpty()){
2239 status = (fSequenceNumber==seqnum);
2240 }
2241 return status;
2242}
2243
2245{
2246 Bool_t status = kTRUE;
2247 if (!IsNameEmpty()){
2248 status = (fNumberOfSamples==numsamp);
2249 if (! status){
2250 if (bDEBUG)
2251 std::cerr << "QwMollerADC_Channel::MatchNumberOfSamples: Channel "
2252 << GetElementName()
2253 << " had fNumberOfSamples==" << fNumberOfSamples
2254 << " and was supposed to have " << numsamp
2255 << std::endl;
2256 // PrintChannel();
2257 }
2258 }
2259 return status;
2260}
2261
2262Bool_t QwMollerADC_Channel::ApplySingleEventCuts(Double_t LL,Double_t UL)//only check to see HW_Sum is within these given limits
2263{
2264 Bool_t status = kFALSE;
2265
2266 if (UL < LL){
2267 status=kTRUE;
2268 } else if (GetHardwareSum()<=UL && GetHardwareSum()>=LL){
2269 if ((fErrorFlag & kPreserveError)!=0)
2270 status=kTRUE;
2271 else
2272 status=kFALSE;//If the device HW is failed
2273 }
2274 std::cout<<(this->fErrorFlag & kPreserveError)<<std::endl;
2275 return status;
2276}
2277
2278Bool_t QwMollerADC_Channel::ApplySingleEventCuts()//This will check the limits and update event_flags and error counters
2279{
2280 Bool_t status;
2281
2282 if (bEVENTCUTMODE>=2){//Global switch to ON/OFF event cuts set at the event cut file
2283
2284 if (fULimit < fLLimit){
2285 status=kTRUE;
2286 } else if (GetHardwareSum()<=fULimit && GetHardwareSum()>=fLLimit){
2287 if ((fErrorFlag)==0)
2288 status=kTRUE;
2289 else
2290 status=kFALSE;//If the device HW is failed
2291 }
2292 else{
2293 if (GetHardwareSum()> fULimit)
2295 else
2297 status=kFALSE;
2298 }
2299
2300 if (bEVENTCUTMODE==3){
2301 status=kTRUE; //Update the event cut fail flag but pass the event.
2302 }
2303
2304
2305 }
2306 else{
2307 status=kTRUE;
2308 //fErrorFlag=0;//we need to keep the device error codes
2309 }
2310
2311 return status;
2312}
2313
2315{
2316 TString message;
2317 message = Form("%30s","Device name");
2318 message += Form("%9s", "HW Sat");
2319 message += Form("%9s", "Sample");
2320 message += Form("%9s", "SW_HW");
2321 message += Form("%9s", "Sequence");
2322 message += Form("%9s", "SameHW");
2323 message += Form("%9s", "ZeroHW");
2324 message += Form("%9s", "EventCut");
2325 QwMessage << "---------------------------------------------------------------------------------------------" << QwLog::endl;
2326 QwMessage << message << QwLog::endl;
2327 QwMessage << "---------------------------------------------------------------------------------------------" << QwLog::endl;
2328 return;
2329}
2330
2332{
2333 QwMessage << "---------------------------------------------------------------------------------------------" << QwLog::endl;
2334 return;
2335}
2336
2338{
2339 TString message;
2341 message = Form("%30s", GetElementName().Data());
2342 message += Form("%9d", fErrorCount_HWSat);
2343 message += Form("%9d", fErrorCount_sample);
2344 message += Form("%9d", fErrorCount_SW_HW);
2345 message += Form("%9d", fErrorCount_Sequence);
2346 message += Form("%9d", fErrorCount_SameHW);
2347 message += Form("%9d", fErrorCount_ZeroHW);
2348 message += Form("%9d", fNumEvtsWithEventCutsRejected);
2349
2350 if((fDataToSave == kRaw) && (!kFoundPedestal||!kFoundGain)){
2351 message += " >>>>> No Pedestal or Gain in map file";
2352 }
2353
2354 QwMessage << message << QwLog::endl;
2355 }
2356 return;
2357}
2358
2359void QwMollerADC_Channel::ScaledAdd(Double_t scale, const VQwHardwareChannel *value)
2360{
2361 const QwMollerADC_Channel* input = dynamic_cast<const QwMollerADC_Channel*>(value);
2362
2363 // follows same steps as += but w/ scaling factor
2364 if(input!=NULL && !IsNameEmpty()){
2365 // QwWarning << "Adding " << input->GetElementName()
2366 // << " to " << GetElementName()
2367 // << " with scale factor " << scale
2368 // << QwLog::endl;
2369 // PrintValue();
2370 // input->PrintValue();
2371 for(Int_t i = 0; i < fBlocksPerEvent; i++){
2372 this -> fBlock[i] += scale * input->fBlock[i];
2373 this -> fBlockM2[i] = 0.0;
2374 }
2375 this -> fHardwareBlockSum += scale * input->fHardwareBlockSum;
2376 this -> fHardwareBlockSumM2 = 0.0;
2377 this -> fNumberOfSamples += input->fNumberOfSamples;
2378 this -> fSequenceNumber = 0;
2379 this -> fErrorFlag |= (input->fErrorFlag);
2380 } else if (input == NULL && value != NULL) {
2381 TString loc="Standard exception from QwMollerADC_Channel::ScaledAdd "
2382 +value->GetElementName()+" "
2383 +this->GetElementName()+" are not of the same type";
2384 throw(std::invalid_argument(loc.Data()));
2385 }
2386}
2387
2389 const QwMollerADC_Channel* tmpptr;
2390 tmpptr = dynamic_cast<const QwMollerADC_Channel*>(valueptr);
2391 if (tmpptr!=NULL){
2396 } else {
2397 TString loc="Standard exception from QwMollerADC_Channel::CopyParameters"
2398 +valueptr->GetElementName()+" "
2399 +this->GetElementName()+" are not of the same type";
2400 throw(std::invalid_argument(loc.Data()));
2401 }
2402};
2403
2404#ifdef __USE_DATABASE__
2405void QwMollerADC_Channel::AddErrEntriesToList(std::vector<QwErrDBInterface> &row_list)
2406{
2407
2408 QwErrDBInterface row;
2409 TString name = GetElementName();
2410
2411 row.Reset();
2412 row.SetDeviceName(name);
2413 row.SetErrorCodeId(1);
2415 row_list.push_back(row);
2416
2417 row.Reset();
2418 row.SetDeviceName(name);
2419 row.SetErrorCodeId(2);
2421 row_list.push_back(row);
2422
2423 row.Reset();
2424 row.SetDeviceName(name);
2425 row.SetErrorCodeId(3);
2427 row_list.push_back(row);
2428
2429
2430 row.Reset();
2431 row.SetDeviceName(name);
2432 row.SetErrorCodeId(4);
2434 row_list.push_back(row);
2435
2436
2437 row.Reset();
2438 row.SetDeviceName(name);
2439 row.SetErrorCodeId(5);
2441 row_list.push_back(row);
2442
2443 row.Reset();
2444 row.SetDeviceName(name);
2445 row.SetErrorCodeId(6);
2447 row_list.push_back(row);
2448
2449
2450 row.Reset();
2451 row.SetDeviceName(name);
2452 row.SetErrorCodeId(7);
2454 row_list.push_back(row);
2455 return;
2456
2457}
2458#endif
Helper functions and utilities for ROOT histogram management.
QwHistogramHelper gQwHists
Globally defined instance of the QwHistogramHelper class.
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
Physical units and constants for Qweak analysis.
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)
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
static EDecodeMode fDecodeMode
Int_t ProcessEvBuffer_oldmock(UInt_t *buffer, UInt_t num_words_left, UInt_t index=0)
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
static constexpr Int_t kOldMockWordsPerChannel
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
static Int_t GetWordsPerChannel()
static Int_t GetDefaultBlocksPerEvent()
static void SetDecodeMode(UInt_t input)
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
static constexpr Int_t kOldMockDefaultBlocks
Double_t fBlockM2[kMaxBlock]
Second moment of the sub-block.
Bool_t ApplySingleEventCuts() override
void MultiplyBy(const VQwHardwareChannel *valueptr) override
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.
static constexpr Int_t kNewReshuffledDefaultBlocks
Double_t fBlockError[kMaxBlock]
Uncertainty on the sub-block.
Int_t GetRawBlockValue(size_t blocknum) const
QwMollerADC_Channel & operator-=(const QwMollerADC_Channel &value)
static Int_t GetModuleHeaderWords()
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)
static constexpr Int_t kMaxBlock
void DivideBy(const VQwHardwareChannel *valueptr) override
Int_t fBlock_min[kMaxBlock+1]
Int_t fNumEvtsWithEventCutsRejected
Counts the Event cut rejected events.
void SetEventData(Double_t *block, UInt_t sequencenumber=0)
Int_t fBlock_max[kMaxBlock+1]
void Scale(Double_t Offset) override
Long64_t fSoftwareBlockSum_raw
Sum of the data in the four sub-blocks raw.
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
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 constexpr Int_t kNewReshuffledChannelsPerModule
Long64_t fHardwareBlockSum_raw
Module-based sum of the four sub-blocks as read from the module.
static constexpr Int_t kOldMockChannelsPerModule
static Int_t GetBufferOffset(Int_t moduleindex, Int_t channelindex)
Long64_t fBlock_raw[kMaxBlock]
Array of the sub-block data as read from the module.
Double_t GetHardwareSumRMS() const
Int_t fErrorCount_SameHW
check to see ADC returning same HW value
void FillHistograms() override
Fill the histograms for this data element.
Int_t GetRawHardwareSum() const
static Bool_t fDecodeModeHasBeenSet
static const Int_t kModuleHeaderWords
Int_t ApplyHWChecks() override
Int_t fErrorCount_Sequence
sequence number check
static void PrintErrorCounterTail()
void ConstructHistograms(TDirectory *folder, TString &prefix) override
Construct the histograms for this data element.
UInt_t fPreviousSequenceNumber
Previous event sequence number for this channel.
Double_t GetValueWidth() const
Double_t GetBlockRMS(Int_t i) const
void IncrementErrorCounters() override
Double_t fHardwareBlockSumError
Uncertainty on the hardware sum.
UInt_t fBlockSample[kMaxBlock+1]
Double_t GetBlockValue(size_t blocknum) const
Int_t ProcessEvBuffer_newreshuffled(UInt_t *buffer, UInt_t num_words_left, UInt_t index=0)
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
Long64_t fBlockSumSq_raw[kMaxBlock+1]
void AccumulateRunningSum(const QwMollerADC_Channel &value, Int_t count=0, Int_t ErrorMask=0xFFFFFFF)
const QwMollerADC_Channel operator+(const QwMollerADC_Channel &value) const
Double_t fBlockRMS[kMaxBlock+1]
static const Bool_t bDEBUG
debugging display purposes
Double_t GetHardwareSumWidth() const
Double_t GetAverageVolts() const
static constexpr Int_t kNewReshuffledWordsPerChannel
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)
static Int_t GetChannelsPerModule()
Double_t GetHardwareSumError() const
void ConstructBranch(TTree *tree, TString &prefix) override
Double_t fBlock[kMaxBlock]
Array of the sub-block data.
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