JAPAn
Just Another Parity Analyzer
Loading...
Searching...
No Matches
QwQPD.cc
Go to the documentation of this file.
1/**
2 * \file QwQPD.cc
3 * \brief Quadrant photodiode (QPD) implementation
4 *
5 * Provides four photodiode channels; calculates X/Y from the standard QPD
6 * formula and an effective charge. Supports calibration, single-event cuts,
7 * hardware checks, burp detection, and all standard BPM operations.
8 */
9
10#include "QwQPD.h"
11
12// System headers
13#include <stdexcept>
14
15// ROOT headers for RNTuple support
16#ifdef HAS_RNTUPLE_SUPPORT
17#include <ROOT/RNTupleModel.hxx>
18#include <ROOT/RNTupleWriter.hxx>
19#endif // HAS_RNTUPLE_SUPPORT
20
21// Qweak headers
22#ifdef __USE_DATABASE__
23#include "QwDBInterface.h"
24#endif // __USE_DATABASE__
25
26/* Position calibration factor, transform ADC counts in mm*/
27const TString QwQPD::subelement[4]={"BR","TR","BL","TL"};
28
29
30/** Initialize QPD with 4 photodiode raw channels and derived position/charge. */
31void QwQPD::InitializeChannel(TString name)
32{
33 Short_t i=0;
34 Bool_t localdebug = kFALSE;
35
37
38 fEffectiveCharge.InitializeChannel(name+"WS","derived");
39
40 for(i=0;i<4;i++) {
41 fPhotodiode[i].InitializeChannel(name+subelement[i],"raw");
42
43 if(localdebug)
44 std::cout<<" photodiode ["<<i<<"]="<<fPhotodiode[i].GetElementName()<<"\n";
45 }
46
47 for(i=kXAxis;i<kNumAxes;i++) {
48 fRelPos[i].InitializeChannel(name+"Rel"+kAxisLabel[i],"derived");
49 fAbsPos[i].InitializeChannel(name+kAxisLabel[i],"derived");
50 }
51
52 bFullSave=kTRUE;
53
54 return;
55}
56
57/** Initialize QPD with subsystem scoping for proper tree/histogram naming. */
58void QwQPD::InitializeChannel(TString subsystem, TString name)
59{
60 Short_t i=0;
61 Bool_t localdebug = kFALSE;
62
64
65 fEffectiveCharge.InitializeChannel(subsystem, "QwQPD", name+"WS","derived");
66
67 for(i=0;i<4;i++) {
68 fPhotodiode[i].InitializeChannel(subsystem, "QwQPD", name+subelement[i],"raw");
69 if(localdebug)
70 std::cout<<" photodiode ["<<i<<"]="<<fPhotodiode[i].GetElementName()<<"\n";
71 }
72 for(i=kXAxis;i<kNumAxes;i++) fRelPos[i].InitializeChannel(subsystem, "QwQPD", name+"Rel"+kAxisLabel[i],"derived");
73 for(i=kXAxis;i<kNumAxes;i++) fAbsPos[i].InitializeChannel(subsystem, "QwQPD", name+kAxisLabel[i],"derived");
74
75 bFullSave=kTRUE;
76
77 return;
78}
79
80/**
81 * Apply QPD-specific calibration factors converting ADC counts to mm.
82 * These come from geometry/calibration files for each axis.
83 */
84void QwQPD::GetCalibrationFactors(Double_t AlphaX, Double_t AlphaY)
85{
86 // Read in the calibration factors from the injector_beamline_geometry.map
87 // for the QPD, AlphaX and AlphaY gives the conversion from adc counts to mm.
88
89 Bool_t ldebug = kFALSE;
90
91 fQwQPDCalibration[0]=1.0/AlphaX;
92 fQwQPDCalibration[1]=1.0/AlphaY;
93
94 if(ldebug){
95 std::cout<<"\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
96 std::cout<<this->GetElementName();
97 std::cout<<"\nfQwQPDCalibration[0] = "<<fQwQPDCalibration[0]<<std::endl;
98 std::cout<<"\nfQwQPDCalibration[1] = "<<fQwQPDCalibration[1]<<std::endl;
99 std::cout<<"AlphaX = "<<fRelativeGains[0]<<std::endl;
100 std::cout<<"AlphaY = "<<fRelativeGains[1]<<std::endl;
101 }
102 return;
103}
104
105/** Clear event data for all photodiodes and derived position/charge channels. */
107{
108 Short_t i=0;
109
110 for(i=0;i<4;i++) fPhotodiode[i].ClearEventData();
111
112 for(i=kXAxis;i<kNumAxes;i++) {
113 fRelPos[i].ClearEventData();
114 fAbsPos[i].ClearEventData();
115 }
116
117 fEffectiveCharge.ClearEventData();
118
119 return;
120}
121
122
123/**
124 * Apply hardware-level checks to all four photodiode channels and
125 * aggregate their status.
126 *
127 * @return true if all photodiodes pass hardware checks.
128 */
130{
131 Bool_t eventokay=kTRUE;
132
133 UInt_t deviceerror=0;
134 for(Short_t i=0;i<4;i++)
135 {
136 deviceerror|= fPhotodiode[i].ApplyHWChecks(); //OR the error code from each wire
137 eventokay &= (deviceerror & 0x0);//AND with 0 since zero means HW is good.
138
139 if (bDEBUG) std::cout<<" Inconsistent within QPD terminals photodiode[ "<<i<<" ] "<<std::endl;
140 if (bDEBUG) std::cout<<" photodiode[ "<<i<<" ] sequence num "<<fPhotodiode[i].GetSequenceNumber()<<" sample size "<<fPhotodiode[i].GetNumberOfSamples()<<std::endl;
141 }
142
143 return eventokay;
144}
145
146/** Increment persistent error counters for all channels. */
148{
149 Short_t i=0;
150 for(i=0;i<4;i++)
152 for(i=kXAxis;i<kNumAxes;i++) {
153 fRelPos[i].IncrementErrorCounters();
154 fAbsPos[i].IncrementErrorCounters();
155 }
156 fEffectiveCharge.IncrementErrorCounters();
157}
158
159/** Print error counter summaries for all channels. */
161{
162 Short_t i=0;
163 for(i=0;i<4;i++)
165 for(i=kXAxis;i<kNumAxes;i++) {
166 fRelPos[i].PrintErrorCounters();
167 fAbsPos[i].PrintErrorCounters();
168 }
169 fEffectiveCharge.PrintErrorCounters();
170}
171
172/** Return OR of event-cut error flags across all photodiodes and derived channels. */
174{
175 Short_t i=0;
176 UInt_t error=0;
177 for(i=0;i<4;i++)
179
180 for(i=kXAxis;i<kNumAxes;i++) {
181 error|=fRelPos[i].GetEventcutErrorFlag();
182 error|=fAbsPos[i].GetEventcutErrorFlag();
183 }
184
185 error|=fEffectiveCharge.GetEventcutErrorFlag();
186 return error;
187}
188
189/**
190 * Update derived channel error flags based on photodiode error codes and
191 * return aggregated event-cut flags.
192 */
194{
195 Short_t i=0;
196 UInt_t error1=0;
197 UInt_t error2=0;
198 for(i=0;i<4;i++){
199 error1|=fPhotodiode[i].GetErrorCode();
200 error2|=fPhotodiode[i].GetEventcutErrorFlag();
201 }
202 for(i=kXAxis;i<kNumAxes;i++) {
203 fRelPos[i].UpdateErrorFlag(error1);
204 fAbsPos[i].UpdateErrorFlag(error1);
205 error2|=fRelPos[i].GetEventcutErrorFlag();
206 error2|=fAbsPos[i].GetEventcutErrorFlag();
207 }
208 fEffectiveCharge.UpdateErrorFlag(error1);
209 error2|=fEffectiveCharge.GetEventcutErrorFlag();
210 return error2;
211}
212
213/**
214 * Apply single-event cuts to photodiodes and derived channels, propagating
215 * error codes to position and charge outputs.
216 *
217 * @return true if all channels pass their cuts.
218 */
220{
221 Bool_t status=kTRUE;
222 Int_t i=0;
223 UInt_t error_code = 0;
224 //Event cuts for four pads
225 for(i=0;i<4;i++){
226 if (fPhotodiode[i].ApplySingleEventCuts()){ //for RelX
227 status&=kTRUE;
228 }
229 else{
230 status&=kFALSE;
231 if (bDEBUG) std::cout<<" single pad "<<fPhotodiode[i].GetElementName()<<" event cut failed ";
232 }
233 //Get the Event cut error flag for the pads
234 error_code|=fPhotodiode[i].GetErrorCode();
235 }
236
237 for(i=0;i<2;i++){
238 fRelPos[i].UpdateErrorFlag(error_code);//To update the rel/abs error code from the channels/wires event cut error codes
239 status &= fRelPos[i].ApplySingleEventCuts();
240
241 fAbsPos[i].UpdateErrorFlag(error_code);//To update the rel/abs error code from the channels/wires event cut error codes
242 status &= fAbsPos[i].ApplySingleEventCuts();
243 }
244 fEffectiveCharge.UpdateErrorFlag(error_code);// To update the eff-charge error code from the channels/wires event cut error codes
245 status &= fEffectiveCharge.ApplySingleEventCuts();
246
247 return status;
248}
249
250/**
251 * Map a human-readable name to the corresponding channel pointer.
252 * Supports: tl/tr/br/bl (photodiodes), relx/rely, absx/x, absy/y,
253 * effectivecharge/charge.
254 *
255 * @throws std::invalid_argument on unrecognized names.
256 */
258{
259 VQwHardwareChannel* tmpptr = NULL;
260 ch_name.ToLower();
261 if (ch_name=="tl"){
262 tmpptr = &fPhotodiode[0];
263 }else if (ch_name=="tr"){
264 tmpptr = &fPhotodiode[1];
265 }else if (ch_name=="br"){
266 tmpptr = &fPhotodiode[2];
267 }else if (ch_name=="bl"){
268 tmpptr = &fPhotodiode[3];
269 }else if (ch_name=="relx"){
270 tmpptr = &fRelPos[0];
271 }else if (ch_name=="rely"){
272 tmpptr = &fRelPos[1];
273 }else if (ch_name=="absx" || ch_name=="x" ){
274 tmpptr = &fAbsPos[0];
275 }else if (ch_name=="absy" || ch_name=="y"){
276 tmpptr = &fAbsPos[1];
277 }else if (ch_name=="effectivecharge" || ch_name=="charge"){
278 tmpptr = &fEffectiveCharge;
279 } else {
280 TString loc="QwQPD::GetSubelementByName for"
281 + this->GetElementName() + " was passed "
282 + ch_name + ", which is an unrecognized subelement name.";
283 throw std::invalid_argument(loc.Data());
284 }
285 return tmpptr;
286}
287
288/*
289void QwQPD::SetSingleEventCuts(TString ch_name, Double_t minX, Double_t maxX)
290{
291
292 if (ch_name=="tl"){
293 QwMessage<<"TL LL " << minX <<" UL " << maxX <<QwLog::endl;
294 fPhotodiode[0].SetSingleEventCuts(minX,maxX);
295
296 }else if (ch_name=="tr"){
297 QwMessage<<"TR LL " << minX <<" UL " << maxX <<QwLog::endl;
298 fPhotodiode[1].SetSingleEventCuts(minX,maxX);
299
300 }else if (ch_name=="br"){
301 QwMessage<<"BR LL " << minX <<" UL " << maxX <<QwLog::endl;
302 fPhotodiode[2].SetSingleEventCuts(minX,maxX);
303
304 }else if (ch_name=="bl"){
305 QwMessage<<"BL LL " << minX <<" UL " << maxX <<QwLog::endl;
306 fPhotodiode[3].SetSingleEventCuts(minX,maxX);
307
308 }else if (ch_name=="relx"){
309 QwMessage<<"RelX LL " << minX <<" UL " << maxX <<QwLog::endl;
310 fRelPos[0].SetSingleEventCuts(minX,maxX);
311
312 }else if (ch_name=="rely"){
313 QwMessage<<"RelY LL " << minX <<" UL " << maxX <<QwLog::endl;
314 fRelPos[1].SetSingleEventCuts(minX,maxX);
315
316 }else if (ch_name=="x" || ch_name=="y" || ch_name=="effectivecharge" ){
317
318 VQwBPM::SetSingleEventCuts(ch_name, minX, maxX);
319 }
320
321}*/
322
323/**
324 * Configure single-event cuts for a specific subelement by name, including
325 * error flags, limits, stability, and burp detection parameters.
326 *
327 * @param ch_name Subelement name (tl,tr,bl,br,relx,rely,absx,absy,effectivecharge)
328 * @param errorflag Error flag mask to set when the cut fails
329 * @param minX Lower limit
330 * @param maxX Upper limit
331 * @param stability Stability cut width
332 * @param burplevel Burp detection threshold
333 */
334void QwQPD::SetSingleEventCuts(TString ch_name, UInt_t errorflag,Double_t minX, Double_t maxX, Double_t stability, Double_t burplevel){
335 errorflag|=kBPMErrorFlag;//update the device flag
336 if (ch_name=="tl"){
337 QwMessage<<"TL LL " << minX <<" UL " << maxX <<QwLog::endl;
338 fPhotodiode[0].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
339
340 }else if (ch_name=="tr"){
341 QwMessage<<"TR LL " << minX <<" UL " << maxX <<QwLog::endl;
342 fPhotodiode[1].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
343
344 }else if (ch_name=="br"){
345 QwMessage<<"BR LL " << minX <<" UL " << maxX <<QwLog::endl;
346 fPhotodiode[2].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
347
348 }else if (ch_name=="bl"){
349 QwMessage<<"BL LL " << minX <<" UL " << maxX <<QwLog::endl;
350 fPhotodiode[3].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
351
352 }else if (ch_name=="relx"){
353 QwMessage<<"RelX LL " << minX <<" UL " << maxX <<QwLog::endl;
354 fRelPos[0].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
355
356 }else if (ch_name=="rely"){
357 QwMessage<<"RelY LL " << minX <<" UL " << maxX <<QwLog::endl;
358 fRelPos[1].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
359
360 }else if (ch_name=="absx"){
361 QwMessage<<"AbsX LL " << minX <<" UL " << maxX <<QwLog::endl;
362 fAbsPos[0].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
363
364 }else if (ch_name=="absy"){
365 QwMessage<<"AbsY LL " << minX <<" UL " << maxX <<QwLog::endl;
366 fAbsPos[1].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
367
368 }else if (ch_name=="effectivecharge"){
369 QwMessage<<"EffectveQ LL " << minX <<" UL " << maxX <<QwLog::endl;
370 fEffectiveCharge.SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
371
372 }
373
374}
375
376/**
377 * Polymorphic burp check against a reference QPD, delegating to all
378 * photodiodes, position, and charge channels.
379 *
380 * @return true if any subchannel reports a burp failure.
381 * @throws std::invalid_argument if ev_error is not a QwQPD.
382 */
384 Short_t i=0;
385 Bool_t burpstatus = kFALSE;
386 try {
387 if(typeid(*ev_error)==typeid(*this)) {
388 //std::cout<<" Here in QwQPD::CheckForBurpFail \n";
389 if (this->GetElementName()!="") {
390 const QwQPD* value_qpd = dynamic_cast<const QwQPD* >(ev_error);
391 for(i=0;i<4;i++){
392 burpstatus |= fPhotodiode[i].CheckForBurpFail(&(value_qpd->fPhotodiode[i]));
393 }
394 for(i=kXAxis;i<kNumAxes;i++) {
395 burpstatus |= fRelPos[i].CheckForBurpFail(&(value_qpd->fRelPos[i]));
396 burpstatus |= fAbsPos[i].CheckForBurpFail(&(value_qpd->fAbsPos[i]));
397 }
398 burpstatus |= fEffectiveCharge.CheckForBurpFail(&(value_qpd->fEffectiveCharge));
399 }
400 } else {
401 TString loc="Standard exception from QwQPD::CheckForBurpFail :"+
402 ev_error->GetElementName()+" "+this->GetElementName()+" are not of the "
403 +"same type";
404 throw std::invalid_argument(loc.Data());
405 }
406 } catch (std::exception& e) {
407 std::cerr<< e.what()<<std::endl;
408 }
409 return burpstatus;
410};
411
412/**
413 * Copy error flags from a reference QPD to this instance.
414 *
415 * @throws std::invalid_argument if ev_error is not a QwQPD.
416 */
417void QwQPD::UpdateErrorFlag(const VQwBPM *ev_error){
418 Short_t i=0;
419 try {
420 if(typeid(*ev_error)==typeid(*this)) {
421 // std::cout<<" Here in QwQPD::UpdateErrorFlag \n";
422 if (this->GetElementName()!="") {
423 const QwQPD* value_bpm = dynamic_cast<const QwQPD* >(ev_error);
424 for(i=0;i<4;i++){
425 fPhotodiode[i].UpdateErrorFlag(value_bpm->fPhotodiode[i]);
426 }
427 for(i=kXAxis;i<kNumAxes;i++) {
428 fRelPos[i].UpdateErrorFlag(value_bpm->fRelPos[i]);
429 fAbsPos[i].UpdateErrorFlag(value_bpm->fAbsPos[i]);
430 }
431 fEffectiveCharge.UpdateErrorFlag(value_bpm->fEffectiveCharge);
432 }
433 } else {
434 TString loc="Standard exception from QwQPD::UpdateErrorFlag :"+
435 ev_error->GetElementName()+" "+this->GetElementName()+" are not of the "
436 +"same type";
437 throw std::invalid_argument(loc.Data());
438 }
439 } catch (std::exception& e) {
440 std::cerr<< e.what()<<std::endl;
441 }
442
443};
444
445
446
447/**
448 * Process the current event: apply HW checks, sum photodiodes for effective
449 * charge, and calculate X/Y positions using the standard QPD formula:
450 * X = ((TL-TR) + (BL-BR)) / (TL+TR+BL+BR)
451 * Y = ((TL-BL) + (TR-BR)) / (TL+TR+BL+BR)
452 */
454{
455 Bool_t localdebug = kFALSE;
456 static QwVQWK_Channel numer[2];
457 static QwVQWK_Channel tmp("tmp");
458 static QwVQWK_Channel tmp1("tmp1");
459 static QwVQWK_Channel tmp2("tmp2");
460
461 numer[0].InitializeChannel("Xnumerator","raw");
462 numer[1].InitializeChannel("Ynumerator","raw");
463
464 Short_t i = 0;
465
467 /* Frst apply HW checks and update HW error flags.
468 Calling this routine here and not in ApplySingleEventCuts
469 makes a difference for a QPDs because they are derived devices.
470 */
471
472 fEffectiveCharge.ClearEventData();
473
474 for(i=0;i<4;i++){
475 fPhotodiode[i].ProcessEvent();
477 }
478
479 if (localdebug) fEffectiveCharge.PrintInfo();
480
481
482 /** The positions X and Y from a QPD are calculated using following equations,
483
484 TL --------- TR
485 | 4 | 2 |
486 ---------
487 BL | 3 | 1 | BR
488 ---------
489
490
491 (4-2) + (3-1) (4-3) + (2-1)
492 X = ------------ Y = -------------
493 1+2+3+4 1+2+3+4
494 **/
495
496 if(localdebug){
497 std::cout<<"#############################\n";
498 std::cout<<" QPD name = "<<fElementName<<std::endl;
499 std::cout<<" event number = "<<fPhotodiode[0].GetSequenceNumber()<<"\n";
500 std::cout<<" hw BR ="<<fPhotodiode[0].GetValue()<<"\n";
501 std::cout<<" hw TR ="<<fPhotodiode[1].GetValue()<<"\n";
502 std::cout<<" hw BL ="<<fPhotodiode[2].GetValue()<<"\n";
503 std::cout<<" hw TL ="<<fPhotodiode[3].GetValue()<<"\n\n";
504 }
505
506 // X numerator
507 tmp1.ClearEventData();
508 tmp1.Difference(fPhotodiode[3],fPhotodiode[1]); // 4-2
509 tmp2.ClearEventData();
510 tmp2.Difference(fPhotodiode[2],fPhotodiode[0]); // 3-1
511 tmp.ClearEventData();
512 numer[0].Sum(tmp1,tmp2);
513
514 // Y numerator
515 tmp1.ClearEventData();
516 tmp1.Difference(fPhotodiode[3],fPhotodiode[2]); // 4-3
517 tmp2.ClearEventData();
518 tmp2.Difference(fPhotodiode[1],fPhotodiode[0]); // 2-1
519 tmp.ClearEventData();
520 numer[1].Sum(tmp1,tmp2);
521
522 for(i=kXAxis;i<kNumAxes;i++){
523 tmp.ClearEventData();
524 tmp.Sum(fPhotodiode[0],fPhotodiode[1]);
525 tmp1.ClearEventData();
526 tmp1.Sum(fPhotodiode[2],fPhotodiode[3]);
527 fEffectiveCharge.Sum(tmp,tmp1);
528
529 // X/Y reading in ADC counts
530 fRelPos[i].Ratio(numer[i],fEffectiveCharge);
531
532 // X/Y reading in mm.
533 fAbsPos[i]=fRelPos[i];
534 fAbsPos[i].Scale(fQwQPDCalibration[i]);
535
536 if(localdebug){
537 std::cout<<" hw numerator= "<<numer[i].GetValue()<<" ";
538 std::cout<<" hw denominator (== Effective_Charge)= "<<fEffectiveCharge.GetValue()<<"\n";
539 std::cout<<" hw clibration factors= "<<fQwQPDCalibration[i]<<"\n";
540 std::cout<<" hw fRelPos["<<kAxisLabel[i]<<"]="<<fRelPos[i].GetValue()<<"\n \n";
541 std::cout<<" hw fAbsPos["<<kAxisLabel[i]<<"]="<<fAbsPos[i].GetValue()<<"\n \n";
542 }
543 }
544
545 return;
546}
547
548
549/**
550 * Route raw buffer data to the specified photodiode channel.
551 *
552 * @param buffer Raw event buffer
553 * @param word_position_in_buffer Position in buffer to read from
554 * @param index Target photodiode index (0-3)
555 * @return Original word_position_in_buffer
556 */
557Int_t QwQPD::ProcessEvBuffer(UInt_t* buffer, UInt_t word_position_in_buffer,UInt_t index)
558{
559 if(index<4)
560 {
561 fPhotodiode[index].ProcessEvBuffer(buffer,word_position_in_buffer);
562 }
563 else
564 {
565 std::cerr <<
566 "QwQPD::ProcessEvBuffer(): attempt to fill in raw date for a wire that doesn't exist \n";
567 }
568 return word_position_in_buffer;
569}
570
571
572TString QwQPD::GetSubElementName(Int_t subindex)
573{
574 TString thisname;
575 if(subindex<4&&subindex>-1)
576 thisname=fPhotodiode[subindex].GetElementName();
577 else
578 std::cerr<<"QwQPD::GetSubElementName for "<<
579 GetElementName()<<" this subindex doesn't exists \n";
580
581 return thisname;
582}
583
584UInt_t QwQPD::GetSubElementIndex(TString subname)
585{
586 subname.ToUpper();
587 UInt_t localindex=kInvalidSubelementIndex;
588 for(Short_t i=0;i<4;i++) if(subname==subelement[i])localindex=i;
589
590 if(localindex>3)
591 std::cerr << "QwQPD::GetSubElementIndex is unable to associate the string -"
592 <<subname<<"- to any index"<<std::endl;
593
594 return localindex;
595}
596
598{
599 *(dynamic_cast<QwQPD*>(this)) = *(dynamic_cast<const QwQPD*>(&value));
600 return *this;
601}
602
604{
605 if (GetElementName()!=""){
606 Short_t i = 0;
608 for(i=0;i<4;i++) this->fPhotodiode[i]=value.fPhotodiode[i];
609 for(i=kXAxis;i<kNumAxes;i++){
610 this->fRelPos[i]=value.fRelPos[i];
611 this->fAbsPos[i]=value.fAbsPos[i];
612 }
613 }
614 return *this;
615}
616
618{
619 *(dynamic_cast<QwQPD*>(this)) += *(dynamic_cast<const QwQPD*>(&value));
620 return *this;
621}
622
624{
625 if (GetElementName()!=""){
626 Short_t i = 0;
628 for(i=0;i<4;i++) this->fPhotodiode[i]+=value.fPhotodiode[i];
629
630 for(i=kXAxis;i<kNumAxes;i++){
631 this->fRelPos[i]+=value.fRelPos[i];
632 this->fAbsPos[i]+=value.fAbsPos[i];
633 }
634 }
635 return *this;
636}
637
639{
640 *(dynamic_cast<QwQPD*>(this)) -= *(dynamic_cast<const QwQPD*>(&value));
641 return *this;
642}
643
645{
646 if (GetElementName()!=""){
647 Short_t i = 0;
649 for(i=0;i<4;i++) this->fPhotodiode[i]-=value.fPhotodiode[i];
650
651 for(i=kXAxis;i<kNumAxes;i++){
652 this->fRelPos[i]-=value.fRelPos[i];
653 this->fAbsPos[i]-=value.fAbsPos[i];
654 }
655 }
656 return *this;
657}
658
659
660void QwQPD::Ratio(QwQPD &numer, QwQPD &denom)
661{
662 // this function is called when forming asymmetries. In this case what we actually want for the
663 // QPD is the difference only not the asymmetries
664
665 *this=numer;
666 this->fEffectiveCharge.Ratio(numer.fEffectiveCharge,denom.fEffectiveCharge);
667 return;
668}
669
670
671
672void QwQPD::Scale(Double_t factor)
673{
674 Short_t i = 0;
675
676 for(i=0;i<4;i++) fPhotodiode[i].Scale(factor);
677 for(i=kXAxis;i<kNumAxes;i++){
678 fRelPos[i].Scale(factor);
679 fAbsPos[i].Scale(factor);
680 }
681 fEffectiveCharge.Scale(factor);
682 return;
683}
684
686{
687 Short_t i = 0;
688 for(i=0;i<4;i++) fPhotodiode[i].CalculateRunningAverage();
689 for (i = 0; i < 2; i++){
690 fRelPos[i].CalculateRunningAverage();
691 fAbsPos[i].CalculateRunningAverage();
692 }
693 fEffectiveCharge.CalculateRunningAverage();
694 return;
695}
696
697void QwQPD::AccumulateRunningSum(const VQwBPM& value, Int_t count, Int_t ErrorMask)
698{
699 AccumulateRunningSum(*dynamic_cast<const QwQPD* >(&value), count, ErrorMask);
700}
701
702void QwQPD::AccumulateRunningSum(const QwQPD& value, Int_t count, Int_t ErrorMask)
703{
704 Short_t i = 0;
705 for(i=0;i<4;i++) fPhotodiode[i].AccumulateRunningSum(value.fPhotodiode[i], count, ErrorMask);
706 for (i = 0; i < 2; i++){
707 fRelPos[i].AccumulateRunningSum(value.fRelPos[i], count, ErrorMask);
708 fAbsPos[i].AccumulateRunningSum(value.fAbsPos[i], count, ErrorMask);
709 }
710 fEffectiveCharge.AccumulateRunningSum(value.fEffectiveCharge, count, ErrorMask);
711 return;
712
713
714}
715
716void QwQPD::DeaccumulateRunningSum(VQwBPM& value, Int_t ErrorMask)
717{
718 DeaccumulateRunningSum(*dynamic_cast<QwQPD* >(&value), ErrorMask);
719}
720
721void QwQPD::DeaccumulateRunningSum(QwQPD& value, Int_t ErrorMask)
722{
723
724 Short_t i = 0;
725 for(i=0;i<4;i++) fPhotodiode[i].DeaccumulateRunningSum(value.fPhotodiode[i]);
726 for (i = 0; i < 2; i++){
727 fRelPos[i].DeaccumulateRunningSum(value.fRelPos[i], ErrorMask);
728 fAbsPos[i].DeaccumulateRunningSum(value.fAbsPos[i], ErrorMask);
729 }
730 fEffectiveCharge.DeaccumulateRunningSum(value.fEffectiveCharge, ErrorMask);
731 return;
732
733
734}
735
736
737
738void QwQPD::ConstructHistograms(TDirectory *folder, TString &prefix)
739{
740
741 if (GetElementName()=="") {
742 // This channel is not used, so skip filling the histograms.
743 } else {
744 fEffectiveCharge.ConstructHistograms(folder, prefix);
745 TString thisprefix=prefix;
746
747 if(prefix.Contains("asym_"))
748 thisprefix.ReplaceAll("asym_","diff_");
749 SetRootSaveStatus(prefix);
750 Short_t i = 0;
751 if(bFullSave) {
752 for(i=0;i<4;i++) fPhotodiode[i].ConstructHistograms(folder, thisprefix);
753 }
754 for(i=kXAxis;i<kNumAxes;i++) {
755 fAbsPos[i].ConstructHistograms(folder, thisprefix);
756 fRelPos[i].ConstructHistograms(folder, thisprefix);
757 }
758 }
759 return;
760}
761
763{
764 if (GetElementName()=="") {
765 // This channel is not used, so skip filling the histograms.
766 }
767 else {
768 fEffectiveCharge.FillHistograms();
769 Short_t i = 0;
770 if(bFullSave) {
771 for(i=0;i<4;i++) fPhotodiode[i].FillHistograms();
772 }
773 for(i=kXAxis;i<kNumAxes;i++){
774 fAbsPos[i].FillHistograms();
775 fRelPos[i].FillHistograms();
776 }
777 }
778 return;
779}
780
781void QwQPD::ConstructBranchAndVector(TTree *tree, TString &prefix, QwRootTreeBranchVector &values)
782{
783 if (GetElementName()==""){
784 // This channel is not used, so skip constructing trees.
785 }
786 else {
787 TString thisprefix=prefix;
788 if(prefix.Contains("asym_"))
789 thisprefix.ReplaceAll("asym_","diff_");
790
791 SetRootSaveStatus(prefix);
792
793 fEffectiveCharge.ConstructBranchAndVector(tree,prefix,values);
794 Short_t i = 0;
795 if(bFullSave) {
796 for(i=0;i<4;i++) fPhotodiode[i].ConstructBranchAndVector(tree,thisprefix,values);
797 }
798 for(i=kXAxis;i<kNumAxes;i++) {
799 fAbsPos[i].ConstructBranchAndVector(tree,thisprefix,values);
800 fRelPos[i].ConstructBranchAndVector(tree,thisprefix,values);
801 }
802
803 }
804 return;
805}
806
807void QwQPD::ConstructBranch(TTree *tree, TString &prefix)
808{
809 if (GetElementName()==""){
810 // This channel is not used, so skip constructing trees.
811 }
812 else {
813 TString thisprefix=prefix;
814 if(prefix.Contains("asym_"))
815 thisprefix.ReplaceAll("asym_","diff_");
816
817 SetRootSaveStatus(prefix);
818
819 fEffectiveCharge.ConstructBranch(tree,prefix);
820 Short_t i = 0;
821 if(bFullSave) {
822 for(i=0;i<4;i++) fPhotodiode[i].ConstructBranch(tree,thisprefix);
823 }
824 for(i=kXAxis;i<kNumAxes;i++) {
825 fAbsPos[i].ConstructBranch(tree,thisprefix);
826 fRelPos[i].ConstructBranch(tree,thisprefix);
827 }
828
829 }
830 return;
831}
832
833void QwQPD::ConstructBranch(TTree *tree, TString &prefix, QwParameterFile& modulelist)
834{
835 TString devicename;
836
837 devicename=GetElementName();
838 devicename.ToLower();
839 if (GetElementName()==""){
840 // This channel is not used, so skip filling the histograms.
841 } else
842 {
843 if (modulelist.HasValue(devicename)){
844 TString thisprefix=prefix;
845 if(prefix.Contains("asym_"))
846 thisprefix.ReplaceAll("asym_","diff_");
847
848 SetRootSaveStatus(prefix);
849
850 fEffectiveCharge.ConstructBranch(tree,prefix);
851 Short_t i = 0;
852 if(bFullSave) {
853 for(i=0;i<4;i++) fPhotodiode[i].ConstructBranch(tree,thisprefix);
854 }
855 for(i=kXAxis;i<kNumAxes;i++) {
856 fAbsPos[i].ConstructBranch(tree,thisprefix);
857 fRelPos[i].ConstructBranch(tree,thisprefix);
858 }
859
860 QwMessage <<" Tree leaves added to "<<devicename<<" Corresponding channels"<<QwLog::endl;
861 }
862 // this functions doesn't do anything yet
863 }
864
865
866
867
868
869 return;
870}
871
873{
874 if (GetElementName()=="") {
875 // This channel is not used, so skip filling the tree.
876 }
877 else {
878 fEffectiveCharge.FillTreeVector(values);
879 Short_t i = 0;
880 if(bFullSave) {
881 for(i=0;i<4;i++) fPhotodiode[i].FillTreeVector(values);
882 }
883
884 for(i=kXAxis;i<kNumAxes;i++){
885 fAbsPos[i].FillTreeVector(values);
886 fRelPos[i].FillTreeVector(values);
887 }
888 }
889 return;
890}
891
892#ifdef HAS_RNTUPLE_SUPPORT
893void QwQPD::ConstructNTupleAndVector(std::unique_ptr<ROOT::RNTupleModel>& model, TString& prefix, std::vector<Double_t>& values, std::vector<std::shared_ptr<Double_t>>& fieldPtrs)
894{
895 if (GetElementName()==""){
896 // This channel is not used, so skip constructing.
897 }
898 else {
899 TString thisprefix=prefix;
900 if(prefix.Contains("asym_"))
901 thisprefix.ReplaceAll("asym_","diff_");
902
903 SetRootSaveStatus(prefix);
904
905 fEffectiveCharge.ConstructNTupleAndVector(model,prefix,values,fieldPtrs);
906 Short_t i = 0;
907 if(bFullSave) {
908 for(i=0;i<4;i++) fPhotodiode[i].ConstructNTupleAndVector(model,thisprefix,values,fieldPtrs);
909 }
910 for(i=kXAxis;i<kNumAxes;i++) {
911 fAbsPos[i].ConstructNTupleAndVector(model,thisprefix,values,fieldPtrs);
912 fRelPos[i].ConstructNTupleAndVector(model,thisprefix,values,fieldPtrs);
913 }
914
915 }
916 return;
917}
918
919void QwQPD::FillNTupleVector(std::vector<Double_t>& values) const
920{
921 if (GetElementName()=="") {
922 // This channel is not used, so skip filling.
923 }
924 else {
925 fEffectiveCharge.FillNTupleVector(values);
926 Short_t i = 0;
927 if(bFullSave) {
928 for(i=0;i<4;i++) fPhotodiode[i].FillNTupleVector(values);
929 }
930
931 for(i=kXAxis;i<kNumAxes;i++){
932 fAbsPos[i].FillNTupleVector(values);
933 fRelPos[i].FillNTupleVector(values);
934 }
935 }
936 return;
937}
938#endif
939
940
941
942void QwQPD::SetEventCutMode(Int_t bcuts)
943{
944 Short_t i = 0;
945 // bEVENTCUTMODE=bcuts;
946 for (i=0;i<4;i++) fPhotodiode[i].SetEventCutMode(bcuts);
947 for (i=kXAxis;i<kNumAxes;i++) {
948 fAbsPos[i].SetEventCutMode(bcuts);
949 fRelPos[i].SetEventCutMode(bcuts);
950 }
951 fEffectiveCharge.SetEventCutMode(bcuts);
952}
953
954
956{
957 for (size_t i = kXAxis; i < kNumAxes; i++) {
958 QwVQWK_Channel abspos(fAbsPos[i]);
959 abspos = fAbsPos[i];
960 fQPDElementList.push_back(abspos);
961 }
962 QwVQWK_Channel effectivecharge(fEffectiveCharge);
963 effectivecharge = fEffectiveCharge;
964 fQPDElementList.push_back(effectivecharge);
965}
966
967#ifdef __USE_DATABASE__
968std::vector<QwDBInterface> QwQPD::GetDBEntry()
969{
970 std::vector <QwDBInterface> row_list;
971 row_list.clear();
972 for(size_t i=kXAxis;i<kNumAxes;i++) {
973 fAbsPos[i].AddEntriesToList(row_list);
974 }
975 fEffectiveCharge.AddEntriesToList(row_list);
976 return row_list;
977}
978
979std::vector<QwErrDBInterface> QwQPD::GetErrDBEntry()
980{
981 std::vector <QwErrDBInterface> row_list;
982 row_list.clear();
983 for(size_t i=kXAxis;i<kNumAxes;i++) {
984 fAbsPos[i].AddErrEntriesToList(row_list);
985 }
986 fEffectiveCharge.AddErrEntriesToList(row_list);
987 return row_list;
988}
989#endif // __USE_DATABASE__
990
991
992/**********************************
993 * Mock data generation routines
994 **********************************/
995
996void QwQPD::SetRandomEventParameters(Double_t meanX, Double_t sigmaX, Double_t meanY, Double_t sigmaY)
997{
998 // Average values of the signals in the stripline ADCs
999 Double_t sumX = 1.1e8; // These are just guesses, but I made X and Y different
1000 Double_t sumY = 0.9e8; // to make it more interesting for the analyzer...
1001
1002
1003 // Determine the asymmetry from the position
1004 Double_t meanXP = (1.0 + meanX / fQwQPDCalibration[0]) * sumX / 2.0;
1005 Double_t meanXM = (1.0 - meanX / fQwQPDCalibration[0]) * sumX / 2.0; // = sumX - meanXP;
1006 Double_t meanYP = (1.0 + meanY / fQwQPDCalibration[1]) * sumY / 2.0;
1007 Double_t meanYM = (1.0 - meanY / fQwQPDCalibration[1]) * sumY / 2.0; // = sumY - meanYP;
1008
1009 // Determine the spread of the asymmetry (this is not tested yet)
1010 // (negative sigma should work in the QwVQWK_Channel, but still using fabs)
1011 Double_t sigmaXP = fabs(sumX * sigmaX / meanX);
1012 Double_t sigmaXM = sigmaXP;
1013 Double_t sigmaYP = fabs(sumY * sigmaY / meanY);
1014 Double_t sigmaYM = sigmaYP;
1015
1016 // Propagate these parameters to the ADCs
1017 fPhotodiode[0].SetRandomEventParameters(meanXP, sigmaXP);
1018 fPhotodiode[1].SetRandomEventParameters(meanXM, sigmaXM);
1019 fPhotodiode[2].SetRandomEventParameters(meanYP, sigmaYP);
1020 fPhotodiode[3].SetRandomEventParameters(meanYM, sigmaYM);
1021}
1022
1023
1024void QwQPD::RandomizeEventData(int helicity, double time)
1025{
1026 for (Short_t i=0; i<4; i++) fPhotodiode[i].RandomizeEventData(helicity, time);
1027
1028 return;
1029}
1030
1031
1032void QwQPD::SetEventData(Double_t* relpos, UInt_t sequencenumber)
1033{
1034 for (Short_t i=0; i<2; i++)
1035 {
1036 fAbsPos[i].SetHardwareSum(relpos[i], sequencenumber);
1037 }
1038
1039 return;
1040}
1041
1042
1043void QwQPD::EncodeEventData(std::vector<UInt_t> &buffer)
1044{
1045 for (Short_t i=0; i<4; i++) fPhotodiode[i].EncodeEventData(buffer);
1046}
1047
1048
1049void QwQPD::SetDefaultSampleSize(Int_t sample_size)
1050{
1051 for(Short_t i=0;i<4;i++) fPhotodiode[i].SetDefaultSampleSize((size_t)sample_size);
1052 return;
1053}
1054
1055
1056void QwQPD::SetSubElementPedestal(Int_t j, Double_t value)
1057{
1058 fPhotodiode[j].SetPedestal(value);
1059 return;
1060}
1061
1062void QwQPD::SetSubElementCalibrationFactor(Int_t j, Double_t value)
1063{
1064 fPhotodiode[j].SetCalibrationFactor(value);
1065 return;
1066}
1067
#define QwMessage
Predefined log drain for regular messages.
Definition QwLog.h:49
static const UInt_t kBPMErrorFlag
Definition QwTypes.h:170
static const UInt_t kInvalidSubelementIndex
Definition QwTypes.h:198
Database interface for QwIntegrationPMT and subsystems.
Quadrant photodiode beam position monitor implementation.
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 HasValue(TString &vname)
A helper class to manage a vector of branch entries for ROOT trees.
Definition QwRootFile.h:53
Concrete hardware channel for VQWK ADC modules (6x32-bit words)
void InitializeChannel(TString name, TString datatosave) override
Initialize the fields in this object.
void Sum(const QwVQWK_Channel &value1, const QwVQWK_Channel &value2)
void ClearEventData() override
Clear the event data in this element.
Double_t GetValue(size_t element) const override
void Difference(const QwVQWK_Channel &value1, const QwVQWK_Channel &value2)
VQwDataElement()
Default constructor.
TString fElementName
Name of this data element.
virtual const TString & GetElementName() const
Get the name of this element.
Abstract base for concrete hardware channels implementing dual-operator pattern.
static UInt_t GetSubElementIndex(TString subname)
Definition QwQPD.cc:584
Bool_t ApplyHWChecks()
Definition QwQPD.cc:129
static const TString subelement[4]
Definition QwQPD.h:27
void ClearEventData() override
Definition QwQPD.cc:106
void AccumulateRunningSum(const QwQPD &value, Int_t count=0, Int_t ErrorMask=0xFFFFFFF)
Definition QwQPD.cc:702
void GetCalibrationFactors(Double_t AlphaX, Double_t AlphaY)
Definition QwQPD.cc:84
Bool_t CheckForBurpFail(const VQwDataElement *ev_error) override
Definition QwQPD.cc:383
void ConstructBranch(TTree *tree, TString &prefix) override
Definition QwQPD.cc:807
void SetEventCutMode(Int_t bcuts) override
Definition QwQPD.cc:942
TString GetSubElementName(Int_t subindex) override
Definition QwQPD.cc:572
void ConstructHistograms(TDirectory *folder, TString &prefix) override
Construct the histograms for this data element.
Definition QwQPD.cc:738
void ConstructBranchAndVector(TTree *tree, TString &prefix, QwRootTreeBranchVector &values) override
Definition QwQPD.cc:781
std::array< QwVQWK_Channel, 4 > fPhotodiode
Definition QwQPD.h:167
void Scale(Double_t factor) override
Definition QwQPD.cc:672
std::array< QwVQWK_Channel, 2 > fAbsPos
Definition QwQPD.h:172
void ProcessEvent() override
Definition QwQPD.cc:453
UInt_t GetEventcutErrorFlag() override
Definition QwQPD.cc:173
VQwHardwareChannel * GetSubelementByName(TString ch_name) override
Definition QwQPD.cc:257
QwQPD()
Definition QwQPD.h:43
void SetDefaultSampleSize(Int_t sample_size) override
Definition QwQPD.cc:1049
VQwBPM & operator-=(const VQwBPM &value) override
Definition QwQPD.cc:638
Int_t ProcessEvBuffer(UInt_t *buffer, UInt_t word_position_in_buffer, UInt_t indexnumber) override
Definition QwQPD.cc:557
QwVQWK_Channel fEffectiveCharge
Definition QwQPD.h:173
VQwBPM & operator+=(const VQwBPM &value) override
Definition QwQPD.cc:617
void SetSubElementPedestal(Int_t j, Double_t value) override
Definition QwQPD.cc:1056
std::vector< QwVQWK_Channel > fQPDElementList
Definition QwQPD.h:175
UInt_t UpdateErrorFlag() override
Definition QwQPD.cc:193
Bool_t ApplySingleEventCuts() override
Definition QwQPD.cc:219
void CalculateRunningAverage() override
Definition QwQPD.cc:685
void Ratio(QwQPD &numer, QwQPD &denom)
Definition QwQPD.cc:660
void SetRandomEventParameters(Double_t meanX, Double_t sigmaX, Double_t meanY, Double_t sigmaY) override
Definition QwQPD.cc:996
void PrintErrorCounters() const override
Definition QwQPD.cc:160
void SetSubElementCalibrationFactor(Int_t j, Double_t value) override
Definition QwQPD.cc:1062
void InitializeChannel(TString name)
Definition QwQPD.cc:31
Double_t fQwQPDCalibration[2]
Definition QwQPD.h:163
void EncodeEventData(std::vector< UInt_t > &buffer) override
Definition QwQPD.cc:1043
void DeaccumulateRunningSum(VQwBPM &value, Int_t ErrorMask=0xFFFFFFF) override
Definition QwQPD.cc:716
void FillHistograms() override
Fill the histograms for this data element.
Definition QwQPD.cc:762
void MakeQPDList()
Definition QwQPD.cc:955
VQwBPM & operator=(const VQwBPM &value) override
Definition QwQPD.cc:597
std::array< QwVQWK_Channel, 2 > fRelPos
Definition QwQPD.h:168
void IncrementErrorCounters() override
Definition QwQPD.cc:147
void FillTreeVector(QwRootTreeBranchVector &values) const override
Definition QwQPD.cc:872
void SetSingleEventCuts(TString ch_name, UInt_t errorflag, Double_t minX, Double_t maxX, Double_t stability, Double_t burplevel)
Inherited from VQwDataElement to set the upper and lower limits (fULimit and fLLimit),...
Definition QwQPD.cc:334
void RandomizeEventData(int helicity=0, double time=0.0) override
Definition QwQPD.cc:1024
void SetEventData(Double_t *block, UInt_t sequencenumber)
Definition QwQPD.cc:1032
@ kXAxis
Definition VQwBPM.h:72
@ kNumAxes
Definition VQwBPM.h:72
void SetRootSaveStatus(TString &prefix)
Definition VQwBPM.cc:220
static const TString kAxisLabel[2]
Definition VQwBPM.h:25
Double_t fRelativeGains[2]
Definition VQwBPM.h:331
void InitializeChannel(TString name)
Initialize common BPM state and set the element name.
Definition VQwBPM.cc:35
static const Bool_t bDEBUG
Definition VQwBPM.h:350
Bool_t bFullSave
Definition VQwBPM.h:348
VQwBPM()
Definition VQwBPM.h:76