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