JAPAn
Just Another Parity Analyzer
Loading...
Searching...
No Matches
QwBPMCavity.cc
Go to the documentation of this file.
1/*!
2 * \file QwBPMCavity.cc
3 * \brief Cavity beam position monitor implementation
4 *
5 * Implementation of the cavity-style BPM (beam position monitor) wrapper.
6 * This class owns three hardware channels (XI, YI, Q) and derives relative
7 * and absolute positions from them. It also wires histogram/tree outputs,
8 * applies hardware checks and single-event cuts, and participates in running
9 * sum/average calculations. No physics behavior is changed by this file's
10 * documentation-only edits.
11 */
12
13#include "QwBPMCavity.h"
14
15// System headers
16#include <stdexcept>
17
18// ROOT headers for RNTuple support
19#ifdef HAS_RNTUPLE_SUPPORT
20#include <ROOT/RNTupleModel.hxx>
21#include <ROOT/RNTupleWriter.hxx>
22#endif // HAS_RNTUPLE_SUPPORT
23
24// Qweak headers
25#ifdef __USE_DATABASE__
26#include "QwDBInterface.h"
27#endif // __USE_DATABASE__
28
29/* Position calibration factor, transform ADC counts in mm*/
30const Double_t QwBPMCavity::kQwCavityCalibration = 1.0;
31//The value of kQwCavityCalibration is made up so we have to replace it with an actual value when it is determined
32//Josh Kaisen
33
34const TString QwBPMCavity::subelement[QwBPMCavity::kNumElements]={"XI","YI","Q"};
35
36
37/**
38 * Decode a fully qualified channel name into detector and subelement parts.
39 *
40 * @param channel Full channel name (e.g. "bpm3iXI").
41 * @param detname Out-parameter set to the detector base name.
42 * @param subname Out-parameter set to the recognized subelement tag.
43 * @param localindex Out-parameter set to the subelement enum index or
44 * kInvalidSubelementIndex on failure.
45 * @return true if a valid subelement suffix is recognized; false otherwise.
46 */
47Bool_t QwBPMCavity::ParseChannelName(const TString &channel,
48 TString &detname,
49 TString &subname,
50 UInt_t &localindex)
51{
52 localindex=kInvalidSubelementIndex;
53 //QwMessage << "Channel Name: " << channel << QwLog::endl;
54 for(size_t i=0;i<kNumElements;i++){
55 if(channel.EndsWith(subelement[i],TString::kIgnoreCase)){
56 localindex=i;
57 subname = subelement[i];
58 size_t detnamesize = channel.Sizeof() - subname.Sizeof();
59 detname = channel(0,detnamesize);
60 break;
61 }
62 }
63
64 //QwMessage << "Detector Name: " << detname << QwLog::endl;
65 //QwMessage << "Sub Name: " << subname << QwLog::endl;
66
67 if(localindex==kInvalidSubelementIndex){
68 detname = "";
69 subname = "";
70 QwWarning << "QwBPMCavity::GetSubElementIndex is unable to associate the string -"
71 <<subname<<"- to any index" << QwLog::endl;
72 }
73 return (localindex!=kInvalidSubelementIndex);
74}
75
76
77/**
78 * Initialize channels and derived quantities using a simple name.
79 * Creates three raw hardware channels (XI, YI, Q) and two derived channels
80 * for relative and absolute positions along each transverse axis.
81 *
82 * @param name Detector base name.
83 */
85{
86 size_t i=0;
87 Bool_t localdebug = kFALSE;
88
90
91 for(i=0;i<kNumElements;i++) {
92 fElement[i].InitializeChannel(name+subelement[i],"raw");
93 if(localdebug)
94 std::cout<<" Wire ["<<i<<"]="<<fElement[i].GetElementName()<<"\n";
95 }
96
97 for(i=kXAxis;i<kNumAxes;i++){
98 fRelPos[i].InitializeChannel(name+"Rel"+subelement[i],"derived");
99 fAbsPos[i].InitializeChannel(name+kAxisLabel[i],"derived");
100 }
101
102 bFullSave=kTRUE;
103
104 return;
105}
106
107/**
108 * Initialize channels with explicit subsystem and detector name.
109 * This variant forwards subsystem information down to subelements so that
110 * output branches and histograms carry proper scoping.
111 *
112 * @param subsystem Subsystem name.
113 * @param name Detector base name.
114 */
115void QwBPMCavity::InitializeChannel(TString subsystem, TString name)
116{
117 size_t i=0;
118 Bool_t localdebug = kFALSE;
119
121
122 for(i=0;i<kNumElements;i++) {
123 fElement[i].InitializeChannel(subsystem, "QwBPMCavity", name+subelement[i],"raw");
124 if(localdebug)
125 std::cout<<" Wire ["<<i<<"]="<<fElement[i].GetElementName()<<"\n";
126 }
127
128 for(i=kXAxis;i<kNumAxes;i++){
129 fRelPos[i].InitializeChannel(subsystem, "QwBPMCavity", name+"Rel"+subelement[i],"derived");
130 fAbsPos[i].InitializeChannel(subsystem, "QwBPMCavity", name+kAxisLabel[i],"derived");
131 }
132
133 bFullSave=kTRUE;
134
135 return;
136}
137
138/** Clear all owned subelement and derived channel state for the current event. */
140{
141 size_t i=0;
142
143 for(i=0;i<kNumElements;i++){
144 fElement[i].ClearEventData();
145 }
146 for(i=0;i<kNumAxes;i++){
147 fAbsPos[i].ClearEventData();
148 fRelPos[i].ClearEventData();
149 }
150}
151
152
153/**
154 * Apply hardware-level checks to each subelement and aggregate status.
155 *
156 * @return true if no hardware errors are detected across all subelements.
157 */
159{
160 Bool_t eventokay=kTRUE;
161
162 UInt_t deviceerror=0;
163 for(size_t i=0;i<kNumElements;i++)
164 {
165 deviceerror|= fElement[i].ApplyHWChecks(); //OR the error code from each wire
166 eventokay &= (deviceerror & 0x0);//AND with 0 since zero means HW is good.
167
168 if (bDEBUG) std::cout<<" Inconsistent within BPM terminals wire[ "<<i<<" ] "<<std::endl;
169 if (bDEBUG) std::cout<<" wire[ "<<i<<" ] sequence num "<<fElement[i].GetSequenceNumber()<<" sample size "<<fElement[i].GetNumberOfSamples()<<std::endl;
170 }
171 return eventokay;
172}
173
174/** Increment persistent error counters across subelements and derived channels. */
176{
177 size_t i=0;
178
179 for(i=0;i<kNumElements;i++){
180 fElement[i].IncrementErrorCounters();
181 }
182 for(i=0;i<kNumAxes;i++){
183 fRelPos[i].IncrementErrorCounters();
184 fAbsPos[i].IncrementErrorCounters();
185 }
186}
187
188/** Print persistent error counter summaries for diagnostics. */
190{
191 size_t i=0;
192 for(i=0;i<kNumElements;i++) {
193 fElement[i].PrintErrorCounters();
194 }
195 for(i=0;i<kNumAxes;i++){
196 // fRelPos[i].PrintErrorCounters();
197 fAbsPos[i].PrintErrorCounters();
198 }
199}
200
201/**
202 * Return the OR of per-channel event-cut error flags for this detector.
203 * This includes raw elements, relative and absolute positions.
204 */
206{
207 size_t i=0;
208 UInt_t error=0;
209 for(i=0;i<kNumElements;i++) {
210 error|=fElement[i].GetEventcutErrorFlag();
211 }
212 for(i=0;i<kNumAxes;i++){
213 error|=fRelPos[i].GetEventcutErrorFlag();
214 error|=fAbsPos[i].GetEventcutErrorFlag();
215 }
216 return error;
217}
218
219/**
220 * Update derived channel error flags based on raw element error codes and
221 * return the aggregated event-cut error mask.
222 */
224{
225 size_t i=0;
226 UInt_t error1=0;
227 UInt_t error2=0;
228 for(i=0;i<kNumElements;i++) {
229 error1|=fElement[i].GetErrorCode();
230 error2|=fElement[i].GetEventcutErrorFlag();
231 }
232 for(i=kXAxis;i<kNumAxes;i++) {
233 fRelPos[i].UpdateErrorFlag(error1);
234 fAbsPos[i].UpdateErrorFlag(error1);
235 error2|=fRelPos[i].GetEventcutErrorFlag();
236 error2|=fAbsPos[i].GetEventcutErrorFlag();
237 }
238 return error2;
239}
240
241/**
242 * Apply analysis-level single-event cuts to raw and derived quantities.
243 *
244 * @return true if all configured channels pass their single-event cuts.
245 */
247{
248 Bool_t status=kTRUE;
249 Int_t i=0;
250 UInt_t error_code = 0;
251 //Event cuts for elements
252 for(i=0;i<kNumElements;i++){
254 status&=kTRUE;
255 }
256 else{
257 status&=kFALSE;
258 if (bDEBUG) std::cout<<" Element "<< fElement[i].GetElementName()
259 << " event cut failed ";
260 }
261 error_code |= fElement[i].GetErrorCode();
262 }
263 for(i=kXAxis;i<kNumAxes;i++){
264 fRelPos[i].UpdateErrorFlag(error_code);
265 if (fRelPos[i].ApplySingleEventCuts()){ //for RelX
266 status&=kTRUE;
267 }
268 else{
269 status&=kFALSE;
270 if (bDEBUG) std::cout<<" Rel X event cut failed ";
271 }
272 }
273
274 for(i=kXAxis;i<kNumAxes;i++){
275 fAbsPos[i].UpdateErrorFlag(error_code);
276 if (fAbsPos[i].ApplySingleEventCuts()){ //for RelX
277 status&=kTRUE;
278 }
279 else{
280 status&=kFALSE;
281 if (bDEBUG) std::cout<<" Abs X event cut failed ";
282 }
283 }
284 return status;
285}
286
287/**
288 * Map a human-readable subelement name to the corresponding channel.
289 * Valid names include: relx, rely, absx/x, absy/y, effectivecharge/charge/q,
290 * as well as xi/yi to access raw elements.
291 *
292 * @throws std::invalid_argument on an unrecognized subelement request.
293 */
295{
296 VQwHardwareChannel* tmpptr = NULL;
297 ch_name.ToLower();
298 if (ch_name=="relx"){
299 tmpptr = &fRelPos[0];
300 }else if (ch_name=="rely"){
301 tmpptr = &fRelPos[1];
302 }else if (ch_name=="absx" || ch_name=="x" ){
303 tmpptr = &fAbsPos[0];
304 }else if (ch_name=="absy" || ch_name=="y"){
305 tmpptr = &fAbsPos[1];
306 }else if (ch_name=="effectivecharge" || ch_name=="charge" || ch_name=="q"){
307 tmpptr = &fElement[kQElem];
308 } else {
309 TString loc="QwLinearDiodeArray::GetSubelementByName for"
310 + this->GetElementName() + " was passed "
311 + ch_name + ", which is an unrecognized subelement name.";
312 throw std::invalid_argument(loc.Data());
313 }
314 return tmpptr;
315}
316
317
318/*
319void QwBPMCavity::SetSingleEventCuts(TString ch_name, Double_t minX, Double_t maxX)
320{
321
322 if (ch_name=="relx"){
323 QwMessage<<"RelX LL " << minX <<" UL " << maxX <<QwLog::endl;
324 fRelPos[0].SetSingleEventCuts(minX,maxX);
325
326 }else if (ch_name=="rely"){
327 QwMessage<<"RelY LL " << minX <<" UL " << maxX <<QwLog::endl;
328 fRelPos[1].SetSingleEventCuts(minX,maxX);
329
330 } else if (ch_name=="absx"){
331 QwMessage<<"AbsX LL " << minX <<" UL " << maxX <<QwLog::endl;
332 fAbsPos[0].SetSingleEventCuts(minX,maxX);
333
334 }else if (ch_name=="absy"){
335 QwMessage<<"AbsY LL " << minX <<" UL " << maxX <<QwLog::endl;
336 fAbsPos[1].SetSingleEventCuts(minX,maxX);
337
338 }else if (ch_name=="effectivecharge"){
339 QwMessage<<"EffectveQ LL " << minX <<" UL " << maxX <<QwLog::endl;
340 fElement[kQElem].SetSingleEventCuts(minX,maxX);
341
342 }
343
344}*/
345
346/**
347 * Configure single-event cuts for one subelement by name.
348 *
349 * @param ch_name Subchannel selector (e.g. relx, rely, absx, absy, effectivecharge, xi, yi).
350 * @param errorflag Error mask bit(s) to associate with failures.
351 * @param minX Lower limit for the channel value.
352 * @param maxX Upper limit for the channel value.
353 * @param stability Allowed fractional stability (implementation-specific).
354 * @param burplevel Threshold for burp/burst detection (implementation-specific).
355 */
356void QwBPMCavity::SetSingleEventCuts(TString ch_name, UInt_t errorflag,Double_t minX, Double_t maxX, Double_t stability, Double_t burplevel){
357 errorflag|=kBPMErrorFlag;//update the device flag
358 if (ch_name=="relx"){
359 QwMessage<<"RelX LL " << minX <<" UL " << maxX <<QwLog::endl;
360 fRelPos[0].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
361
362 }else if (ch_name=="rely"){
363 QwMessage<<"RelY LL " << minX <<" UL " << maxX <<QwLog::endl;
364 fRelPos[1].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
365
366 } else if (ch_name=="absx"){
367 QwMessage<<"AbsX LL " << minX <<" UL " << maxX <<QwLog::endl;
368 fAbsPos[0].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
369
370 }else if (ch_name=="absy"){
371 QwMessage<<"AbsY LL " << minX <<" UL " << maxX <<QwLog::endl;
372 fAbsPos[1].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
373
374 }else if (ch_name=="effectivecharge"){
375 QwMessage<<"EffectveQ LL " << minX <<" UL " << maxX <<QwLog::endl;
376 fElement[kQElem].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
377
378 }else if (ch_name=="xi"){
379 QwMessage<<"XI " << minX <<" UL " << maxX <<QwLog::endl;
380 fElement[0].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
381
382 }else if (ch_name=="yi"){
383 QwMessage<<"YI " << minX <<" UL " << maxX <<QwLog::endl;
384 fElement[1].SetSingleEventCuts(errorflag,minX,maxX,stability,burplevel);
385
386 }
387
388}
389
390/**
391 * Polymorphic burp/burst failure check against a reference element of the
392 * same concrete type. For each subelement and derived channel, delegate to
393 * its CheckForBurpFail implementation.
394 *
395 * @param ev_error Reference data element to compare against.
396 * @return true if any sub-channel reports a burp/burst failure.
397 * @throws std::invalid_argument if ev_error is not a QwBPMCavity.
398 */
400 Short_t i=0;
401 Bool_t burpstatus = kFALSE;
402 try {
403 if(typeid(*ev_error)==typeid(*this)) {
404 //std::cout<<" Here in QwBPMCavity::CheckForBurpFail \n";
405 if (this->GetElementName()!="") {
406 const QwBPMCavity* value_bpm = dynamic_cast<const QwBPMCavity* >(ev_error);
407 for(i=0;i<2;i++){
408 burpstatus |= fElement[i].CheckForBurpFail(&(value_bpm->fElement[i]));
409 burpstatus |= fRelPos[i].CheckForBurpFail(&(value_bpm->fRelPos[i]));
410 burpstatus |= fAbsPos[i].CheckForBurpFail(&(value_bpm->fAbsPos[i]));
411 }
412 burpstatus |= fElement[kQElem].CheckForBurpFail(&(value_bpm->fElement[kQElem]));
413 }
414 } else {
415 TString loc="Standard exception from QwBPMCavity::CheckForBurpFail :"+
416 ev_error->GetElementName()+" "+this->GetElementName()+" are not of the "
417 +"same type";
418 throw std::invalid_argument(loc.Data());
419 }
420 } catch (std::exception& e) {
421 std::cerr<< e.what()<<std::endl;
422 }
423 return burpstatus;
424}
425
426/**
427 * Update error flags by copying flags from a reference BPM of the same
428 * concrete type. This is used to propagate error state across containers.
429 *
430 * @param ev_error Reference BPM (must be QwBPMCavity).
431 * @throws std::invalid_argument if ev_error is not a QwBPMCavity.
432 */
434 size_t i=0;
435 try {
436 if(typeid(*ev_error)==typeid(*this)) {
437 // std::cout<<" Here in QwBPMStripline::UpdateErrorFlag \n";
438 if (this->GetElementName()!="") {
439 const QwBPMCavity* value_bpm = dynamic_cast<const QwBPMCavity* >(ev_error);
440 for(i=0;i<kNumElements;i++){
441 fElement[i].UpdateErrorFlag(value_bpm->fElement[i]);
442 }
443 for(i=kXAxis;i<kNumAxes;i++) {
444 fRelPos[i].UpdateErrorFlag(value_bpm->fRelPos[i]);
445 fAbsPos[i].UpdateErrorFlag(value_bpm->fAbsPos[i]);
446 }
447 }
448 } else {
449 TString loc="Standard exception from QwBPMCavity::UpdateErrorFlag :"+
450 ev_error->GetElementName()+" "+this->GetElementName()+" are not of the "
451 +"same type";
452 throw std::invalid_argument(loc.Data());
453 }
454 } catch (std::exception& e) {
455 std::cerr<< e.what()<<std::endl;
456 }
457};
458
459
460
461/**
462 * Process the current event by first applying hardware checks and then
463 * computing relative and absolute positions from raw subelements.
464 */
466{
467 size_t i = 0;
468
470 /**First apply HW checks and update HW error flags.
471 Calling this routine here and not in ApplySingleEventCuts
472 makes a difference for a BPMs because they have derived devices.
473 */
474 for(i=0;i<kNumElements;i++) {
475 fElement[i].ProcessEvent();
476 }
477
478 for(i=kXAxis;i<kNumAxes;i++){
479 fRelPos[i].Ratio(fElement[i],fElement[kQElem]);
481 fAbsPos[i]= fRelPos[i];
482 fAbsPos[i].AddChannelOffset(fPositionCenter[i]);
483 }
484
485 return;
486}
487
488
489/**
490 * Decode and route a raw data buffer into the requested subelement.
491 *
492 * @param buffer CODA/raw buffer pointer.
493 * @param word_position_in_buffer Starting word index to parse.
494 * @param index Target subelement index (0..kNumElements-1).
495 * @return The original word_position_in_buffer (legacy behavior).
496 */
497Int_t QwBPMCavity::ProcessEvBuffer(UInt_t* buffer, UInt_t word_position_in_buffer,UInt_t index)
498{
499 if(index<kNumElements) {
500 fElement[index].ProcessEvBuffer(buffer,word_position_in_buffer);
501 }
502 else {
503 std::cerr <<
504 "QwBPMCavity::ProcessEvBuffer(): attempt to fill in raw date for a wire that doesn't exist \n";
505 }
506 return word_position_in_buffer;
507}
508
509
510
511/** Print the current values of raw and absolute position channels. */
513{
514 for (size_t i = 0; i < kNumElements; i++) {
515 fElement[i].PrintValue();
516 }
517 for (size_t i=0;i<kNumAxes;i++){
518 // fRelPos[i].PrintValue();
519 fAbsPos[i].PrintValue();
520 }
521}
522
523/** Print a description of the raw and absolute position channels. */
525{
526 size_t i = 0;
527 for (i = 0; i < kNumElements; i++) {
528 fElement[i].PrintInfo();
529 }
530 for(i=0;i<kNumAxes;i++){
531 // fRelPos[i].PrintInfo();
532 fAbsPos[i].PrintInfo();
533 }
534}
535
536
537/**
538 * Return the element name for a given raw subelement index.
539 *
540 * @param subindex Index into the raw elements array.
541 * @return Element name; logs an error and returns empty on invalid index.
542 */
543TString QwBPMCavity::GetSubElementName(Int_t subindex)
544{
545 TString thisname;
546 if(subindex<kNumElements&&subindex>-1)
547 thisname=fElement[subindex].GetElementName();
548 else
549 std::cerr<<"QwBPMCavity::GetSubElementName for "<<
550 GetElementName()<<" this subindex doesn't exists \n";
551 return thisname;
552}
553
554/** Convert a subelement tag (XI, YI, Q) into an enum index. */
555UInt_t QwBPMCavity::GetSubElementIndex(TString subname)
556{
557 subname.ToUpper();
558 UInt_t localindex=kInvalidSubelementIndex;
559 for(size_t i=0;i<kNumElements;i++)
560 if(subname==subelement[i])localindex=i;
561
562 if(localindex==kInvalidSubelementIndex)
563 std::cerr << "QwBPMCavity::GetSubElementIndex is unable to associate the string -"
564 <<subname<<"- to any index"<<std::endl;
565
566 return localindex;
567}
568
569/**
570 * Recompute absolute positions from raw elements and stored offsets.
571 * Intended for use after externally setting raw subelements.
572 */
574{
575 for(size_t i=0;i<kNumAxes;i++){
576 fRelPos[i].Ratio(fElement[i],fElement[kQElem]);
577 fAbsPos[i]= fRelPos[i];
578 fAbsPos[i].AddChannelOffset(fPositionCenter[i]);
579 }
580 // For Z, the absolute position will be the offset we are reading from the
581 // geometry map file. Since we are not putting that to the tree it is not
582 // treated as a vqwk channel.
583}
584
585
586/** Type-erased assignment; forwards to the concrete operator=. */
588{
589 *(dynamic_cast<QwBPMCavity*>(this)) =
590 *(dynamic_cast<const QwBPMCavity*>(&value));
591 return *this;
592}
593
594/** Concrete assignment; copies raw elements and derived channels. */
596{
597 VQwBPM::operator= (value);
598
599 if (GetElementName()!=""){
600 size_t i = 0;
601 for(i=0;i<kNumElements;i++) {
602 this->fElement[i]=value.fElement[i];
603 }
604 for(i=0;i<kNumAxes;i++){
605 this->fRelPos[i]=value.fRelPos[i];
606 this->fAbsPos[i]=value.fAbsPos[i];
607 }
608 }
609 return *this;
610}
611
612
613/** Element-wise addition of raw and derived channels. */
615{
616
617 if (GetElementName()!=""){
618 size_t i = 0;
619 for(i=0;i<kNumElements;i++) {
620 this->fElement[i]+=value.fElement[i];
621 }
622 for(i=0;i<kNumAxes;i++){
623 this->fRelPos[i]+=value.fRelPos[i];
624 this->fAbsPos[i]+=value.fAbsPos[i];
625 }
626 }
627 return *this;
628}
629
630/** Type-erased addition; forwards to the concrete operator+=. */
632{
633 *(dynamic_cast<QwBPMCavity*>(this)) +=
634 *(dynamic_cast<const QwBPMCavity*>(&value));
635 return *this;
636}
637
638
639
640/** Element-wise subtraction of raw and derived channels. */
642{
643
644 if (GetElementName()!=""){
645 size_t i = 0;
646 for(i=0;i<kNumElements;i++) {
647 this->fElement[i]-=value.fElement[i];
648 }
649 for(i=0;i<kNumAxes;i++){
650 this->fRelPos[i]-=value.fRelPos[i];
651 this->fAbsPos[i]-=value.fAbsPos[i];
652 }
653 }
654 return *this;
655}
656
657/** Type-erased subtraction; forwards to the concrete operator-=. */
659{
660 *(dynamic_cast<QwBPMCavity*>(this)) -=
661 *(dynamic_cast<const QwBPMCavity*>(&value));
662 return *this;
663}
664
665
666
667/**
668 * Special ratio behavior for cavity BPMs when forming asymmetries.
669 * Only the effective charge channel participates; transverse positions are
670 * kept as differences (consistent with stripline BPM behavior).
671 */
673{
674 // this function is called when forming asymmetries. In this case what we actually want for the
675 // stripline is the difference only not the asymmetries
676
677 *this=numer;
678 this->fElement[kQElem].Ratio(numer.fElement[kQElem],denom.fElement[kQElem]);
679 return;
680}
681
682
683
684/** Scale all raw and derived channels by a common factor. */
685void QwBPMCavity::Scale(Double_t factor)
686{
687 for(size_t i=0;i<kNumElements;i++){
688 fElement[i].Scale(factor);
689 }
690 for(size_t i=0;i<kNumAxes;i++){
691 fRelPos[i].Scale(factor);
692 fAbsPos[i].Scale(factor);
693 }
694 return;
695}
696
697
698/** Update per-channel running averages based on accumulated sums. */
700{
701 size_t i = 0;
702 for(i=0;i<kNumElements;i++)
704 for (i = 0; i < kNumAxes; i++){
705 fRelPos[i].CalculateRunningAverage();
706 fAbsPos[i].CalculateRunningAverage();
707 }
708 return;
709}
710
711/** Type-erased running-sum accumulate; forwards to concrete overload. */
712void QwBPMCavity::AccumulateRunningSum(const VQwBPM &value, Int_t count, Int_t ErrorMask){
713 AccumulateRunningSum(*dynamic_cast<const QwBPMCavity* >(&value), count, ErrorMask);
714};
715
716/** Accumulate running sums for raw and derived channels. */
717void QwBPMCavity::AccumulateRunningSum(const QwBPMCavity& value, Int_t count, Int_t ErrorMask)
718{
719
720 size_t i = 0;
721 for(i=0;i<kNumElements;i++)
722 fElement[i].AccumulateRunningSum(value.fElement[i], count, ErrorMask);
723 for (i = 0; i < 2; i++){
724 fRelPos[i].AccumulateRunningSum(value.fRelPos[i], count, ErrorMask);
725 fAbsPos[i].AccumulateRunningSum(value.fAbsPos[i], count, ErrorMask);
726 }
727 return;
728}
729
730/** Type-erased running-sum deaccumulate; forwards to concrete overload. */
731void QwBPMCavity::DeaccumulateRunningSum(VQwBPM &value, Int_t ErrorMask){
732 DeaccumulateRunningSum(*dynamic_cast<QwBPMCavity* >(&value), ErrorMask);
733};
734
735/** Deaccumulate running sums for raw and derived channels. */
737{
738 size_t i = 0;
739 for(i=0;i<kNumElements;i++)
740 fElement[i].DeaccumulateRunningSum(value.fElement[i], ErrorMask);
741 for (i = 0; i < kNumAxes; i++){
742 fRelPos[i].DeaccumulateRunningSum(value.fRelPos[i], ErrorMask);
743 fAbsPos[i].DeaccumulateRunningSum(value.fAbsPos[i], ErrorMask);
744 }
745 return;
746}
747
748
749
750
751/**
752 * Define ROOT histograms for subelements and derived absolute positions.
753 * The prefix "asym_" is converted to "diff_" for positions.
754 */
755void QwBPMCavity::ConstructHistograms(TDirectory *folder, TString &prefix)
756{
757
758 if (GetElementName()=="") {
759 // This channel is not used, so skip filling the histograms.
760 } else {
761 fElement[kQElem].ConstructHistograms(folder, prefix);
762 TString thisprefix=prefix;
763
764 if(prefix.Contains("asym_"))
765 thisprefix.ReplaceAll("asym_","diff_");
766 SetRootSaveStatus(prefix);
767 size_t i = 0;
768 for(i=kXAxis;i<kNumAxes;i++) {
769 if(bFullSave) fElement[i].ConstructHistograms(folder, thisprefix);
770 // fRelPos[i].ConstructHistograms(folder, thisprefix);
771 fAbsPos[i].ConstructHistograms(folder, thisprefix);
772 }
773 }
774 return;
775}
776
777/** Fill previously constructed ROOT histograms for this detector. */
779{
780 if (GetElementName()=="") {
781 // This channel is not used, so skip filling the histograms.
782 }
783 else {
784 fElement[kQElem].FillHistograms();
785 size_t i = 0;
786 for(i=kXAxis;i<kNumAxes;i++){
787 if (bFullSave) fElement[i].FillHistograms();
788 // fRelPos[i].FillHistograms();
789 fAbsPos[i].FillHistograms();
790 }
791 //No data for z position
792 }
793 return;
794}
795
796/**
797 * Define TTree branches and attach backing vectors for output variables.
798 * The prefix "asym_" is converted to "diff_" for positions.
799 */
800void QwBPMCavity::ConstructBranchAndVector(TTree *tree, TString &prefix, QwRootTreeBranchVector &values)
801{
802 if (GetElementName()==""){
803 // This channel is not used, so skip constructing trees.
804 }
805 else {
806 TString thisprefix=prefix;
807 if(prefix.Contains("asym_"))
808 thisprefix.ReplaceAll("asym_","diff_");
809 SetRootSaveStatus(prefix);
810
811 fElement[kQElem].ConstructBranchAndVector(tree,prefix,values);
812 size_t i = 0;
813 for(i=kXAxis;i<kNumAxes;i++) {
814 if (bFullSave) fElement[i].ConstructBranchAndVector(tree,thisprefix,values);
815 // fRelPos[i].ConstructBranchAndVector(tree,thisprefix,values);
816 fAbsPos[i].ConstructBranchAndVector(tree,thisprefix,values);
817 }
818
819 }
820 return;
821}
822
823 /**
824 * Define TTree branches for output variables using the provided prefix.
825 * The prefix "asym_" is converted to "diff_" for positions.
826 */
827 void QwBPMCavity::ConstructBranch(TTree *tree, TString &prefix)
828 {
829 if (GetElementName()==""){
830 // This channel is not used, so skip constructing trees.
831 }
832 else {
833 TString thisprefix=prefix;
834 if(prefix.Contains("asym_"))
835 thisprefix.ReplaceAll("asym_","diff_");
836 SetRootSaveStatus(prefix);
837
838 fElement[kQElem].ConstructBranch(tree,prefix);
839 size_t i = 0;
840 for(i=kXAxis;i<kNumAxes;i++) {
841 if (bFullSave) fElement[i].ConstructBranch(tree,thisprefix);
842 // fRelPos[i].ConstructBranch(tree,thisprefix);
843 fAbsPos[i].ConstructBranch(tree,thisprefix);
844 }
845
846 }
847 return;
848 }
849
850 /**
851 * Conditionally define TTree branches based on a module list filter.
852 * Only branches present in the module list are created.
853 */
854 void QwBPMCavity::ConstructBranch(TTree *tree, TString &prefix, QwParameterFile& modulelist)
855 {
856 TString devicename;
857 /*
858 QwMessage <<" QwBCM::ConstructBranch "<<QwLog::endl;
859 modulelist.RewindToFileStart();
860 while (modulelist.ReadNextLine()){
861 modulelist.TrimComment('!'); // Remove everything after a '!' character.
862 modulelist.TrimWhitespace(); // Get rid of leading and trailing spaces
863 QwMessage <<" "<<modulelist.GetLine()<<" ";
864 }
865 QwMessage <<QwLog::endl;
866 */
867 devicename=GetElementName();
868 devicename.ToLower();
869 if (GetElementName()==""){
870 // This channel is not used, so skip filling the histograms.
871 } else
872 {
873 if (modulelist.HasValue(devicename)){
874 TString thisprefix=prefix;
875 if(prefix.Contains("asym_"))
876 thisprefix.ReplaceAll("asym_","diff_");
877 SetRootSaveStatus(prefix);
878
879 fElement[kQElem].ConstructBranch(tree,prefix);
880 size_t i = 0;
881 for(i=kXAxis;i<kNumAxes;i++) {
882 if (bFullSave) fElement[i].ConstructBranch(tree,thisprefix);
883 // fRelPos[i].ConstructBranch(tree,thisprefix);
884 fAbsPos[i].ConstructBranch(tree,thisprefix);
885 }
886
887 QwMessage <<" Tree leaves added to "<<devicename<<" Corresponding channels"<<QwLog::endl;
888 }
889 // this functions doesn't do anything yet
890 }
891
892
893
894
895
896 return;
897 }
898
899
900/** Append this detector's values to the provided output vector. */
902{
903 if (GetElementName()=="") {
904 // This channel is not used, so skip filling the tree.
905 }
906 else {
907 fElement[kQElem].FillTreeVector(values);
908 size_t i = 0;
909 for(i=kXAxis;i<kNumAxes;i++){
910 if (bFullSave) fElement[i].FillTreeVector(values);
911 // fRelPos[i].FillTreeVector(values);
912 fAbsPos[i].FillTreeVector(values);
913 }
914 }
915 return;
916}
917
918#ifdef HAS_RNTUPLE_SUPPORT
919/**
920 * Define RNTuple fields and attach backing vectors for output variables.
921 * The prefix "asym_" is converted to "diff_" for positions.
922 */
923void QwBPMCavity::ConstructNTupleAndVector(std::unique_ptr<ROOT::RNTupleModel>& model, TString& prefix, std::vector<Double_t>& values, std::vector<std::shared_ptr<Double_t>>& fieldPtrs)
924{
925 if (GetElementName()==""){
926 // This channel is not used, so skip constructing.
927 }
928 else {
929 TString thisprefix=prefix;
930 if(prefix.Contains("asym_"))
931 thisprefix.ReplaceAll("asym_","diff_");
932 SetRootSaveStatus(prefix);
933
934 fElement[kQElem].ConstructNTupleAndVector(model,prefix,values,fieldPtrs);
935 size_t i = 0;
936 for(i=kXAxis;i<kNumAxes;i++) {
937 if (bFullSave) fElement[i].ConstructNTupleAndVector(model,thisprefix,values,fieldPtrs);
938 // fRelPos[i].ConstructNTupleAndVector(model,thisprefix,values,fieldPtrs);
939 fAbsPos[i].ConstructNTupleAndVector(model,thisprefix,values,fieldPtrs);
940 }
941
942 }
943 return;
944}
945
946/** Append this detector's values to the RNTuple output vector. */
947void QwBPMCavity::FillNTupleVector(std::vector<Double_t>& values) const
948{
949 if (GetElementName()=="") {
950 // This channel is not used, so skip filling.
951 }
952 else {
953 fElement[kQElem].FillNTupleVector(values);
954 size_t i = 0;
955 for(i=kXAxis;i<kNumAxes;i++){
956 if (bFullSave) fElement[i].FillNTupleVector(values);
957 // fRelPos[i].FillNTupleVector(values);
958 fAbsPos[i].FillNTupleVector(values);
959 }
960 }
961 return;
962}
963#endif
964
965/** Propagate event-cut mode bitmask to all owned subchannels. */
967{
968 size_t i = 0;
969 // bEVENTCUTMODE=bcuts;
970 for (i=0;i<kNumElements;i++) {
971 fElement[i].SetEventCutMode(bcuts);
972 }
973 for(i=0;i<kNumAxes;i++){
974 fRelPos[i].SetEventCutMode(bcuts);
975 fAbsPos[i].SetEventCutMode(bcuts);
976 }
977}
978
979
980/** Build a flat list of representative channels for legacy consumers. */
982{
983 for (size_t i = kXAxis; i < kNumAxes; i++) {
984 QwVQWK_Channel relpos(fRelPos[i]);
985 relpos = fRelPos[i];
986 fBPMElementList.push_back(relpos);
987 }
988 QwVQWK_Channel effectivecharge(fElement[kQElem]);
989 effectivecharge = fElement[kQElem];
990 fBPMElementList.push_back(effectivecharge);
991}
992
993#ifdef __USE_DATABASE__
994std::vector<QwDBInterface> QwBPMCavity::GetDBEntry()
995{
996 std::vector <QwDBInterface> row_list;
997 row_list.clear();
998 for(size_t i=0;i<kNumAxes;i++) {
999 fRelPos[i].AddEntriesToList(row_list);
1000 fAbsPos[i].AddEntriesToList(row_list);
1001 }
1002 fElement[kQElem].AddEntriesToList(row_list);
1003 return row_list;
1004}
1005
1006
1007std::vector<QwErrDBInterface> QwBPMCavity::GetErrDBEntry()
1008{
1009 std::vector <QwErrDBInterface> row_list;
1010 row_list.clear();
1011 for(size_t i=0;i<kNumAxes;i++) {
1012 fRelPos[i].AddErrEntriesToList(row_list);
1013 fAbsPos[i].AddErrEntriesToList(row_list);
1014 }
1015 fElement[kQElem].AddErrEntriesToList(row_list);
1016 return row_list;
1017}
1018#endif // __USE_DATABASE__
1019
1020/**********************************
1021 * Mock data generation routines
1022 **********************************/
1023
1024/**
1025 * Configure mock-data generation parameters for testing.
1026 * Currently a placeholder for cavity-specific randomization strategies.
1027 */
1028void QwBPMCavity::SetRandomEventParameters(Double_t meanX, Double_t sigmaX, Double_t meanY, Double_t sigmaY)
1029{
1030 // Average values of the signals in the stripline ADCs
1031 //Double_t sumX = 1.1e8; // These are just guesses, but I made X and Y different
1032 //Double_t sumY = 0.9e8; // to make it more interesting for the analyzer...
1033
1034 // Rotate the requested position if necessary (this is not tested yet)
1035 /* if (bRotated) {
1036 Double_t rotated_meanX = (meanX + meanY) / kRotationCorrection;
1037 Double_t rotated_meanY = (meanX - meanY) / kRotationCorrection;
1038 meanX = rotated_meanX;
1039 meanY = rotated_meanY;
1040 }*/
1041
1042 // Determine the asymmetry from the position
1043 //Double_t meanXP = (1.0 + meanX / kQwCavityCalibration) * sumX / 2.0;
1044 //Double_t meanXM = (1.0 - meanX / kQwCavityCalibration) * sumX / 2.0; // = sumX - meanXP;
1045 //Double_t meanYP = (1.0 + meanY / kQwCavityCalibration) * sumY / 2.0;
1046 //Double_t meanYM = (1.0 - meanY / kQwCavityCalibration) * sumY / 2.0; // = sumY - meanYP;
1047
1048 // Determine the spread of the asymmetry (this is not tested yet)
1049 // (negative sigma should work in the QwVQWK_Channel, but still using fabs)
1050 //Double_t sigmaXP = fabs(sumX * sigmaX / meanX);
1051 //Double_t sigmaXM = sigmaXP;
1052 //Double_t sigmaYP = fabs(sumY * sigmaY / meanY);
1053 //Double_t sigmaYM = sigmaYP;
1054
1055 // Propagate these parameters to the ADCs
1056 //fElement[0].SetRandomEventParameters(meanXP, sigmaXM);
1057 //fElement[1].SetRandomEventParameters(meanXM, sigmaYM);
1058 //fElement[2].SetRandomEventParameters(meanYP, sigmaYP);
1059}
1060
1061
1062/** Generate random event data in owned raw elements for mock runs. */
1063void QwBPMCavity::RandomizeEventData(int helicity, double time)
1064{
1065 for (size_t i=0; i<kNumElements; i++) fElement[i].RandomizeEventData(helicity, time);
1066
1067 return;
1068}
1069
1070
1071/** Set relative position hardware sums and sequence numbers directly. */
1072void QwBPMCavity::SetEventData(Double_t* relpos, UInt_t sequencenumber)
1073{
1074 for (size_t i=0; i<kNumElements; i++)
1075 {
1076 fRelPos[i].SetHardwareSum(relpos[i], sequencenumber);
1077 }
1078
1079 return;
1080}
1081
1082
1083/** Serialize raw element data into a CODA-like output buffer. */
1084void QwBPMCavity::EncodeEventData(std::vector<UInt_t> &buffer)
1085{
1086 for (size_t i=0; i<kNumElements; i++)
1087 fElement[i].EncodeEventData(buffer);
1088}
1089
1090
1091/** Set the default sample size for all raw subelements. */
1093{
1094 for(size_t i=0;i<kNumElements;i++)
1095 fElement[i].SetDefaultSampleSize((size_t)sample_size);
1096}
1097
1098
1099/** Set the pedestal for a specific raw subelement. */
1100void QwBPMCavity::SetSubElementPedestal(Int_t j, Double_t value)
1101{
1102 fElement[j].SetPedestal(value);
1103}
1104
1105/** Set the calibration factor for a specific raw subelement. */
1107{
1108 fElement[j].SetCalibrationFactor(value);
1109}
1110
#define QwWarning
Predefined log drain for warnings.
Definition QwLog.h:44
#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.
Cavity 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)
VQwDataElement()
Default constructor.
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)
std::vector< QwErrDBInterface > GetErrDBEntry()
void SetDefaultSampleSize(Int_t sample_size) override
void AccumulateRunningSum(const VQwBPM &value, Int_t count=0, Int_t ErrorMask=0xFFFFFFF) override
void ProcessEvent() override
Bool_t ApplyHWChecks()
void CalculateRunningAverage() override
Bool_t ApplySingleEventCuts() override
void GetAbsolutePosition() override
UInt_t GetEventcutErrorFlag() override
VQwHardwareChannel * GetSubelementByName(TString ch_name) override
void SetSubElementCalibrationFactor(Int_t j, Double_t value) override
std::array< QwVQWK_Channel, kNumAxes > fRelPos
void MakeBPMCavityList()
static const TString subelement[kNumElements]
Definition QwBPMCavity.h:34
void FillHistograms() override
TString GetSubElementName(Int_t subindex) override
void ConstructBranchAndVector(TTree *tree, TString &prefix, QwRootTreeBranchVector &values) override
Bool_t CheckForBurpFail(const VQwDataElement *ev_error) override
void Ratio(QwBPMCavity &numer, QwBPMCavity &denom)
void SetEventData(Double_t *block, UInt_t sequencenumber)
void ClearEventData() override
std::vector< QwDBInterface > GetDBEntry()
void ConstructBranch(TTree *tree, TString &prefix) override
std::array< QwVQWK_Channel, kNumElements > fElement
std::array< QwVQWK_Channel, kNumAxes > fAbsPos
void EncodeEventData(std::vector< UInt_t > &buffer) override
void ConstructHistograms(TDirectory *folder, TString &prefix) override
VQwBPM & operator-=(const VQwBPM &value) override
void IncrementErrorCounters() override
void InitializeChannel(TString name)
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),...
std::vector< QwVQWK_Channel > fBPMElementList
void SetEventCutMode(Int_t bcuts) override
static Bool_t ParseChannelName(const TString &channel, TString &detname, TString &subname, UInt_t &localindex)
void PrintValue() const override
void PrintInfo() const override
UInt_t UpdateErrorFlag() override
void PrintErrorCounters() const override
Int_t ProcessEvBuffer(UInt_t *buffer, UInt_t word_position_in_buffer, UInt_t indexnumber) override
void SetSubElementPedestal(Int_t j, Double_t value) override
void RandomizeEventData(int helicity=0, double time=0.0) override
VQwBPM & operator=(const VQwBPM &value) override
void DeaccumulateRunningSum(VQwBPM &value, Int_t ErrorMask=0xFFFFFFF) override
void SetRandomEventParameters(Double_t meanX, Double_t sigmaX, Double_t meanY, Double_t sigmaY) override
static const Double_t kQwCavityCalibration
VQwBPM & operator+=(const VQwBPM &value) override
void Scale(Double_t factor) override
void FillTreeVector(QwRootTreeBranchVector &values) const override
Double_t fPositionCenter[3]
Definition VQwBPM.h:328
@ 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
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
virtual VQwBPM & operator=(const VQwBPM &value)=0
Definition VQwBPM.cc:156
VQwBPM()
Definition VQwBPM.h:76