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