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