JAPAn
Just Another Parity Analyzer
Loading...
Searching...
No Matches
QwCombinedBPM.cc
Go to the documentation of this file.
1/*!
2 * \file QwCombinedBPM.cc
3 * \brief Combined beam position monitor implementation using linear fitting
4 *
5 * Implementation of a combined BPM that fits transverse position as a
6 * charge-weighted linear combination of constituent BPMs. Provides per-axis
7 * slope/intercept, minimum chi-square, and an effective charge channel.
8 * Documentation-only edits; runtime behavior unchanged.
9 */
10
11#include "QwCombinedBPM.h"
12
13// System headers
14#include <stdexcept>
15
16// ROOT headers
17#ifdef HAS_RNTUPLE_SUPPORT
18#include "ROOT/RNTupleModel.hxx"
19#include "ROOT/RField.hxx"
20#endif // HAS_RNTUPLE_SUPPORT
21
22// Qweak headers
23#ifdef __USE_DATABASE__
24#include "QwDBInterface.h"
25#endif // __USE_DATABASE__
26#include "QwVQWK_Channel.h"
27#include "QwScaler_Channel.h"
28#include "QwParameterFile.h"
29#include "QwMollerADC_Channel.h"
30
31/**
32 * Initialize derived output channels using a simple detector name.
33 * Creates absolute position, slope, intercept, chi-square per axis, and
34 * an effective charge channel. Clears internal element/weight lists.
35 */
36template<typename T>
38{
39
41
42 fEffectiveCharge.InitializeChannel(name+"WS","derived");
43
44 for( Short_t axis=kXAxis;axis<kNumAxes;axis++){
45 fAbsPos[axis].InitializeChannel(name+kAxisLabel[axis],"derived");
46 fSlope[axis].InitializeChannel(name+kAxisLabel[axis]+"Slope","derived");
47 fIntercept[axis].InitializeChannel(name+kAxisLabel[axis]+"Intercept","derived");
48 fMinimumChiSquare[axis].InitializeChannel(name+kAxisLabel[axis]+"MinChiSquare","derived");
49 }
50
52
53 fElement.clear();
54 fQWeights.clear();
55 fXWeights.clear();
56 fYWeights.clear();
57
58 fSumQweights = 0.0;
59
60 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
61 erra[axis] = 0.0;
62 errb[axis] = 0.0;
63 covab[axis] = 0.0;
64 A[axis] = 0.0;
65 B[axis] = 0.0;
66 D[axis] = 0.0;
67 m[axis] = 0.0;
68 }
69
70 return;
71}
72
73/**
74 * Initialize derived output channels with explicit subsystem scoping.
75 * Forwards subsystem/name/type information to child channels.
76 */
77template<typename T>
78void QwCombinedBPM<T>::InitializeChannel(TString subsystem, TString name)
79{
80
82
83 fEffectiveCharge.InitializeChannel(subsystem, "QwCombinedBPM", name+"WS","derived");
84
85 for( Short_t axis=kXAxis;axis<kNumAxes;axis++){
86 fAbsPos[axis].InitializeChannel(subsystem, "QwCombinedBPM", name+kAxisLabel[axis],"derived");
87 fSlope[axis].InitializeChannel(subsystem, "QwCombinedBPM", name+kAxisLabel[axis]+"Slope","derived");
88 fIntercept[axis].InitializeChannel(subsystem, "QwCombinedBPM", name+kAxisLabel[axis]+"Intercept","derived");
89 fMinimumChiSquare[axis].InitializeChannel(subsystem, "QwCombinedBPM",name+kAxisLabel[axis]+"MinChiSquare","derived");
90 }
91
93
94 fElement.clear();
95 fQWeights.clear();
96 fXWeights.clear();
97 fYWeights.clear();
98
99 fSumQweights = 0.0;
100
101 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
102 erra[axis] = 0.0;
103 errb[axis] = 0.0;
104 covab[axis] = 0.0;
105 A[axis] = 0.0;
106 B[axis] = 0.0;
107 D[axis] = 0.0;
108 m[axis] = 0.0;
109 }
110
111 return;
112}
113
114
115/** Clear event-time state for effective charge and per-axis outputs. */
116template<typename T>
118{
119 fEffectiveCharge.ClearEventData();
120
121 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
122 fAbsPos[axis].ClearEventData();
123 fSlope[axis].ClearEventData();
124 fIntercept[axis].ClearEventData();
125 }
126
127 return;
128}
129
130
131/**
132 * Add a constituent BPM and associated weights to the combination.
133 *
134 * @param bpm Pointer to a constituent BPM instance.
135 * @param charge_weight Weight contributing to effective charge.
136 * @param x_weight Weight contributing to X position fit.
137 * @param y_weight Weight contributing to Y position fit.
138 * @param sumqw Precomputed sum of absolute charge weights.
139 */
140template<typename T>
141void QwCombinedBPM<T>::SetBPMForCombo(const VQwBPM* bpm, Double_t charge_weight, Double_t x_weight, Double_t y_weight,
142 Double_t sumqw)
143{
144 fElement.push_back(bpm);
145 fQWeights.push_back(charge_weight);
146 fXWeights.push_back(x_weight);
147 fYWeights.push_back(y_weight);
148 fSumQweights=sumqw;
149
150 size_t i = fElement.size();
151 if (i>=1){
152 i--;
153 // std::cout << "+++++++++++++++++++++++++++\n+++++++++++++++++++++++++++\n" << std::endl;
154 // std::cout << "fElement.size()==" << fElement.size() << " " << i << " "
155 // << fElement.at(i)->GetElementName() << " "
156 // << fQWeights.at(i) << " "
157 // << fXWeights.at(i) << " "
158 // << fYWeights.at(i) << " "
159 // << "fElement.at(i)->GetEffectiveCharge()==" << fElement.at(i)->GetEffectiveCharge() << " "
160 // << std::endl;
161 // fElement.at(i)->GetEffectiveCharge()->PrintInfo();
162 // fElement.at(i)->PrintInfo();
163 }
164 return;
165
166}
167
168
169/**
170 * Combined BPM does not add hardware checks beyond constituents.
171 *
172 * @return Always true; underlying BPMs manage their own HW checks.
173 */
174template<typename T>
176{
177 Bool_t eventokay=kTRUE;
178
179 return eventokay;
180}
181
182
183/** Increment persistent error counters for all derived outputs. */
184template<typename T>
186{
187 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
188 fAbsPos[axis].IncrementErrorCounters();
189 fSlope[axis].IncrementErrorCounters();
190 fIntercept[axis].IncrementErrorCounters();
191 fMinimumChiSquare[axis].IncrementErrorCounters();
192 }
193
194 fEffectiveCharge.IncrementErrorCounters();
195}
196
197/** Print persistent error counters for all derived outputs. */
198template<typename T>
200{
201 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
202 fAbsPos[axis].PrintErrorCounters();
203 fSlope[axis].PrintErrorCounters();
204 fIntercept[axis].PrintErrorCounters();
205 fMinimumChiSquare[axis].PrintErrorCounters();
206 }
207
208 fEffectiveCharge.PrintErrorCounters();
209}
210
211/**
212 * Aggregate event-cut error flags across per-axis outputs and effective
213 * charge.
214 */
215template<typename T>
217{
218 UInt_t error=0;
219 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
220 error|=fAbsPos[axis].GetEventcutErrorFlag();
221 error|=fSlope[axis].GetEventcutErrorFlag();
222 error|=fIntercept[axis].GetEventcutErrorFlag();
223 error|=fMinimumChiSquare[axis].GetEventcutErrorFlag();
224 }
225
226 error|=fEffectiveCharge.GetEventcutErrorFlag();
227 return error;
228}
229
230
231
232/**
233 * Apply single-event cuts to slope/intercept outputs per axis, using error
234 * masks from constituent BPM positions to gate derived quantities.
235 *
236 * @return true if all derived outputs pass their cuts.
237 */
238template<typename T>
240{
241 Bool_t status=kTRUE;
242 Int_t axis=0;
243 UInt_t charge_error;
244 UInt_t pos_error[2];
245 charge_error = 0;
246 pos_error[kXAxis]=0;
247 pos_error[kYAxis]=0;
248
249 for(size_t i=0;i<fElement.size();i++){
250 /// TODO: The returned base class should be changed so
251 /// these casts aren't needed, but "GetErrorCode"
252 /// is not meaningful for every VQwDataElement.
253 /// Maybe the return should be a VQwHardwareChannel?
254
255 //To update the event cut failures in individual BPM devices
256 charge_error |= fElement[i]->GetEffectiveCharge()->GetErrorCode();
257 pos_error[kXAxis] |= fElement[i]->GetPosition(kXAxis)->GetErrorCode();
258 pos_error[kYAxis] |= fElement[i]->GetPosition(kYAxis)->GetErrorCode();
259 }
260
261 //Event cuts for X & Y slopes
263 fSlope[axis].UpdateErrorFlag(pos_error[axis]);
264 if (fSlope[axis].ApplySingleEventCuts()){ //for X slope
265 status&=kTRUE;
266 }
267 else{
268 status&=kFALSE;
269 if (bDEBUG) std::cout<<" X Slope event cut failed ";
270 }
271 }
272
273 //Event cuts for X & Y intercepts
275 fIntercept[axis].UpdateErrorFlag(pos_error[axis]);
276 if (fIntercept[axis].ApplySingleEventCuts()){ //for X slope
277 status&=kTRUE;
278 }
279 else{
280 status&=kFALSE;
281 if (bDEBUG) std::cout<<" X Intercept event cut failed ";
282 }
283 }
284
285
286 //Event cuts for X & Y minimum chi square
288 fMinimumChiSquare[axis].UpdateErrorFlag(pos_error[axis]);
289 if (fMinimumChiSquare[axis].ApplySingleEventCuts()){ //for X slope
290 status&=kTRUE;
291 }
292 else{
293 status&=kFALSE;
294 if (bDEBUG) std::cout<<" X Intercept event cut failed ";
295 }
296 }
297
298
299 //Event cuts for X & Y positions
301 fAbsPos[axis].UpdateErrorFlag(pos_error[axis]);
303 status&=kTRUE;
304 }
305 else{
306 status&=kFALSE;
307 if (bDEBUG) std::cout<<" Abs X event cut failed ";
308 }
309 }
310
311 //Event cuts for four wire sum (EffectiveCharge)
312 fEffectiveCharge.UpdateErrorFlag(charge_error);
313 if (fEffectiveCharge.ApplySingleEventCuts()){
314 status&=kTRUE;
315 }
316 else{
317 status&=kFALSE;
318 if (bDEBUG) std::cout<<"EffectiveCharge event cut failed ";
319 }
320
321 return status;
322}
323
324template<typename T>
326{
327 Int_t axis=0;
328 UInt_t charge_error;
329 UInt_t pos_error[2];
330 charge_error = 0;
331 pos_error[kXAxis]=0;
332 pos_error[kYAxis]=0;
333
334 UInt_t error = 0;
335
336 for(size_t i=0;i<fElement.size();i++){
337 //To update the event cut failures in individual BPM devices
338 charge_error |= fElement[i]->GetEffectiveCharge()->GetErrorCode();
339 pos_error[kXAxis] |= fElement[i]->GetPosition(kXAxis)->GetErrorCode();
340 pos_error[kYAxis] |= fElement[i]->GetPosition(kYAxis)->GetErrorCode();
341 }
342
343 //Event cuts for X & Y slopes
345 fIntercept[axis].UpdateErrorFlag(pos_error[axis]);
346 fSlope[axis].UpdateErrorFlag(pos_error[axis]);
347 fMinimumChiSquare[axis].UpdateErrorFlag(pos_error[axis]);
348 fAbsPos[axis].UpdateErrorFlag(pos_error[axis]);
349
350 //Get the Event cut error flag for SlopeX/Y
351 error|=fSlope[axis].GetEventcutErrorFlag();
352 error|=fIntercept[axis].GetEventcutErrorFlag();
353 error|=fMinimumChiSquare[axis].GetEventcutErrorFlag();
354 error|=fAbsPos[axis].GetEventcutErrorFlag();
355
356 }
357
358 //Event cuts for four wire sum (EffectiveCharge)
359 fEffectiveCharge.UpdateErrorFlag(charge_error);
360 //Get the Event cut error flag for EffectiveCharge
361 error|=fEffectiveCharge.GetEventcutErrorFlag();
362
363 return error;
364}
365
366template<typename T>
368 Bool_t burpstatus = kFALSE;
369 try {
370 if (typeid(*ev_error) == typeid(*this)) {
371 if (this->GetElementName() != "") {
372 const QwCombinedBPM<T>* value_bpm = dynamic_cast<const QwCombinedBPM<T>*>(ev_error);
373 // Delegate to subelements
374 for (int i = 0; i < 2; ++i) {
375 burpstatus |= fAbsPos[i].CheckForBurpFail(&(value_bpm->fAbsPos[i]));
376 burpstatus |= fSlope[i].CheckForBurpFail(&(value_bpm->fSlope[i]));
377 burpstatus |= fIntercept[i].CheckForBurpFail(&(value_bpm->fIntercept[i]));
378 burpstatus |= fMinimumChiSquare[i].CheckForBurpFail(&(value_bpm->fMinimumChiSquare[i]));
379 }
380 burpstatus |= fEffectiveCharge.CheckForBurpFail(&(value_bpm->fEffectiveCharge));
381 }
382 } else {
383 TString loc = "Standard exception from QwCombinedBPM::CheckForBurpFail :" +
384 ev_error->GetElementName() + " " + this->GetElementName() + " are not of the same type";
385 throw std::invalid_argument(loc.Data());
386 }
387 } catch (std::exception& e) {
388 std::cerr << e.what() << std::endl;
389 }
390 return burpstatus;
391}
392
393template<typename T>
395{
396 VQwHardwareChannel* tmpptr = NULL;
397 ch_name.ToLower();
398 if (ch_name=="xslope"){
399 tmpptr = &fSlope[kXAxis];
400 }else if (ch_name=="yslope"){
401 tmpptr = &fSlope[kYAxis];
402 }else if (ch_name=="xintercept"){
403 tmpptr = &fIntercept[kXAxis];
404 }else if (ch_name=="yintercept"){
405 tmpptr = &fIntercept[kYAxis];
406 }else if (ch_name=="xminchisquare"){
407 tmpptr = &fMinimumChiSquare[kXAxis];
408 }else if (ch_name=="yminchisquare"){
409 tmpptr = &fMinimumChiSquare[kYAxis];
410 }else if (ch_name=="absx" || ch_name=="x" ){
411 tmpptr = &fAbsPos[kXAxis];
412 }else if (ch_name=="absy" || ch_name=="y"){
413 tmpptr = &fAbsPos[kYAxis];
414 }else if (ch_name=="effectivecharge" || ch_name=="charge"){
415 tmpptr = &fEffectiveCharge;
416 } else {
417 TString loc="QwCombinedBPM::GetSubelementByName for"
418 + this->GetElementName() + " was passed "
419 + ch_name + ", which is an unrecognized subelement name.";
420 throw std::invalid_argument(loc.Data());
421 }
422 return tmpptr;
423}
424
425/*
426template<typename T>
427void QwCombinedBPM<T>::SetSingleEventCuts(TString ch_name, Double_t minX, Double_t maxX)
428{
429
430 if (ch_name=="xslope"){//cuts for the x slope
431 QwMessage<<"XSlope LL " << minX <<" UL " << maxX <<QwLog::endl;
432 fSlope[kXAxis].SetSingleEventCuts(minX,maxX);
433
434 }else if (ch_name=="yslope"){//cuts for the y slope
435 QwMessage<<"YSlope LL " << minX <<" UL " << maxX <<QwLog::endl;
436 fSlope[kYAxis].SetSingleEventCuts(minX,maxX);
437
438 }else if (ch_name=="xintercept"){//cuts for the x intercept
439 QwMessage<<"XIntercept LL " << minX <<" UL " << maxX <<QwLog::endl;
440 fIntercept[kXAxis].SetSingleEventCuts(minX,maxX);
441
442 }else if (ch_name=="yintercept"){//cuts for the y intercept
443 QwMessage<<"YIntercept LL " << minX <<" UL " << maxX <<QwLog::endl;
444 fIntercept[kYAxis].SetSingleEventCuts(minX,maxX);
445
446 } else if (ch_name=="absx"){
447 //cuts for the absolute x and y
448 QwMessage<<"AbsX LL " << minX <<" UL " << maxX <<QwLog::endl;
449 fAbsPos[kXAxis].SetSingleEventCuts(minX,maxX);
450
451 }else if (ch_name=="absy"){
452 QwMessage<<"AbsY LL " << minX <<" UL " << maxX <<QwLog::endl;
453 fAbsPos[kYAxis].SetSingleEventCuts(minX,maxX);
454
455 }else if (ch_name=="effectivecharge"){ //cuts for the effective charge
456 QwMessage<<"EffectveQ LL " << minX <<" UL " << maxX <<QwLog::endl;
457 fEffectiveCharge.SetSingleEventCuts(minX,maxX);
458 }
459}
460
461template<typename T>
462void QwCombinedBPM<T>::SetSingleEventCuts(TString ch_name, UInt_t errorflag,Double_t minX, Double_t maxX, Double_t stability){
463 errorflag|=kBPMErrorFlag;//update the device flag
464 if (ch_name=="xslope"){//cuts for the x slope
465 QwMessage<<"XSlope LL " << minX <<" UL " << maxX << " kGlobalCut "<< (errorflag&kGlobalCut)<< QwLog::endl;
466 fSlope[kXAxis].SetSingleEventCuts(errorflag, minX,maxX, stability);
467
468 }else if (ch_name=="yslope"){//cuts for the y slope
469 QwMessage<<"YSlope LL " << minX <<" UL " << maxX <<" kGlobalCut "<< (errorflag&kGlobalCut)<< QwLog::endl;
470 fSlope[kYAxis].SetSingleEventCuts(errorflag, minX,maxX, stability);
471
472 }else if (ch_name=="xintercept"){//cuts for the x intercept
473 QwMessage<<"XIntercept LL " << minX <<" UL " << maxX <<" kGlobalCut "<< (errorflag&kGlobalCut)<< QwLog::endl;
474 fIntercept[kXAxis].SetSingleEventCuts(errorflag, minX,maxX, stability);
475
476 }else if (ch_name=="yintercept"){//cuts for the y intercept
477 QwMessage<<"YIntercept LL " << minX <<" UL " << maxX <<" kGlobalCut "<< (errorflag&kGlobalCut)<< QwLog::endl;
478 fIntercept[kYAxis].SetSingleEventCuts(errorflag, minX,maxX, stability);
479
480 } else if (ch_name=="absx"){
481 //cuts for the absolute x and y
482 QwMessage<<"AbsX LL " << minX <<" UL " << maxX <<" kGlobalCut "<< (errorflag&kGlobalCut)<< QwLog::endl;
483 fIntercept[kXAxis].SetSingleEventCuts(errorflag, 0,0,0);
484 fAbsPos[kXAxis].SetSingleEventCuts(errorflag, minX,maxX, stability);
485
486 }else if (ch_name=="absy"){
487 QwMessage<<"AbsY LL " << minX <<" UL " << maxX <<" kGlobalCut "<< (errorflag&kGlobalCut)<< QwLog::endl;
488 fIntercept[kYAxis].SetSingleEventCuts(errorflag, 0,0,0);
489 fAbsPos[kYAxis].SetSingleEventCuts(errorflag, minX,maxX, stability);
490
491 }else if (ch_name=="effectivecharge"){ //cuts for the effective charge
492 QwMessage<<"EffectveQ LL " << minX <<" UL " << maxX <<" kGlobalCut "<< (errorflag&kGlobalCut)<< QwLog::endl;
493 fEffectiveCharge.SetSingleEventCuts(errorflag, minX,maxX, stability);
494 }
495}
496
497*/
498
499template<typename T>
501 Short_t i=0;
502 try {
503 if(typeid(*ev_error)==typeid(*this)) {
504 // std::cout<<" Here in QwBPMStripline::UpdateErrorFlag \n";
505 if (this->GetElementName()!="") {
506 const QwCombinedBPM<T>* value_bpm = dynamic_cast<const QwCombinedBPM<T>* >(ev_error);
507 for(i=kXAxis;i<kNumAxes;i++) {
508 fAbsPos[i].UpdateErrorFlag(value_bpm->fAbsPos[i]);
509 fSlope[i].UpdateErrorFlag(value_bpm->fSlope[i]);
510 fIntercept[i].UpdateErrorFlag(value_bpm->fIntercept[i]);
511 fMinimumChiSquare[i].UpdateErrorFlag(value_bpm->fMinimumChiSquare[i]);
512 }
513 fEffectiveCharge.UpdateErrorFlag(value_bpm->fEffectiveCharge);
514 }
515 } else {
516 TString loc="Standard exception from QwCombinedBPM::UpdateErrorFlag :"+
517 ev_error->GetElementName()+" "+this->GetElementName()+" are not of the "
518 +"same type";
519 throw std::invalid_argument(loc.Data());
520 }
521 } catch (std::exception& e) {
522 std::cerr<< e.what()<<std::endl;
523 }
524};
525
526
527
528template<typename T>
530{
531 Bool_t ldebug = kFALSE;
532
533 static T tmpQADC("tmpQADC"), tmpADC("tmpADC");
534
535 this->ClearEventData();
536 //check to see if the fixed parameters are calculated
538 if(ldebug) std::cout<<"QwCombinedBPM:Calculating fixed parameters..\n";
541 fixedParamCalculated = kTRUE;
542 }
543
544 for(size_t i=0;i<fElement.size();i++){
545 if(ldebug){
546 std::cout<<"*******************************\n";
547 std::cout<<" QwCombinedBPM: Reading "<<fElement[i]->GetElementName()<<" with charge weight ="<<fQWeights[i]
548 <<" and x weight ="<<fXWeights[i]
549 <<" and y weight ="<<fYWeights[i]<<"\n"<<std::flush;
550
551 }
552 tmpQADC.AssignValueFrom(fElement[i]->GetEffectiveCharge());
553 tmpQADC.Scale(fQWeights[i]);
554 fEffectiveCharge+=tmpQADC;
555
556
557 if(ldebug) {
558 std::cout<<"fElement[" << i << "]->GetEffectiveCharge()=="
559 << fElement[i]->GetEffectiveCharge()
560 << std::endl << std::flush;
561 fElement[i]->GetEffectiveCharge()->PrintInfo();
562 std::cout<<"fElement[" << i << "]->GetPosition(kXAxis)=="
563 << fElement[i]->GetPosition(kXAxis)
564 << std::endl << std::flush;
565 std::cout<<"fElement[" << i << "]->GetPosition(kYAxis)=="
566 << fElement[i]->GetPosition(kYAxis)
567 << std::endl << std::flush;
568
569 if (fElement[i]->GetEffectiveCharge()==NULL){
570 std::cout<<"fElement[" << i << "]->GetEffectiveCharge returns NULL"
571 << std::endl;
572 } else
573 std::cout<<"got 4-wire.hw_sum = "<<fEffectiveCharge.GetValue()
574 <<" vs actual "
575 << fElement[i]->GetEffectiveCharge()->GetValue()
576 << std::endl << std::flush;
577
578
579 std::cout<<"copied absolute X position hw_sum from device "
580 << fElement[i]->GetPosition(kXAxis)->GetValue() <<std::endl;
581 std::cout<<"copied absolute Y position hw_sum from device "
582 << fElement[i]->GetPosition(kYAxis)->GetValue() <<std::endl;
583
584 }
585 }
586
588 //fAbsPos[0].ResetErrorFlag(0x4000000);
589 //Least squares fit for X
591
592 //Least squares fit for Y
594
595
596 if(ldebug){
597 std::cout<<" QwCombinedBPM:: Projected target X position = "<<fAbsPos[kXAxis].GetValue()
598 <<" and target X slope = "<<fSlope[kXAxis].GetValue()
599 <<" and target X intercept = "<<fIntercept[kXAxis].GetValue()
600 <<" with minimum chi square = "<< fMinimumChiSquare[kXAxis].GetValue()
601 <<" \nProjected target Y position = "<<fAbsPos[kYAxis].GetValue()
602 <<" and target Y slope = "<<fSlope[kYAxis].GetValue()
603 <<" and target Y intercept = "<<fIntercept[kYAxis].GetValue()
604 <<" with minimum chi square = "<< fMinimumChiSquare[kYAxis].GetValue()<<std::endl;
605
606 }
607
608
609 if (ldebug) {
610 //fEffectiveCharge.PrintInfo();
611 for(Short_t axis=kXAxis;axis<kNumAxes;axis++) {
612 fAbsPos[axis].PrintInfo();
613 fSlope[axis].PrintInfo();
614 fIntercept[axis].PrintInfo();
615 //fMinimumChiSquare[axis].PrintInfo();
616 }
617 }
618
619 return;
620
621 }
622
623
624
625template<typename T>
626 void QwCombinedBPM<T>::CalculateFixedParameter(std::vector<Double_t> fWeights, Int_t pos)
627 {
628
629 Bool_t ldebug = kFALSE;
630 static Double_t zpos = 0.0;
631
632 for(size_t i=0;i<fElement.size();i++){
633 zpos = fElement[i]->GetPositionInZ();
634 A[pos] += zpos*fWeights[i]; //zw
635 B[pos] += fWeights[i]; //w
636 D[pos] += zpos*zpos*fWeights[i]; //z^2w
637 }
638
639 m[pos] = D[pos]*B[pos]-A[pos]*A[pos];
640 erra[pos] = B[pos]/m[pos];
641 errb[pos] = D[pos]/m[pos];
642 covab[pos] = -A[pos]/m[pos];
643
644 // Divvy
645 if (m[pos] == 0)
646 QwWarning << "Angry Divvy: Division by zero in " << this->GetElementName() << QwLog::endl;
647
648 if(ldebug){
649 std::cout<<" A = "<<A[pos]<<", B = "<<B[pos]<<", D = "<<D[pos]<<", m = "<<m[pos]<<std::endl;
650 std::cout<<"For least square fit, errors are "<<erra[pos]
651 <<"\ncovariance = "<<covab[pos]<<"\n\n";
652 }
653
654 return;
655 }
656
657
658template<typename T>
659 Double_t QwCombinedBPM<T>::SumOver(std::vector<Double_t> weight,std::vector <T> val)
660 {
661 Double_t sum = 0.0;
662 if(weight.size()!=fElement.size()){
663 std::cout
664 <<"QwCombinedBPM:: Number of devices doesn't match the number of weights."
665 <<" Exiting calculating parameters for the least squares fit"
666 <<std::endl;
667 }
668 else{
669 for(size_t i=0;i<weight.size();i++){
670 val[i].Scale(weight[i]);
671 sum+=val[i].GetValue();
672 }
673 }
674 return sum;
675 }
676
677template<typename T>
679 {
680
681 /**
682 REF : W.R Leo
683
684 For Y = aX +b
685
686 A = sigma(X * Wy) B = sigma(Wy) C = sigma(Y*Wy) D = sigma(X *X * Wy) E = sigma(X*Y*Wy) F = sigma(Y * Y *Wy)
687
688 then
689 a = (EB-CA)/(DB-AA) b =(DC-EA)/(DB-AA)
690 **/
691
692 Bool_t ldebug = kFALSE;
693 static Double_t zpos = 0;
694 static T tmp1("tmp1","derived");
695 static T tmp2("tmp2","derived");
696 static T tmp3("tmp3","derived");
697 static T C[kNumAxes];
698 static T E[kNumAxes];
699
700 // initialize the VQWK_Channel arrays
701 C[kXAxis].InitializeChannel("cx","derived");
702 C[kYAxis].InitializeChannel("cy","derived");
703 E[kXAxis].InitializeChannel("ex","derived");
704 E[kYAxis].InitializeChannel("ey","derived");
705
706 C[axis].ClearEventData();
707 E[axis].ClearEventData();
708 for(size_t i=0;i<fElement.size();i++){
709 zpos = fElement[i]->GetPositionInZ();
710 tmp1.ClearEventData();
711 tmp1.AssignValueFrom(fElement[i]->GetPosition(axis));
712 tmp1.Scale(fWeights[i]);
713 C[axis] += tmp1; //xw or yw
714 tmp1.Scale(zpos);//xzw or yzw
715 E[axis] += tmp1;
716 }
717
718 if(ldebug) std::cout<<"\n A ="<<A[axis]
719 <<" -- B ="<<B[axis]
720 <<" --C ="<<C[axis].GetValue()
721 <<" --D ="<<D[axis]
722 <<" --E ="<<E[axis].GetValue()<<"\n";
723
724 // calculate the slope a = E*erra + C*covab
725 fSlope[axis].AssignScaledValue(E[axis], erra[axis]);
726 tmp2.AssignScaledValue(C[axis], covab[axis]);
727 fSlope[axis] += tmp2;
728
729 // calculate the intercept b = C*errb + E*covab
730 fIntercept[axis].AssignScaledValue(C[axis], errb[axis]);
731 tmp2.AssignScaledValue(E[axis], covab[axis]);
732 fIntercept[axis] += tmp2;
733
734 if(ldebug) std::cout<<" Least Squares Fit Parameters for "<< axis
735 <<" are: \n slope = "<< fSlope[axis].GetValue()
736 <<" \n intercept = " << fIntercept[axis].GetValue()<<"\n\n";
737
738
739 // absolute positions at target using X = Za + b
740 tmp1.ClearEventData();
741 // Absolute position of the combined bpm is not a physical position but a derived one.
742
743
744 zpos = this->GetPositionInZ();
745 //UInt_t err_flag=fAbsPos[axis].GetEventcutErrorFlag();
746 fAbsPos[axis] = fIntercept[axis]; // X = b
747 //fAbsPos[axis].ResetErrorFlag(err_flag);
748 tmp1.AssignScaledValue(fSlope[axis],zpos); //az
749 fAbsPos[axis] += tmp1; //X = az+b
750
751
752 // to perform the minimul chi-square test
753 // We want to calculate (X-az-b)^2 for each bpm in the combination and sum over the values
754 tmp3.ClearEventData();
755 fMinimumChiSquare[axis].ClearEventData();
756
757 for(size_t i=0;i<fElement.size();i++){
758 tmp1.ClearEventData();
759 tmp2.ClearEventData();
760 //std::cout<<"\nName -------- ="<<(fElement[i]->GetElementName())<<std::endl;
761 //std::cout<<"\nRead value ="<<(fElement[i]->GetPosition(axis))->GetValue()<<std::endl;
762
763 tmp1.AssignValueFrom(fElement[i]->GetPosition(axis)); // = X
764 //std::cout<<"Read value ="<<tmp1.GetValue()<<std::endl;
765
766 tmp2.AssignScaledValue(fSlope[axis],fElement[i]->GetPositionInZ());
767 tmp2+=fIntercept[axis];
768 //std::cout<<"Calculated abs value ="<<tmp2.GetValue()<<std::endl;
769
770 tmp1 -= tmp2; // = X-Za-b
771 //std::cout<<"Read-calculated ="<<tmp1.GetValue()<<std::endl;
772 tmp1.Product(tmp1,tmp1); // = (X-Za-b)^2
773 //std::cout<<"(Read-calculated)^2 ="<<tmp1.GetValue()<<std::endl;
774 tmp1.Scale(fWeights[i]*fWeights[i]); // = [(X-Za-b)^2]W
775 //std::cout<<"(Read-calculated)^2/weight ="<<tmp1.GetValue()<<std::endl;
776 tmp3+=tmp1; //sum over
777 //std::cout<<"Sum (Read-calculated)^2/weight +="<<tmp3.GetValue()<<std::endl;
778 }
779
780 if (fElement.size()>2){
781 fMinimumChiSquare[axis].AssignScaledValue(tmp3,1.0/(fElement.size()-2)); //minimul chi-square
782 } else {
783 fMinimumChiSquare[axis].AssignScaledValue(tmp3,0.0);
784 }
785
786 //std::cout << "1.0/fElement.size() = " << 1.0/fElement.size() << std::endl;
787
788 return;
789 }
790
791template<typename T>
792 Int_t QwCombinedBPM<T>::ProcessEvBuffer(UInt_t* buffer, UInt_t word_position_in_buffer,UInt_t index)
793 {
794 return word_position_in_buffer;
795 }
796
797//-----------------------------------------------------------------------------------------------------------
798
799template<typename T>
801 {
802 // For now, go ahead and do the projection for any BPM, not just for ones which are used by this
803 // CombinedBPM object.
804
806
807 for(Short_t iaxis=kXAxis; iaxis<kNumAxes; iaxis++) {
808 //std::cout << "iaxis= " << iaxis << std::endl;
809 //std::cout << "kNumAxes= " << kNumAxes << std::endl;
810 if (iaxis==kXAxis) {
811 axis=kXAxis;
812 //std::cout << "kXAxis= " << kXAxis << std::endl;
813 //std::cout << "axis= " << axis << std::endl;
814 }
815 else if (iaxis==kYAxis) {
816 axis=kYAxis;
817 //std::cout << "kYAxis= " << kYAxis << std::endl;
818 //std::cout << "axis= " << axis << std::endl;
819 }
820 else continue;
821 (device->GetPosition(axis))->ClearEventData();
822 (device->GetPosition(axis))->AssignScaledValue(fSlope[axis],device->GetPositionInZ());
823 (device->GetPosition(axis))->operator+=(fIntercept[axis]);
824 }
825 // Maybe we should apply resolution smearing to the stripline BPMs?
826 // device->PrintInfo();
827 device->ApplyResolutionSmearing();
828 //device->PrintInfo();
829 device->FillRawEventData();
830 //std::cout << "Device " << device->GetElementName() << " X = " << std::setprecision(15) << device->GetPosition(kXAxis)->GetValue()
831 //<< "\t Y = " << std::setprecision(15) << device->GetPosition(kYAxis)->GetValue() << std::endl;
832}
833
834//-----------------------------------------------------------------------------------------------------------
835
836
837template<typename T>
839{
840 Short_t axis;
841
842 for(axis = kXAxis; axis < kNumAxes; axis++){
843 fAbsPos[axis].PrintValue();
844 }
845 /// TODO: To print the Z position, we need to use GetPositionInZ()
846 for(axis = kXAxis; axis < kNumAxes; axis++) {
847 fSlope[axis].PrintValue();
848 fIntercept[axis].PrintValue();
849 fMinimumChiSquare[axis].PrintValue();
850 }
851 fEffectiveCharge.PrintValue();
852
853 return;
854 }
855
856
857template<typename T>
859{
860
861 Short_t axis;
862
863 for(axis = kXAxis; axis < kNumAxes; axis++){
864 fAbsPos[axis].PrintInfo();
865 }
866 /// TODO: To print the Z position, we need to use GetPositionInZ()
867 for(axis = kXAxis; axis < kNumAxes; axis++) {
868 fSlope[axis].PrintInfo();
869 fIntercept[axis].PrintInfo();
870 fMinimumChiSquare[axis].PrintInfo();
871 }
872 fEffectiveCharge.PrintInfo();
873
874 return;
875}
876
877
878template<typename T>
880{
881 *(dynamic_cast<QwCombinedBPM<T>*>(this))=
882 *(dynamic_cast<const QwCombinedBPM<T>*>(&value));
883 return *this;
884}
885
886template<typename T>
888{
889 VQwBPM::operator= (value);
890 if (this->GetElementName()!=""){
892 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
893 this->fSlope[axis]=value.fSlope[axis];
894 this->fIntercept[axis] = value.fIntercept[axis];
895 this->fAbsPos[axis]=value.fAbsPos[axis];
897 }
898 }
899 return *this;
900}
901
902
903template<typename T>
905{
906 *(dynamic_cast<QwCombinedBPM<T>*>(this))+=
907 *(dynamic_cast<const QwCombinedBPM<T>*>(&value));
908 return *this;
909}
910
911template<typename T>
913{
914
915 if (this->GetElementName()!=""){
917 for(Short_t axis=kXAxis;axis<kNumAxes;axis++) {
918 this->fSlope[axis]+=value.fSlope[axis];
919 this->fIntercept[axis]+=value.fIntercept[axis];
920 this->fAbsPos[axis]+=value.fAbsPos[axis];
922 }
923 }
924 return *this;
925}
926
927template<typename T>
929{
930 *(dynamic_cast<QwCombinedBPM<T>*>(this))-=
931 *(dynamic_cast<const QwCombinedBPM<T>*>(&value));
932 return *this;
933}
934
935
936template<typename T>
938{
939
940 if (this->GetElementName()!=""){
942 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
943 this->fSlope[axis]-=value.fSlope[axis];
944 this->fIntercept[axis]-=value.fIntercept[axis];
945 this->fAbsPos[axis]-=value.fAbsPos[axis];
947 }
948 }
949 return *this;
950}
951
952
953template<typename T>
955{
956 Ratio(*dynamic_cast<QwCombinedBPM<T>*>(&numer),
957 *dynamic_cast<QwCombinedBPM<T>*>(&denom));
958}
959
960template<typename T>
962 QwCombinedBPM<T> &denom)
963{
964 // this function is called when forming asymmetries. In this case what we actually want for the
965 // combined bpm is the difference only not the asymmetries
966
967 *this=numer;
968 this->fEffectiveCharge.Ratio(numer.fEffectiveCharge,denom.fEffectiveCharge);
969 if (this->GetElementName()!=""){
970 // The slope, intercept and absolute positions should all be differences, not asymmetries.
971 for(Short_t axis=kXAxis;axis<kNumAxes;axis++) {
972 this->fSlope[axis] = numer.fSlope[axis];
973 this->fIntercept[axis] = numer.fIntercept[axis];
974 this->fAbsPos[axis] = numer.fAbsPos[axis];
976 }
977 }
978
979 return;
980}
981
982
983template<typename T>
984void QwCombinedBPM<T>::Scale(Double_t factor)
985{
986 fEffectiveCharge.Scale(factor);
987 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
988 fSlope[axis].Scale(factor);
989 fIntercept[axis].Scale(factor);
990 fAbsPos[axis].Scale(factor);
991 fMinimumChiSquare[axis].Scale(factor);
992 }
993 return;
994}
995
996template<typename T>
998{
999 fEffectiveCharge.CalculateRunningAverage();
1000
1001 for (Short_t axis = kXAxis; axis < kNumAxes; axis++) {
1002 fSlope[axis].CalculateRunningAverage();
1003 fIntercept[axis].CalculateRunningAverage();
1004 fAbsPos[axis].CalculateRunningAverage();
1005 fMinimumChiSquare[axis].CalculateRunningAverage();
1006 }
1007}
1008
1009
1010template<typename T>
1011void QwCombinedBPM<T>::AccumulateRunningSum(const VQwBPM& value, Int_t count, Int_t ErrorMask)
1012{
1013 AccumulateRunningSum(*dynamic_cast<const QwCombinedBPM<T>* >(&value), count, ErrorMask);
1014}
1015
1016template<typename T>
1017void QwCombinedBPM<T>::AccumulateRunningSum(const QwCombinedBPM<T>& value, Int_t count, Int_t ErrorMask)
1018{
1019 for (Short_t axis = kXAxis; axis < kNumAxes; axis++){
1020 fSlope[axis].AccumulateRunningSum(value.fSlope[axis], count, ErrorMask);
1021 fIntercept[axis].AccumulateRunningSum(value.fIntercept[axis], count, ErrorMask);
1022 fAbsPos[axis].AccumulateRunningSum(value.fAbsPos[axis], count, ErrorMask);
1023 fMinimumChiSquare[axis].AccumulateRunningSum(value.fMinimumChiSquare[axis], count, ErrorMask);
1024 }
1025 fEffectiveCharge.AccumulateRunningSum(value.fEffectiveCharge, count, ErrorMask);
1026}
1027
1028template<typename T>
1030{
1031 DeaccumulateRunningSum(*dynamic_cast<QwCombinedBPM<T>* >(&value), ErrorMask);
1032}
1033
1034template<typename T>
1036{
1037
1038 for (Short_t axis = kXAxis; axis < kNumAxes; axis++){
1039 fSlope[axis].DeaccumulateRunningSum(value.fSlope[axis], ErrorMask);
1040 fIntercept[axis].DeaccumulateRunningSum(value.fIntercept[axis], ErrorMask);
1041 fAbsPos[axis].DeaccumulateRunningSum(value.fAbsPos[axis], ErrorMask);
1042 fMinimumChiSquare[axis].DeaccumulateRunningSum(value.fMinimumChiSquare[axis], ErrorMask);
1043 }
1044 fEffectiveCharge.DeaccumulateRunningSum(value.fEffectiveCharge, ErrorMask);
1045
1046}
1047
1048
1049
1050
1051
1052template<typename T>
1053void QwCombinedBPM<T>::ConstructHistograms(TDirectory *folder, TString &prefix)
1054{
1055
1056 if (this->GetElementName()==""){
1057 // This channel is not used, so skip filling the histograms.
1058 }
1059 else{
1060 //we calculate the asym_ for the fEffectiveCharge because its an asymmetry and not a difference.
1061 fEffectiveCharge.ConstructHistograms(folder, prefix);
1062 TString thisprefix=prefix;
1063 if(prefix.Contains("asym_"))
1064 thisprefix.ReplaceAll("asym_","diff_");
1065 this->SetRootSaveStatus(prefix);
1066
1067 for(Short_t axis=kXAxis;axis<kNumAxes;axis++) {
1068 fSlope[axis].ConstructHistograms(folder, thisprefix);
1069 fIntercept[axis].ConstructHistograms(folder, thisprefix);
1070 fAbsPos[axis].ConstructHistograms(folder, thisprefix);
1071 fMinimumChiSquare[axis].ConstructHistograms(folder, thisprefix);
1072 }
1073
1074 }
1075 return;
1076}
1077
1078template<typename T>
1080{
1081 if (this->GetElementName()==""){
1082 // This channel is not used, so skip filling the histograms.
1083 }
1084 else{
1085 fEffectiveCharge.FillHistograms();
1086 for(Short_t axis=kXAxis;axis<kNumAxes;axis++) {
1087 fSlope[axis].FillHistograms();
1088 fIntercept[axis].FillHistograms();
1089 fAbsPos[axis].FillHistograms();
1090 fMinimumChiSquare[axis].FillHistograms();
1091 }
1092 }
1093 return;
1094}
1095
1096template<typename T>
1098{
1099 if (this->GetElementName()==""){
1100 // This channel is not used, so skip constructing trees.
1101 } else
1102 {
1103
1104 TString thisprefix=prefix;
1105 if(prefix.Contains("asym_"))
1106 thisprefix.ReplaceAll("asym_","diff_");
1107
1108 this->SetRootSaveStatus(prefix);
1109
1110 fEffectiveCharge.ConstructBranchAndVector(tree,prefix,values);
1111 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
1112 fSlope[axis].ConstructBranchAndVector(tree,thisprefix,values);
1113 fIntercept[axis].ConstructBranchAndVector(tree,thisprefix,values);
1114 fAbsPos[axis].ConstructBranchAndVector(tree,thisprefix,values);
1115 fMinimumChiSquare[axis].ConstructBranchAndVector(tree,thisprefix,values);
1116 }
1117
1118 }
1119
1120 return;
1121}
1122
1123template<typename T>
1124void QwCombinedBPM<T>::ConstructBranch(TTree *tree, TString &prefix)
1125{
1126 if (this->GetElementName()==""){
1127 // This channel is not used, so skip constructing trees.
1128 } else
1129 {
1130 TString thisprefix=prefix;
1131 if(prefix.Contains("asym_"))
1132 thisprefix.ReplaceAll("asym_","diff_");
1133
1134
1135 fEffectiveCharge.ConstructBranch(tree,prefix);
1136
1137 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
1138 fSlope[axis].ConstructBranch(tree,thisprefix);
1139 fIntercept[axis].ConstructBranch(tree,thisprefix);
1140 fAbsPos[axis].ConstructBranch(tree,thisprefix);
1141 fMinimumChiSquare[axis].ConstructBranch(tree,thisprefix);
1142 }
1143
1144 }
1145 return;
1146}
1147
1148template<typename T>
1149void QwCombinedBPM<T>::ConstructBranch(TTree *tree, TString &prefix, QwParameterFile& modulelist)
1150{
1151 TString devicename;
1152 devicename=this->GetElementName();
1153 devicename.ToLower();
1154
1155 if (this->GetElementName()==""){
1156 // This channel is not used, so skip constructing trees.
1157 } else
1158 {
1159 if (modulelist.HasValue(devicename)){
1160 TString thisprefix=prefix;
1161 if(prefix.Contains("asym_"))
1162 thisprefix.ReplaceAll("asym_","diff_");
1163
1164
1165 fEffectiveCharge.ConstructBranch(tree,prefix);
1166
1167 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
1168 fSlope[axis].ConstructBranch(tree,thisprefix);
1169 fIntercept[axis].ConstructBranch(tree,thisprefix);
1170 fAbsPos[axis].ConstructBranch(tree,thisprefix);
1171 fMinimumChiSquare[axis].ConstructBranch(tree,thisprefix);
1172 }
1173 QwMessage <<" Tree leave added to "<<devicename<<QwLog::endl;
1174 }
1175
1176 }
1177 return;
1178}
1179
1180
1181template<typename T>
1183{
1184 if (this->GetElementName()==""){
1185 // This channel is not used, so skip filling the tree.
1186 }
1187 else{
1188 fEffectiveCharge.FillTreeVector(values);
1189
1190 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
1191 fSlope[axis].FillTreeVector(values);
1192 fIntercept[axis].FillTreeVector(values);
1193 fAbsPos[axis].FillTreeVector(values);
1194 fMinimumChiSquare[axis].FillTreeVector(values);
1195 }
1196 }
1197 return;
1198}
1199
1200#ifdef HAS_RNTUPLE_SUPPORT
1201template<typename T>
1202void QwCombinedBPM<T>::ConstructNTupleAndVector(std::unique_ptr<ROOT::RNTupleModel>& model, TString& prefix, std::vector<Double_t>& values, std::vector<std::shared_ptr<Double_t>>& fieldPtrs)
1203{
1204 if (this->GetElementName()==""){
1205 // This channel is not used, so skip constructing RNTuple.
1206 } else
1207 {
1208 TString thisprefix=prefix;
1209 if(prefix.Contains("asym_"))
1210 thisprefix.ReplaceAll("asym_","diff_");
1211
1212 this->SetRootSaveStatus(prefix);
1213
1214 fEffectiveCharge.ConstructNTupleAndVector(model, prefix, values, fieldPtrs);
1215 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
1216 fSlope[axis].ConstructNTupleAndVector(model, thisprefix, values, fieldPtrs);
1217 fIntercept[axis].ConstructNTupleAndVector(model, thisprefix, values, fieldPtrs);
1218 fAbsPos[axis].ConstructNTupleAndVector(model, thisprefix, values, fieldPtrs);
1219 fMinimumChiSquare[axis].ConstructNTupleAndVector(model, thisprefix, values, fieldPtrs);
1220 }
1221 }
1222}
1223
1224template<typename T>
1225void QwCombinedBPM<T>::FillNTupleVector(std::vector<Double_t>& values) const
1226{
1227 if (this->GetElementName()==""){
1228 // This channel is not used, so skip filling the RNTuple.
1229 }
1230 else{
1231 fEffectiveCharge.FillNTupleVector(values);
1232
1233 for(Short_t axis=kXAxis;axis<kNumAxes;axis++){
1234 fSlope[axis].FillNTupleVector(values);
1235 fIntercept[axis].FillNTupleVector(values);
1236 fAbsPos[axis].FillNTupleVector(values);
1237 fMinimumChiSquare[axis].FillNTupleVector(values);
1238 }
1239 }
1240}
1241#endif // HAS_RNTUPLE_SUPPORT
1242
1243template<typename T>
1245{
1246
1247 // bEVENTCUTMODE=bcuts;
1248 for (Short_t axis=kXAxis;axis<kNumAxes;axis++){
1249 fSlope[axis].SetEventCutMode(bcuts);
1250 fIntercept[axis].SetEventCutMode(bcuts);
1251 fAbsPos[axis].SetEventCutMode(bcuts);
1252 fMinimumChiSquare[axis].SetEventCutMode(bcuts);
1253 }
1254 fEffectiveCharge.SetEventCutMode(bcuts);
1255
1256 return;
1257}
1258
1259
1260template<typename T>
1262{
1263 for (size_t axis = kXAxis; axis < kNumAxes; axis++) {
1264 T abspos(fAbsPos[axis]);
1265 abspos = fAbsPos[axis];
1266 fBPMComboElementList.push_back(abspos);
1267 T slope(fSlope[axis]);
1268 slope = fSlope[axis];
1269 fBPMComboElementList.push_back(slope);
1270 T intercept(fIntercept[axis]);
1271 intercept = fIntercept[axis];
1272 fBPMComboElementList.push_back(intercept);
1273 T minimumchisquare(fMinimumChiSquare[axis]);
1274 minimumchisquare = fMinimumChiSquare[axis];
1275 fBPMComboElementList.push_back(minimumchisquare);
1276 }
1277 T effectivecharge(fEffectiveCharge);
1278 effectivecharge = fEffectiveCharge;
1279 fBPMComboElementList.push_back(effectivecharge);
1280}
1281
1282//-----------------------------------------------------------------------
1283
1284template<typename T>
1285void QwCombinedBPM<T>::RandomizeEventData(int helicity, double time)
1286{
1287 static Double_t zpos = 0;
1288 static T tmp1("tmp1","derived");
1289 // Randomize the abs position and angle.
1290 for (size_t axis=kXAxis; axis<kNumAxes; axis++)
1291 {
1292 //std::cout << "In QwCombinedBPM::RandomizeEventData-> Slope(before): " << fSlope[axis].GetValue() << std::endl;
1293 //std::cout << "BEFORE RANDOMIZING POS & SLOPE: " << std::endl;
1294 //fSlope[axis].PrintInfo();
1295 //fAbsPos[axis].PrintInfo();
1296
1297 fAbsPos[axis].RandomizeEventData(helicity, time);
1298 fSlope[axis].RandomizeEventData(helicity, time);
1299
1300 //std::cout << "AFTER RANDOMIZING POS & SLOPE: " << std::endl;
1301 //fSlope[axis].PrintInfo();
1302 //fAbsPos[axis].PrintInfo();
1303 //fSlope[axis].PrintValue();
1304 //std::cout << "In QwCombinedBPM::RandomizeEventData-> Slope(after): " << fSlope[axis].GetValue() << std::endl;
1305
1306 zpos = this->GetPositionInZ();
1307 //std::cout << "In QwCombinedBPM: zpos= " << zpos << std::endl;
1308 //UInt_t err_flag=fAbsPos[axis].GetEventcutErrorFlag();
1309 fIntercept[axis] = fAbsPos[axis]; // b = X
1310 //fAbsPos[axis].ResetErrorFlag(err_flag);
1311 tmp1.AssignScaledValue(fSlope[axis],zpos); //az
1312 fIntercept[axis] -= tmp1; //b = X - az
1313 // std::cout << axis << " " << fAbsPos[axis].GetValue() << "-" << fSlope[axis].GetValue() <<"*"<<zpos <<"=?" << fIntercept[axis].GetValue() << std::endl;
1314 }
1315 return;
1316}
1317
1318
1319template<typename T>
1321/*
1322 Bool_t ldebug=kFALSE;
1323 Double_t meanX=0.0, sigmaX=0.0, meanY=0.0, sigmaY=0.0;
1324 Double_t meanXslope=0.0, sigmaXslope=0.0, meanYslope=0.0, sigmaYslope=0.0;
1325*/
1326 Double_t xres=0.0, yres=0.0; // Temporary variables for the resolution.
1327
1328 if (paramfile.GetLine().find("resolution")!=std::string::npos){
1329 paramfile.GetNextToken();
1330 xres = paramfile.GetTypedNextToken<Double_t>();
1331 yres = paramfile.GetTypedNextToken<Double_t>();
1332 this->SetResolution(xres, yres);
1333 } else {
1334 // If we have asym, mean, sigma for each coorindate, then we can do:
1335
1336 TString value = paramfile.GetNextToken();
1337 if (value=="xpos") {
1338 fAbsPos[kXAxis].SetMockDataAsDiff();
1339 fAbsPos[kXAxis].LoadMockDataParameters(paramfile);
1340 }
1341 else if (value=="ypos") {
1342 fAbsPos[kYAxis].SetMockDataAsDiff();
1343 fAbsPos[kYAxis].LoadMockDataParameters(paramfile);
1344 }
1345 else if (value=="xslope") {
1346 fSlope[kXAxis].SetMockDataAsDiff();
1347 fSlope[kXAxis].LoadMockDataParameters(paramfile);
1348 }
1349 else if (value=="yslope") {
1350 fSlope[kYAxis].SetMockDataAsDiff();
1351 fSlope[kYAxis].LoadMockDataParameters(paramfile);
1352 }
1353/*
1354 for(size_t i=kXAxis;i<kNumAxes;i++){
1355 //std::cout << "In QwCombinedBPM: ChannelName = " << GetElementName() << std::endl;
1356 fAbsPos[i].SetMockDataAsDiff();
1357 fAbsPos[i].LoadMockDataParameters(paramfile);
1358 }
1359 for(size_t i=kXAxis;i<kNumAxes;i++){
1360 //std::cout << "In QwCombinedBPM: ChannelName = " << GetElementName() << std::endl;
1361 fSlope[i].SetMockDataAsDiff();
1362 fSlope[i].LoadMockDataParameters(paramfile);
1363 }
1364*/
1365// and so on....
1366/*
1367 meanX = paramfile.GetTypedNextToken<Double_t>();
1368 sigmaX = paramfile.GetTypedNextToken<Double_t>();
1369 meanY = paramfile.GetTypedNextToken<Double_t>();
1370 sigmaY = paramfile.GetTypedNextToken<Double_t>();
1371 meanXslope = paramfile.GetTypedNextToken<Double_t>();
1372 sigmaXslope = paramfile.GetTypedNextToken<Double_t>();
1373 meanYslope = paramfile.GetTypedNextToken<Double_t>();
1374 sigmaYslope = paramfile.GetTypedNextToken<Double_t>();
1375
1376 if (ldebug==1) {
1377 std::cout << "#################### \n";
1378 std::cout << "meanX, sigmaX, meanY, sigmaY, meanXslope, sigmaXslope, meanYslope, sigmaYslope \n" << std::endl;
1379 std::cout << meanX << " / "
1380 << sigmaX << " / "
1381 << meanY << " / "
1382 << sigmaY << " / "
1383 << meanXslope << " / "
1384 << sigmaXslope << " / "
1385 << meanYslope << " / "
1386 << sigmaYslope << " / "
1387 << std::endl;
1388 }
1389 this->SetRandomEventParameters(meanX, sigmaX, meanY, sigmaY, meanXslope, sigmaXslope, meanYslope, sigmaYslope);
1390*/
1391 }
1392}
1393
1394
1395template<typename T>
1396void QwCombinedBPM<T>::SetRandomEventParameters(Double_t meanX, Double_t sigmaX, Double_t meanY, Double_t sigmaY,
1397 Double_t meanXslope, Double_t sigmaXslope, Double_t meanYslope, Double_t sigmaYslope)
1398{
1399/*
1400 fAbsPos[kXAxis].SetMockDataAsDiff();
1401 fAbsPos[kYAxis].SetMockDataAsDiff();
1402 fSlope[kXAxis].SetMockDataAsDiff();
1403 fSlope[kYAxis].SetMockDataAsDiff();
1404*/
1405 fAbsPos[kXAxis].SetRandomEventParameters(meanX, sigmaX);
1406 fAbsPos[kYAxis].SetRandomEventParameters(meanY, sigmaY);
1407 fSlope[kXAxis].SetRandomEventParameters(meanXslope, sigmaXslope);
1408 fSlope[kYAxis].SetRandomEventParameters(meanYslope, sigmaYslope);
1409
1410 return;
1411}
1412
1413//-----------------------------------------------------------------------
1414
1415
1416#ifdef __USE_DATABASE__
1417template<typename T>
1418std::vector<QwDBInterface> QwCombinedBPM<T>::GetDBEntry()
1419{
1420 std::vector <QwDBInterface> row_list;
1421 row_list.clear();
1422 for(size_t axis=kXAxis;axis<kNumAxes;axis++) {
1423 fAbsPos[axis].AddEntriesToList(row_list);
1424 fSlope[axis].AddEntriesToList(row_list);
1425 fIntercept[axis].AddEntriesToList(row_list);
1426 fMinimumChiSquare[axis].AddEntriesToList(row_list);
1427 }
1428 fEffectiveCharge.AddEntriesToList(row_list);
1429 return row_list;
1430}
1431
1432
1433
1434template<typename T>
1435std::vector<QwErrDBInterface> QwCombinedBPM<T>::GetErrDBEntry()
1436{
1437 std::vector <QwErrDBInterface> row_list;
1438 row_list.clear();
1439 for(size_t axis=kXAxis;axis<kNumAxes;axis++) {
1440 fAbsPos[axis].AddErrEntriesToList(row_list);
1441 fSlope[axis].AddErrEntriesToList(row_list);
1442 fIntercept[axis].AddErrEntriesToList(row_list);
1443 fMinimumChiSquare[axis].AddErrEntriesToList(row_list);
1444 }
1445 // fEffectiveCharge.AddErrEntriesToList(row_list);
1446 return row_list;
1447}
1448
1449
1450
1451
1452
1453#endif // __USE_DATABASE__
1454
1455template class QwCombinedBPM<QwVQWK_Channel>;
1456template class QwCombinedBPM<QwSIS3801_Channel>;
Base and derived classes for scaler channel data handling.
#define QwWarning
Predefined log drain for warnings.
Definition QwLog.h:44
#define QwMessage
Predefined log drain for regular messages.
Definition QwLog.h:49
Parameter file parsing and management.
Decoding and management for Moller ADC channels (6x32-bit datawords)
Decoding and management for VQWK ADC channels (6x32-bit datawords)
Database interface for QwIntegrationPMT and subsystems.
Combined beam position monitor using weighted average.
static std::ostream & endl(std::ostream &)
End of the line.
Definition QwLog.cc:297
Configuration file parser with flexible tokenization and search capabilities.
T GetTypedNextToken()
Get next token into specific type.
Bool_t HasValue(TString &vname)
std::string GetLine()
std::string GetNextToken(const std::string &separatorchars)
Get next token as a string.
A helper class to manage a vector of branch entries for ROOT trees.
Definition QwRootFile.h:53
VQwDataElement()
Default constructor.
virtual const TString & GetElementName() const
Get the name of this element.
Abstract base for concrete hardware channels implementing dual-operator pattern.
Template for combined beam position monitor using multiple BPMs.
void GetProjectedPosition(VQwBPM *device) override
void Scale(Double_t factor) override
void FillTreeVector(QwRootTreeBranchVector &values) const override
std::vector< Double_t > fQWeights
VQwBPM & operator-=(const VQwBPM &value) override
Bool_t ApplyHWChecks()
Int_t ProcessEvBuffer(UInt_t *buffer, UInt_t word_position_in_buffer, UInt_t indexnumber) override
Process the CODA event buffer for this element.
void DeaccumulateRunningSum(VQwBPM &value, Int_t ErrorMask=0xFFFFFFF) override
EBeamPositionMonitorAxis
Definition VQwBPM.h:72
void RandomizeEventData(int helicity=0, double time=0.0) override
Double_t D[2]
VQwHardwareChannel * GetSubelementByName(TString ch_name) override
void LoadMockDataParameters(QwParameterFile &paramfile) override
UInt_t UpdateErrorFlag() override
Update the error flag based on the error flags of internally contained objects Return parameter is th...
Double_t erra[2]
std::array< T, 2 > fSlope
Double_t SumOver(std::vector< Double_t > weight, std::vector< T > val)
std::vector< T > fBPMComboElementList
Double_t A[2]
std::vector< Double_t > fYWeights
void InitializeChannel(TString name)
void ConstructHistograms(TDirectory *folder, TString &prefix) override
Construct the histograms for this data element.
Double_t fSumQweights
Double_t m[2]
void ConstructBranchAndVector(TTree *tree, TString &prefix, QwRootTreeBranchVector &values) override
std::array< T, 2 > fIntercept
void LeastSquareFit(VQwBPM::EBeamPositionMonitorAxis axis, std::vector< Double_t > fWeights)
void Ratio(QwCombinedBPM &numer, QwCombinedBPM &denom)
std::array< T, 2 > fAbsPos
void IncrementErrorCounters() override
Bool_t CheckForBurpFail(const VQwDataElement *ev_error)
void PrintValue() const override
Print single line of value and error of this data element.
void ClearEventData() override
void ProcessEvent() override
Bool_t ApplySingleEventCuts() override
Double_t errb[2]
void CalculateFixedParameter(std::vector< Double_t > fWeights, Int_t pos)
std::array< T, 2 > fMinimumChiSquare
void FillHistograms() override
Fill the histograms for this data element.
void SetEventCutMode(Int_t bcuts) override
Inherited from VQwDataElement to set the upper and lower limits (fULimit and fLLimit),...
std::vector< Double_t > fXWeights
VQwBPM & operator+=(const VQwBPM &value) override
Bool_t fixedParamCalculated
void ConstructBranch(TTree *tree, TString &prefix) override
const VQwHardwareChannel * GetEffectiveCharge() const override
Double_t covab[2]
void AccumulateRunningSum(const VQwBPM &value, Int_t count=0, Int_t ErrorMask=0xFFFFFFF) override
void SetRandomEventParameters(Double_t meanX, Double_t sigmaX, Double_t meanY, Double_t sigmaY, Double_t meanXslope, Double_t sigmaXslope, Double_t meanYslope, Double_t sigmaYslope) override
UInt_t GetEventcutErrorFlag() override
VQwBPM & operator=(const VQwBPM &value) override
void SetBPMForCombo(const VQwBPM *bpm, Double_t charge_weight, Double_t x_weight, Double_t y_weight, Double_t sumqw) override
void PrintErrorCounters() const override
std::vector< const VQwBPM * > fElement
const VQwHardwareChannel * GetPosition(EBeamPositionMonitorAxis axis) const override
Double_t B[2]
void PrintInfo() const override
Print multiple lines of information about this data element.
void CalculateRunningAverage() override
virtual void ApplyResolutionSmearing()
Definition VQwBPM.h:273
EBeamPositionMonitorAxis
Definition VQwBPM.h:72
@ kXAxis
Definition VQwBPM.h:72
@ kYAxis
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
virtual void SetResolution(Double_t resolutionX, Double_t resolutionY)
Definition VQwBPM.h:256
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
virtual void FillRawEventData()
Definition VQwBPM.h:98
static const TString axis[3]
Definition VQwBPM.h:333
virtual VQwBPM & operator=(const VQwBPM &value)=0
Definition VQwBPM.cc:156
virtual const VQwHardwareChannel * GetPosition(EBeamPositionMonitorAxis axis) const
Definition VQwBPM.h:140
VQwBPM()
Definition VQwBPM.h:76
Double_t GetPositionInZ() const
Definition VQwBPM.h:171