QwAnalysis
QwBlinder.cc
Go to the documentation of this file.
1 /*!
2  * \file QwBlinder.cc
3  * \brief A class for blinding data, adapted from G0 blinder class.
4  *
5  * \author Peiqing Wang
6  * \date 2010-04-14
7  */
8 
9 #include "QwBlinder.h"
10 
11 // System headers
12 #include <string>
13 #include <limits>
14 
15 #include "TMath.h"
16 
17 // Qweak headers
18 #include "QwLog.h"
19 #define MYSQLPP_SSQLS_NO_STATICS
20 #include "QwParitySSQLS.h"
21 #include "QwParityDB.h"
22 #include "QwVQWK_Channel.h"
23 
24 /// Blinder event counter indices
39 };
40 
41 
42 // String names of the blinding and Wien status values
43 const TString QwBlinder::fStatusName[4] = {"Indeterminate", "NotBlindable",
44  "Blindable", "BlindableFail"};
45 
46 // Maximum blinding asymmetry for additive blinding
47 const Double_t QwBlinder::kMaximumBlindingAsymmetry = 0.06; // ppm
48 const Double_t QwBlinder::kMaximumBlindingFactor = 0.1; // [fraction]
49 
50 // Default seed, associated with seed_id 0
51 const TString QwBlinder::kDefaultSeed = "Default seed, should not be used!";
52 
53 //**************************************************//
55  options.AddOptions("Blinder")("blinder.force-target-lh2", po::value<bool>()->default_bool_value(false),
56  "Forces the blinder to interpret the target position as LH2");
57  options.AddOptions("Blinder")("blinder.force-target-out", po::value<bool>()->default_bool_value(false),
58  "Forces the blinder to interpret the target position as target-out");
59  options.AddOptions("Blinder")("blinder.beam-current-threshold", po::value<double>()->default_value(1.0),
60  "Beam current in microamps below which data will not be blinded");
61 }
62 
63 
64 /**
65  * Default constructor using optional database connection and blinding strategy
66  * @param blinding_strategy Blinding strategy
67  */
68 QwBlinder::QwBlinder(const EQwBlindingStrategy blinding_strategy):
69  fTargetBlindability_firstread(kIndeterminate),
70  fTargetBlindability(kIndeterminate),
71  fTargetPositionForced(kFALSE),
72  //
73  fWienMode_firstread(kWienIndeterminate),
74  fWienMode(kWienIndeterminate),
75  fIHWPPolarity_firstread(0),
76  fIHWPPolarity(0),
77  //
78  fBeamCurrentThreshold(1.0),
79  fBeamIsPresent(kFALSE),
80  fBlindingStrategy(blinding_strategy),
81  fBlindingOffset(0.0),
82  fBlindingOffset_Base(0.0),
83  fBlindingFactor(1.0)
84 {
85  // Set up the blinder with seed_id 0
87  fSeedID = 0;
88 
89  InitBlinders(0);
90 
91  // Calculate set of test values
92  InitTestValues(10);
94 }
95 
96 
97 /**
98  * Destructor checks the validity of the blinding and unblinding
99  */
101 {
102  // Check the blinded values
104 }
105 
106 
107 /**
108  * Update the blinder status with new external information
109  *
110  * @param options Qweak option handler
111  */
113 {
114  if (options.GetValue<bool>("blinder.force-target-out")
115  && options.GetValue<bool>("blinder.force-target-lh2")){
116  QwError << "QwBlinder::Update: Both blinder.force-target-lh2 and blinder.force-target-out are set. "
117  << "Only one can be in force at one time. Exit and choose one option."
118  << QwLog::endl;
119  exit(10);
120  } else if (options.GetValue<bool>("blinder.force-target-lh2")){
121  fTargetPositionForced = kTRUE;
123  } else if (options.GetValue<bool>("blinder.force-target-out")){
124  fTargetPositionForced = kTRUE;
126  }
127  if (options.HasValue("blinder.beam-current-threshold")){
128  fBeamCurrentThreshold = options.GetValue<double>("blinder.beam-current-threshold");
129  }
130 
131 }
132 
133 /**
134  * Update the blinder status with new external information
135  *
136  * @param db Database connection
137  */
139 {
140  // Update the seed ID then tell us if it has changed.
141  UInt_t old_seed_id = fSeedID;
142  ReadSeed(db);
143  // If the blinding seed has changed, re-initialize the blinder
144  if (fSeedID != old_seed_id ||
145  (fSeedID==0 && fSeed!=kDefaultSeed) ) {
146  QwWarning << "Changing blinder seed to " << fSeedID
147  << " from " << old_seed_id << "." << QwLog::endl;
149  InitTestValues(10);
150  }
151 }
152 
153 /**
154  * Update the blinder status with new external information
155  *
156  * @param detectors Current subsystem array
157  */
159 {
160  static QwVQWK_Channel q_targ("q_targ");
162  // Check for the target blindability flag
163 
164 
165  // Check that the current on target is above acceptable limit
166  Bool_t tmp_beam = kFALSE;
167  // if (detectors.ReturnInternalValue(q_targ.GetElementName(), &q_targ)) {
168  if (detectors.ReturnInternalValue("q_targ", &q_targ)) {
169  if (q_targ.GetValue() > fBeamCurrentThreshold){
170  // std::cerr << "q_targ.GetValue()=="
171  // << q_targ.GetValue() << std::endl;
172  tmp_beam = kTRUE;
173  }
174  }
175  fBeamIsPresent &= tmp_beam;
176  }
177 }
178 
179 /**
180  * Update the blinder status with new external information
181  *
182  * @param epics Current EPICS event
183  */
184 void QwBlinder::Update(const QwEPICSEvent& epics)
185 {
186  // Check for the target information
187  // Position:
188  // QWtgt_name == "HYDROGEN-CELL" || QWTGTPOS > 350
189  // Temperature:
190  // QWT_miA < 22.0 && QWT_moA < 22.0
191  // Pressure:
192  // QW_PT3 in [20,35] && QW_PT4 in [20,35]
194  TString position = epics.GetDataString("QWtgt_name");
195  Double_t tgt_pos = epics.GetDataValue("QWTGTPOS");
196  Double_t tgt_temperture = epics.GetDataValue("QWT_miB");
197  Double_t tgt_temperture2 = epics.GetDataValue("QWT_moB");
198  Double_t tgt_pressure = epics.GetDataValue("QW_PT3");
199  Double_t tgt_pressure2 = epics.GetDataValue("QW_PT4");
200  QwDebug << "Target parameters used by the blinder: "
201  << "QWtgt_name=" << position << " "
202  << "QWTGTPOS=" << tgt_pos << " "
203  << "QWT_miB=" << tgt_temperture << " "
204  << "QWT_moB=" << tgt_temperture2 << " "
205  << "QW_PT3=" << tgt_pressure << " "
206  << "QW_PT4=" << tgt_pressure2 << " "
207  << QwLog::endl;
208  if (position == "HYDROGEN-CELL"
209  && tgt_pos > 350.
210  && (tgt_temperture>18.0 && tgt_temperture<22.0)
211  && (tgt_temperture2>18.0 && tgt_temperture2<22.0)
212  && (tgt_pressure>20.0 && tgt_pressure < 35.0)
213  && (tgt_pressure2>20.0 && tgt_pressure2 < 35.0)){
215  } else if ((position == "HYDROGEN-CELL"
216  && tgt_pos > 350.)
217  && (tgt_temperture > 22.0)
218  && (tgt_temperture2 > 22.0)
219  && (tgt_pressure > 35.0)
220  && (tgt_pressure2 > 35.0)){
221  // Hydrogen cell is in, but temperature and pressures
222  // are all higher than they should be for LH2.
224  } else if ((position != "HYDROGEN-CELL"
225  && tgt_pos < 350.)){
226  // Name and position agree that this isn't the hydrogen
227  // cell.
229  } else {
231  QwWarning << "Target parameters used by the blinder are indeterminate: "
232  << "QWtgt_name=" << position << " "
233  << "QWTGTPOS=" << tgt_pos << " "
234  << "QWT_miB=" << tgt_temperture << " "
235  << "QWT_moB=" << tgt_temperture2 << " "
236  << "QW_PT3=" << tgt_pressure << " "
237  << "QW_PT4=" << tgt_pressure2 << " "
238  << QwLog::endl;
239 
240 
241  }
242  }
243  // Check for the beam polarity information
244  // IGL1I00DI24_24M Beam Half-wave plate Read(off=out)
245  //
246  if (fBlindingStrategy != kDisabled &&
248  // Use the EPICS class functions to determine the
249  // Wien mode and IHWP polarity.
252 
253  if (fWienMode == kWienForward){
255  } else if (fWienMode == kWienBackward){
257  } else {
258  fBlindingOffset = 0.0;
259  }
260  }
261 }
262 
263 /*!-----------------------------------------------------------
264  *------------------------------------------------------------
265  * Function to read the seed in from the database.
266  *
267  * Parameters:
268  *
269  * Return: Int_t
270  *
271  *------------------------------------------------------------
272  *------------------------------------------------------------*/
274 {
275  // Return unchanged if no database specified
276  if (! db) {
277  QwWarning << "QwBlinder::ReadSeed(): No database specified" << QwLog::endl;
278  fSeedID = 0;
279  fSeed = "Default seed, No database specified";
280  return 0;
281  }
282 
283  // Try to connect to the database
284  if (db->Connect()) {
285 
286  QwError << "QwBlinder::ReadSeed db->GetRunNumber() returns "
287  << db->GetRunNumber() << QwLog::endl;
288  // Build up query
289  string s_sql = "SELECT seed_id, seed FROM seeds, run as rf, run as rl WHERE seeds.first_run_id = rf.run_id AND seeds.last_run_id = rl.run_id ";
290  s_sql += "AND rf.run_number <= ";
291  s_sql += Form("%d",db->GetRunNumber());
292  s_sql += " AND rl.run_number >= ";
293  s_sql += Form("%d",db->GetRunNumber());
294  s_sql += " AND seed_id>2";
295 
296  QwError << "QwBlinder::ReadSeed s_sql contains \'"
297  << s_sql << "\'" << QwLog::endl;
298 
299  // Send query
300  mysqlpp::Query query = db->Query();
301  query << s_sql;
302  mysqlpp::StoreQueryResult res = query.store();
303 
304  // Store seed_id and seed value in fSeedID and fSeed (want to store actual seed_id in those
305  // cases where only the most recent was requested (fSeedID = 0))
306  // There should be one and only one seed_id for each seed.
307  if (res.size() == 1) {
308  // Store seed_id in fSeedID (want to store actual seed_id in those
309  // cases where only the most recent was requested (fSeedID = 0))
310  fSeedID = res[0]["seed_id"];
311 
312  // Store seed value
313  if (!res[0]["seed"].is_null()) {
314  fSeed = res[0]["seed"].data();
315  } else {
316  QwError << "QwBlinder::ReadSeed(): Seed value came back NULL from the database." << QwLog::endl;
317  fSeedID = 0;
319  }
320 
321  std::cout << "QwBlinder::ReadSeed(): Successfully read "
322  << Form("the fSeed with ID %d from the database.", fSeedID)
323  << std::endl;
324 
325  } else {
326  // Error Condition.
327  // There should be one and only one seed_id for each seed.
328  fSeedID = 0;
329  fSeed = Form("ERROR: There should be one and only one seed_id for each seed, but this had %zu.",
330  res.size());
331  std::cerr << "QwBlinder::ReadSeed(): "<<fSeed<<std::endl;
332  }
333 
334  // Disconnect from database
335  db->Disconnect();
336 
337  } else {
338 
339  // We were unable to open the connection.
340  fSeedID = 0;
341  fSeed = "ERROR: Unable to open the connection to the database.";
342  QwError << "QwBlinder::ReadSeed(): Unable to open connection to database." << QwLog::endl;
343  }
344 
345  return fSeedID;
346 }
347 
348 
349 /*!-----------------------------------------------------------
350  *------------------------------------------------------------
351  * Function to read the seed in from the database.
352  *
353  * Parameters:
354  * seed_id = ID number of seed to use (0 = most recent seed)
355  *
356  * Return: Int_t
357  *
358  *------------------------------------------------------------
359  *------------------------------------------------------------*/
360 Int_t QwBlinder::ReadSeed(QwParityDB* db, const UInt_t seed_id)
361 {
362  // Return unchanged if no database specified
363  if (! db) {
364  QwWarning << "QwBlinder::ReadSeed(): No database specified" << QwLog::endl;
365  fSeedID = 0;
366  fSeed = "Default seed, No database specified";
367  return 0;
368  }
369 
370  // Try to connect to the database
371  if (db->Connect()) {
372 
373  // Build up query
374  string s_sql = "SELECT * FROM seeds ";
375  if (fSeedID > 0) {
376  // Use specified seed
377  Char_t s_seed_id[10];
378  sprintf(s_seed_id, "%d", seed_id);
379  s_sql += "WHERE seed_id = ";
380  s_sql += string(s_seed_id);
381  } else {
382  // Use most recent seed
383  s_sql += "ORDER BY seed_id DESC LIMIT 1";
384  }
385 
386  // Send query
387  mysqlpp::Query query = db->Query();
388  query << s_sql;
389  std::vector<QwParitySSQLS::seeds> res;
390  query.storein(res);
391 
392  // Store seed_id and seed value in fSeedID and fSeed (want to store actual seed_id in those
393  // cases where only the most recent was requested (fSeedID = 0))
394  // There should be one and only one seed_id for each seed.
395  if (res.size() == 1) {
396  // Store seed_id in fSeedID (want to store actual seed_id in those
397  // cases where only the most recent was requested (fSeedID = 0))
398  fSeedID = res[0].seed_id;
399 
400  // Store seed value
401  if (!res[0].seed.is_null) {
402  fSeed = res[0].seed.data;
403  } else {
404  QwError << "QwBlinder::ReadSeed(): Seed value came back NULL from the database." << QwLog::endl;
405  fSeedID = 0;
407  }
408 
409  std::cout << "QwBlinder::ReadSeed(): Successfully read "
410  << Form("the fSeed with ID %d from the database.", fSeedID)
411  << std::endl;
412 
413  } else {
414  // Error Condition.
415  // There should be one and only one seed_id for each seed.
416  fSeedID = 0;
417  fSeed = Form("ERROR: There should be one and only one seed_id for each seed, but this had %zu.",
418  res.size());
419  std::cerr << "QwBlinder::ReadSeed(): "<<fSeed<<std::endl;
420  }
421 
422  // Disconnect from database
423  db->Disconnect();
424 
425  } else {
426 
427  // We were unable to open the connection.
428  fSeedID = 0;
429  fSeed = "ERROR: Unable to open the connection to the database.";
430  QwError << "QwBlinder::ReadSeed(): Unable to open connection to database." << QwLog::endl;
431  }
432 
433  return fSeedID;
434 }
435 
436 
437 
438 /**
439  * Initialize the blinder parameters
440  */
441 void QwBlinder::InitBlinders(const UInt_t seed_id)
442 {
443  // If the blinding strategy is disabled
444  if (fBlindingStrategy == kDisabled) {
445 
447  fSeedID = 0;
448  fBlindingFactor = 1.0;
449  fBlindingOffset = 0.0;
450  fBlindingOffset_Base = 0.0;
451  QwWarning << "Blinding parameters have been disabled!"<< QwLog::endl;
452 
453  // Else blinding is enabled
454  } else {
455 
456  Int_t finalseed = UseMD5(fSeed);
457 
458  Double_t newtempout;
459  if ((finalseed & 0x80000000) == 0x80000000) {
460  newtempout = -1.0 * (finalseed & 0x7FFFFFFF);
461  } else {
462  newtempout = 1.0 * (finalseed & 0x7FFFFFFF);
463  }
464 
465 
466  /// The blinding constants are determined in two steps.
467  ///
468  /// First, the blinding asymmetry (offset) is determined. It is
469  /// generated from a signed number between +/- 0.244948974 that
470  /// is squared to get a number between +/- 0.06 ppm.
471  static Double_t maximum_asymmetry_sqrt = sqrt(kMaximumBlindingAsymmetry);
472  Double_t tmp1 = maximum_asymmetry_sqrt * (newtempout / Int_t(0x7FFFFFFF));
473  fBlindingOffset = tmp1 * fabs(tmp1) * 0.000001;
474 
475  // Do another little calulation to round off the blinding asymmetry
476  Double_t tmp2;
477  tmp1 = fBlindingOffset * 4; // Exactly shifts by two binary places
478  tmp2 = tmp1 + fBlindingOffset; // Rounds 5*fBlindingOffset
479  fBlindingOffset = tmp2 - tmp1; // fBlindingOffset has been rounded.
480 
481  // Set the base blinding offset.
483 
484  /// Secondly, the multiplicative blinding factor is determined. This
485  /// number is generated from the blinding asymmetry between, say, 0.9 and 1.1
486  /// by an oscillating but uniformly distributed sawtooth function.
487  fBlindingFactor = 1.0;
488  if (kMaximumBlindingAsymmetry > 0.0) {
489  /// TODO: This section of InitBlinders doesn't calculate a reasonable fBlindingFactor but we don't use it for anything.
490  fBlindingFactor = 1.0 + fmod(30.0 * fBlindingOffset, kMaximumBlindingAsymmetry);
492  }
493 
494  QwMessage << "Blinding parameters have been calculated."<< QwLog::endl;
495 
496  }
497 
498  // Generate checksum
499  TString hex_string;
500  hex_string.Form("%.16llx%.16llx", *(ULong64_t*)(&fBlindingFactor), *(ULong64_t*)(&fBlindingOffset));
501  fDigest = GenerateDigest(hex_string);
502  fChecksum = "";
503  for (size_t i = 0; i < fDigest.size(); i++)
504  fChecksum += string(Form("%.2x",fDigest[i]));
505 }
506 
507 
509 {
510  WriteChecksum(db);
511  if (! CheckTestValues()) {
512  QwError << "QwBlinder::WriteFinalValuesToDB(): "
513  << "Blinded test values have changed; may be a problem in the analysis!!!"
514  << QwLog::endl;
515  }
516  WriteTestValues(db);
517 }
518 
519 
520 
521 /**
522  * Generate a set of test values of similar size as measured asymmetries
523  * @param n Number of test values
524  */
525 void QwBlinder::InitTestValues(const int n)
526 {
527  // Use the stored seed to get a pseudorandom number
528  Int_t finalseed = UsePseudorandom(fSeed);
529 
530  fTestValues.clear();
531  fBlindTestValues.clear();
532  fUnBlindTestValues.clear();
533 
534  Double_t tmp_offset = fBlindingOffset;
536  // For each test case
537  for (int i = 0; i < n; i++) {
538 
539  // Generate a pseudorandom number
540  for (Int_t j = 0; j < 16; j++) {
541  finalseed &= 0x7FFFFFFF;
542  if ((finalseed & 0x800000) == 0x800000) {
543  finalseed = ((finalseed ^ 0x00000d) << 1) | 0x1;
544  } else {
545  finalseed <<= 1;
546  }
547  }
548 
549  // Mask out the low digits of the finalseed, multiply by two,
550  // divide by the mask value, subtract from 1, and divide result by
551  // 1.0e6 to get a range of about -1000 to +1000 ppb.
552  Int_t mask = 0xFFFFFF;
553  Double_t tempval = (1.0 - 2.0*(finalseed&mask)/mask) / (1.0e6);
554 
555  // Store the test values
556  fTestValues.push_back(tempval);
557  BlindValue(tempval);
558  fBlindTestValues.push_back(tempval);
559  UnBlindValue(tempval);
560  fUnBlindTestValues.push_back(tempval);
561  }
562  fBlindingOffset = tmp_offset;
563  QwMessage << "QwBlinder::InitTestValues(): A total of " << fTestValues.size()
564  << " test values have been calculated successfully." << QwLog::endl;
565 }
566 
567 /**
568  * Use string manipulation to get a number from the seed string
569  * @param barestring Seed string
570  * @return Integer number
571  */
572 Int_t QwBlinder::UseStringManip(const TString& barestring)
573 {
574  std::vector<UInt_t> choppedwords;
575  UInt_t tmpword;
576  Int_t finalseed = 0;
577 
578  for (Int_t i = 0; i < barestring.Length(); i++)
579  {
580  if (i % 4 == 0) tmpword = 0;
581  tmpword |= (char(barestring[i]))<<(24-8*(i%4));
582  if (i%4 == 3 || i == barestring.Length()-1)
583  {
584  choppedwords.push_back(tmpword);
585  finalseed ^= (tmpword);
586  }
587  }
588  for (Int_t i=0; i<64; i++)
589  {
590  finalseed &= 0x7FFFFFFF;
591  if ((finalseed & 0x800000) == 0x800000)
592  {
593  finalseed = ((finalseed^0x00000d)<<1) | 0x1;
594  }
595  else
596  {
597  finalseed<<=1;
598  }
599  }
600  if ((finalseed&0x80000000) == 0x80000000)
601  {
602  finalseed = -1 * (finalseed&0x7FFFFFFF);
603  }
604  else
605  {
606  finalseed = (finalseed&0x7FFFFFFF);
607  }
608  return finalseed;
609 }
610 
611 
612 /**
613  * Use pseudo-random number generator to get a number from the seed string
614  * @param barestring Seed string
615  * @return Integer number
616  */
617 Int_t QwBlinder::UsePseudorandom(const TString& barestring)
618 {
619  ULong64_t finalseed;
620  Int_t bitcount;
621  Int_t tempout = 0;
622 
623  // This is an attempt to build a portable 64-bit constant
624  ULong64_t longmask = (0x7FFFFFFF);
625  longmask<<=32;
626  longmask|=0xFFFFFFFF;
627 
628  finalseed = 0;
629  bitcount = 0;
630  for (Int_t i=0; i<barestring.Length(); i++)
631  {
632  if ( ((barestring[i])&0xC0)!=0 && ((barestring[i])&0xC0)!=0xC0)
633  {
634  finalseed = ((finalseed&longmask)<<1) | (((barestring[i])&0x40)>>6);
635  bitcount++;
636  }
637  if ( ((barestring[i])&0x30)!=0 && ((barestring[i])&0x30)!=0x30)
638  {
639  finalseed = ((finalseed&longmask)<<1) | (((barestring[i])&0x10)>>4);
640  bitcount++;
641  }
642  if ( ((barestring[i])&0xC)!=0 && ((barestring[i])&0xC)!=0xC)
643  {
644  finalseed = ((finalseed&longmask)<<1) | (((barestring[i])&0x4)>>2);
645  bitcount++;
646  }
647  if ( ((barestring[i])&0x3)!=0 && ((barestring[i])&0x3)!=0x3)
648  {
649  finalseed = ((finalseed&longmask)<<1) | ((barestring[i])&0x1);
650  bitcount++;
651  }
652  }
653  for (Int_t i=0; i<(192-bitcount); i++)
654  {
655  if ((finalseed & 0x800000) == 0x800000)
656  {
657  finalseed = ((finalseed^0x00000d)<<1) | 0x1;
658  }
659  else
660  {
661  finalseed<<=1;
662  }
663  }
664  tempout = (finalseed&0xFFFFFFFF) ^ ((finalseed>>32)&0xFFFFFFFF);
665  if ((tempout&0x80000000) == 0x80000000)
666  {
667  tempout = -1 * (tempout&0x7FFFFFFF);
668  }
669  else
670  {
671  tempout = 1 * (tempout&0x7FFFFFFF);
672  }
673  return tempout;
674 }
675 
676 
677 /**
678  * Use an MD5 checksum to get a number from the seed string
679  * @param barestring Seed string
680  * @return Integer number
681  */
682 Int_t QwBlinder::UseMD5(const TString& barestring)
683 {
684  Int_t temp = 0;
685  Int_t tempout = 0;
686 
687  std::vector<UChar_t> digest = GenerateDigest(barestring);
688  for (size_t i = 0; i < digest.size(); i++)
689  {
690  Int_t j = i%4;
691  if (j == 0)
692  {
693  temp = 0;
694  }
695  temp |= (digest[i])<<(24-(j*8));
696  if ( (j==3) || (i==(digest.size()-1)))
697  {
698  tempout ^= temp;
699  }
700  }
701 
702  if ((tempout & 0x80000000) == 0x80000000) {
703  tempout = -1 * (tempout & 0x7FFFFFFF);
704  } else {
705  tempout = (tempout & 0x7FFFFFFF);
706  }
707 
708  return tempout;
709 }
710 
711 
712 
713 /*!-----------------------------------------------------------
714  *------------------------------------------------------------
715  * Function to write the checksum into the analysis table
716  *
717  * Parameters: void
718  *
719  * Return: void
720  *
721  * Note: This function assumes that the analysis table has already
722  * been filled for the run.
723  *------------------------------------------------------------
724  *------------------------------------------------------------*/
726 {
727  //----------------------------------------------------------
728  // Construct SQL
729  //----------------------------------------------------------
730  Char_t s_number[20];
731  string s_sql = "UPDATE analysis SET seed_id = ";
732  sprintf(s_number, "%d", fSeedID);
733  s_sql += string(s_number);
734  s_sql += ", bf_checksum = ";
735  s_sql += "\'" + fChecksum + "\'";
736  s_sql += " WHERE analysis_id = ";
737  sprintf(s_number, "%d", db->GetAnalysisID());
738  s_sql += string(s_number);
739 
740  //----------------------------------------------------------
741  // Execute SQL
742  //----------------------------------------------------------
743  db->Connect();
744  mysqlpp::Query query = db->Query();
745  query <<s_sql;
746  query.execute();
747  db->Disconnect();
748 } //End QwBlinder::WriteChecksum
749 
750 /*!------------------------------------------------------------
751  *------------------------------------------------------------
752  * Function to write the test values into the database
753  *
754  * Parameters: void
755  *
756  * Return: void
757  *------------------------------------------------------------
758  *------------------------------------------------------------*/
760 {
761  //----------------------------------------------------------
762  // Construct Initial SQL
763  //----------------------------------------------------------
764  Char_t s_number[20];
765 
766  string s_sql_pre = "INSERT INTO bf_test (analysis_id, test_number, test_value) VALUES (";
767  // analysis_id
768  sprintf(s_number, "%d", db->GetAnalysisID());
769  s_sql_pre += string(s_number);
770  s_sql_pre += ", ";
771 
772  //----------------------------------------------------------
773  // Construct Individual SQL and Execute
774  //----------------------------------------------------------
775  // Loop over all test values
776  for (size_t i = 0; i < fTestValues.size(); i++)
777  {
778  string s_sql = s_sql_pre;
779 
780  // test_number
781  sprintf(s_number, "%d", (int) i);
782  s_sql += string(s_number);
783  s_sql += ", ";
784 
785  // test_value
786  sprintf(s_number, "%9g", fBlindTestValues[i]);
787  s_sql += s_number;
788  s_sql += ")";
789 
790  // Execute SQL
791  db->Connect();
792  mysqlpp::Query query = db->Query();
793  query <<s_sql;
794  query.execute();
795  db->Disconnect();
796  }
797 }
798 
799 
800 /*!--------------------------------------------------------------
801  * This routines checks to see if the stored fBlindTestValues[i]
802  * match a recomputed blinded test value. The values are cast
803  * into floats, and their difference must be less than a change
804  * of the least-significant-bit of fBlindTestValues[i].
805  *--------------------------------------------------------------*/
806 
808 {
809  Bool_t status = kTRUE;
810 
811  Double_t tmp_offset = fBlindingOffset;
813  double epsilon = std::numeric_limits<double>::epsilon();
814  for (size_t i = 0; i < fTestValues.size(); i++) {
815 
816  /// First test: compare a blinded value with a second computation
817  double checkval = fBlindTestValues[i];
818  UnBlindValue(checkval);
819 
820  double test1 = fTestValues[i];
821  double test2 = checkval;
822  if ((test1 - test2) <= -epsilon || (test1 - test2) >= epsilon) {
823  QwError << "QwBlinder::CheckTestValues(): Unblinded test value "
824  << i
825  << " does not agree with original test value, "
826  << "with a difference of "
827  << (test1 - test2)
828  << " (epsilon==" << epsilon << ")"
829  << "." << QwLog::endl;
830  status = kFALSE;
831  }
832 
833  /// Second test: compare the unblinded value with the original value
834  test1 = fUnBlindTestValues[i];
835  test2 = fTestValues[i];
836  if ((test1 - test2) <= -epsilon || (test1 - test2) >= epsilon) {
837  QwError << "QwBlinder::CheckTestValues(): Unblinded test value "
838  << i
839  << " does not agree with original test value, "
840  << "with a difference of "
841  << (test1 - test2) << "." << QwLog::endl;
842  status = kFALSE;
843  }
844  }
845  fBlindingOffset = tmp_offset;
846  return status;
847 }
848 
849 
850 /**
851  * Generate an MD5 digest of the blinding parameters
852  * @param input Input string
853  * @return MD5 digest of the input string
854  */
855 std::vector<UChar_t> QwBlinder::GenerateDigest(const TString& input) const
856 {
857  // Initialize MD5 checksum array
858  const UInt_t length = 16;
859  UChar_t value[length];
860  for (UInt_t i = 0; i < length; i++)
861  value[i] = 0;
862 
863  // Calculate MD5 checksum from input and store in md5_value
864  TMD5 md5;
865  md5.Update((UChar_t*) input.Data(), input.Length());
866  md5.Final(value);
867 
868  // Copy the MD5 checksum in an STL vector
869  std::vector<UChar_t> output;
870  for (UInt_t i = 0; i < length; i++)
871  output.push_back(value[i]);
872 
873  return output;
874 }
875 
876 
877 /**
878  * Print a summary of the blinding/unblinding test
879  */
881 {
882  QwMessage << "QwBlinder::PrintFinalValues(): Begin summary" << QwLog::endl;
883  QwMessage << "================================================" << QwLog::endl;
884  QwMessage << "Blinder Passed Patterns" << QwLog::endl;
885  QwMessage << "\tPatterns with blinding disabled: " << fPatternCounters.at(kBlinderCount_Disabled) << QwLog::endl;
886  QwMessage << "\tPatterns on a non-blindable target: " << fPatternCounters.at(kBlinderCount_NonBlindable) << QwLog::endl;
887  QwMessage << "\tPatterns with transverse beam: " << fPatternCounters.at(kBlinderCount_Transverse) << QwLog::endl;
888  QwMessage << "\tPatterns on blindable target with beam present: " << fPatternCounters.at(kBlinderCount_Blindable) << QwLog::endl;
889  QwMessage << "Blinder Failed Patterns" << QwLog::endl;
890  QwMessage << "\tPatterns with unknown target position: " << fPatternCounters.at(kBlinderCount_UnknownTarget) << QwLog::endl;
891  QwMessage << "\tPatterns with changed target position: " << fPatternCounters.at(kBlinderCount_ChangedTarget) << QwLog::endl;
892  QwMessage << "\tPatterns with an undefined Wien setting: " << fPatternCounters.at(kBlinderCount_UndefinedWien) << QwLog::endl;
893  QwMessage << "\tPatterns with a changed Wien setting: " << fPatternCounters.at(kBlinderCount_ChangedWien) << QwLog::endl;
894  QwMessage << "\tPatterns with an undefined IHWP setting: " << fPatternCounters.at(kBlinderCount_UndefinedIHWP) << QwLog::endl;
895  QwMessage << "\tPatterns with a changed IHWP setting: " << fPatternCounters.at(kBlinderCount_ChangedIHWP) << QwLog::endl;
896  QwMessage << "\tPatterns on blindable target with no beam: " << fPatternCounters.at(kBlinderCount_NoBeam) << QwLog::endl;
897  QwMessage << "\tPatterns with other blinding failure: " << fPatternCounters.at(kBlinderCount_OtherFailure) << QwLog::endl;
898  QwMessage << "================================================" << QwLog::endl;
899  QwMessage << "The blinding parameters checksum for seed ID "
900  << fSeedID << " is:" << QwLog::endl;
902  QwMessage << "================================================" << QwLog::endl;
903  CheckTestValues();
904  double epsilon = std::numeric_limits<double>::epsilon();
905  TString diff;
906  QwMessage << "The test results are:" << QwLog::endl;
907  QwMessage << std::setw(8) << "Index"
908  << std::setw(16) << "Original value"
909  << std::setw(16) << "Blinded value"
910  << std::setw(22) << "Orig.-Unblind value"
911  << QwLog::endl;
912  for (size_t i = 0; i < fTestValues.size(); i++) {
913  if ((fTestValues[i]-fUnBlindTestValues[i]) < -epsilon
914  || (fTestValues[i]-fUnBlindTestValues[i]) > epsilon )
915  diff = Form("% 9g ppb", fTestValues[i]-fUnBlindTestValues[i]*1e9);
916  else
917  diff = "epsilon";
918  QwMessage << std::setw(8) << i
919  << std::setw(16) << Form(" [CENSORED]")
920  << std::setw(16) << Form("% 9.3f ppb",fBlindTestValues[i]*1e9)
921  << std::setw(22) << diff
922  << QwLog::endl;
923  }
924  QwMessage << "================================================" << QwLog::endl;
925  QwMessage << "QwBlinder::PrintFinalValues(): End of summary" << QwLog::endl;
926 }
927 
928 
929 /**
930  * Write the blinding parameters to the database
931  * @param db Database connection
932  * @param datatype Datatype
933  *
934  * For each analyzed run the database contains a digest of the blinding parameters
935  * and a number of blinded test entries.
936  */
937 void QwBlinder::FillDB(QwParityDB *db, TString datatype)
938 {
939  QwDebug << " --------------------------------------------------------------- " << QwLog::endl;
940  QwDebug << " QwBlinder::FillDB " << QwLog::endl;
941  QwDebug << " --------------------------------------------------------------- " << QwLog::endl;
942 
943  // Get the analysis ID
944  UInt_t analysis_id = db->GetAnalysisID();
945 
946  // Fill the rows of the QwParitySSQLS::bf_test table
947  if (! CheckTestValues()) {
948  QwError << "QwBlinder::FillDB(): "
949  << "Blinded test values have changed; "
950  << "may be a problem in the analysis!!!"
951  << QwLog::endl;
952  }
953 
954  QwParitySSQLS::bf_test bf_test_row(0);
955  std::vector<QwParitySSQLS::bf_test> bf_test_list;
956  for (size_t i = 0; i < fTestValues.size(); i++) {
957  bf_test_row.bf_test_id = 0;
958  bf_test_row.analysis_id = analysis_id;
959  bf_test_row.test_number = i;
960  bf_test_row.test_value = fBlindTestValues[i];
961  bf_test_list.push_back(bf_test_row);
962  }
963 
964 
965  // Connect to the database
966  db->Connect();
967 
968  // Modify the seed_id and bf_checksum in the analysis table
969  try {
970  // Get the rows of the QwParitySSQLS::analysis table
971  mysqlpp::Query query = db->Query();
972  query << "select * from analysis where analysis_id = "
973  << analysis_id;
974  std::vector<QwParitySSQLS::analysis> analysis_res;
975  QwDebug << "Query: " << query.str() << QwLog::endl;
976  query.storein(analysis_res);
977  if (analysis_res.size() == 1) {
978  QwParitySSQLS::analysis analysis_row_new = analysis_res[0];
979  // Modify the seed_id and bf_checksum
980  analysis_row_new.seed_id = fSeedID;
981  analysis_row_new.bf_checksum = fChecksum;
982  // Update the analysis table
983  query.update(analysis_res[0], analysis_row_new);
984  QwDebug << "Query: " << query.str() << QwLog::endl;
985  query.execute();
986  } else {
987  QwError << "Unable to update analysis table with blinder information. "
988  << QwLog::endl;
989  }
990  } catch (const mysqlpp::Exception& err) {
991  QwError << err.what() << QwLog::endl;
992  }
993 
994  // Add the bf_test rows
995  try {
996  if (bf_test_list.size()) {
997  mysqlpp::Query query = db->Query();
998  query.insert(bf_test_list.begin(), bf_test_list.end());
999  QwDebug << "Query: " << query.str() << QwLog::endl;
1000  query.execute();
1001  } else {
1002  QwMessage << "QwBlinder::FillDB(): No bf_test entries to write."
1003  << QwLog::endl;
1004  }
1005  } catch (const mysqlpp::Exception& err) {
1006  QwError << err.what() << QwLog::endl;
1007  }
1008 
1009  // Disconnect from database
1010  db->Disconnect();
1011 
1012 }
1013 
1014 void QwBlinder::FillErrDB(QwParityDB *db, TString datatype)
1015 {
1016  QwDebug << " --------------------------------------------------------------- " << QwLog::endl;
1017  QwDebug << " QwBlinder::FillErrDB " << QwLog::endl;
1018  QwDebug << " --------------------------------------------------------------- " << QwLog::endl;
1019  QwErrDBInterface row;
1020  std::vector<QwParitySSQLS::general_errors> entrylist;
1021 
1022  UInt_t analysis_id = db->GetAnalysisID();
1023 
1024  row.SetAnalysisID(analysis_id);
1025  row.SetDeviceID(kMaxUInt);
1026  for (size_t index=0; index<kBlinderCount_NumCounters; index++){
1027  row.SetErrorCodeId(index+20);
1028  row.SetN(fPatternCounters.at(index));
1029  row.AddThisEntryToList( entrylist );
1030  }
1031 
1032  db->Connect();
1033  // Check the entrylist size, if it isn't zero, start to query..
1034  if( entrylist.size() ) {
1035  mysqlpp::Query query= db->Query();
1036  query.insert(entrylist.begin(), entrylist.end());
1037  query.execute();
1038  }
1039  db->Disconnect();
1040 
1041  return;
1042 };
1043 
1044 
1045 
1047 {
1048  fTargetBlindability = status;
1052  QwMessage << "QwBlinder: First set target blindability to "
1054  }
1055 }
1056 
1058 {
1059  fWienMode = wienmode;
1063  QwMessage << "QwBlinder: First set Wien state to "
1065  }
1066 }
1067 
1068 void QwBlinder::SetIHWPPolarity(Int_t ihwppolarity)
1069 {
1070  fIHWPPolarity = ihwppolarity;
1071  if (fIHWPPolarity_firstread == 0 && fIHWPPolarity != 0){
1073  QwMessage << "QwBlinder: First set IHWP state to "
1074  << fIHWPPolarity << QwLog::endl;
1075  }
1076 }
1077 
1078 
1080 {
1082  if (fBlindingStrategy == kDisabled) {
1083  status = QwBlinder::kNotBlindable;
1086  QwDebug << "QwBlinder::CheckBlindability: The target blindability is not determined. "
1087  << "Fail this pattern." << QwLog::endl;
1088  status = QwBlinder::kBlindableFail;
1091  && !fTargetPositionForced) {
1092  QwDebug << "QwBlinder::CheckBlindability: The target blindability has changed. "
1093  << "Fail this pattern." << QwLog::endl;
1094  status = QwBlinder::kBlindableFail;
1096  } else if (fTargetBlindability==kNotBlindable) {
1097  // This isn't a blindable target, so don't do anything.
1098  status = QwBlinder::kNotBlindable;
1100  } else if (fTargetBlindability==kBlindable &&
1102  // Wien status changed. Fail
1103  status = QwBlinder::kBlindableFail;
1105  } else if (fTargetBlindability==kBlindable &&
1107  // IHWP status changed. Fail
1108  status = QwBlinder::kBlindableFail;
1110  } else if (fTargetBlindability==kBlindable &&
1112  // Wien status isn't determined. Fail.
1113  status = QwBlinder::kBlindableFail;
1115  } else if (fTargetBlindability==kBlindable &&
1116  fIHWPPolarity==0) {
1117  // IHWP status isn't determined. Fail.
1118  status = QwBlinder::kBlindableFail;
1120  } else if (fTargetBlindability==kBlindable &&
1122  // We don't have longitudinal beam, so don't blind.
1123  status = QwBlinder::kNotBlindable;
1125  } else if (fTargetBlindability==kBlindable
1126  && fBeamIsPresent) {
1127  // This is a blindable target and the beam is sufficent.
1128  status = QwBlinder::kBlindable;
1130  } else if (fTargetBlindability==kBlindable
1131  && (! fBeamIsPresent) ) {
1132  // This is a blindable target but there is insufficent beam present
1133  status = QwBlinder::kBlindableFail;
1135  } else {
1136  QwError << "QwBlinder::CheckBlindability: The pattern blindability is unclear. "
1137  << "Fail this pattern." << QwLog::endl;
1138  status = QwBlinder::kBlindableFail;
1140  }
1141  //
1143 
1144  return status;
1145 }
Int_t UsePseudorandom(const TString &barestring)
Definition: QwBlinder.cc:617
#define QwMessage
Predefined log drain for regular messages.
Definition: QwLog.h:50
void ProcessOptions(QwOptions &options)
Update the status with new external information.
Definition: QwBlinder.cc:112
void FillErrDB(QwParityDB *db, TString datatype)
Definition: QwBlinder.cc:1014
Double_t fBlindingOffset_Base
The term to be added to detector asymmetries.
Definition: QwBlinder.h:228
Double_t fBlindingFactor
The term to be added to detector asymmetries, before polarity correction.
Definition: QwBlinder.h:229
const VQwHardwareChannel * ReturnInternalValue(const TString &name) const
Retrieve the variable name from subsystems in this subsystem array.
EQwWienMode fWienMode
Definition: QwBlinder.h:201
void InitBlinders(const UInt_t seed_id)
Vector of test values, after unblinding.
Definition: QwBlinder.cc:441
Bool_t fTargetPositionForced
Definition: QwBlinder.h:199
#define default_bool_value(b)
Definition: QwOptions.h:51
void Disconnect()
Definition: QwDatabase.h:59
Int_t UseStringManip(const TString &barestring)
Returns an integer from a string using MD5.
Definition: QwBlinder.cc:572
Bool_t Connect()
Open a connection to the database using the predefined parameters.
Definition: QwDatabase.cc:175
EQwBlinderStatus fTargetBlindability_firstread
Indicates the first value recieved of the blindability of the target.
Definition: QwBlinder.h:193
An options class.
Definition: QwOptions.h:133
void BlindValue(Double_t &value) const
Asymmetry blinding.
Definition: QwBlinder.h:124
Double_t GetDataValue(const string &tag) const
bool HasValue(const std::string &key)
Has this key been defined.
Definition: QwOptions.h:233
Int_t DetermineIHWPPolarity() const
static const TString kDefaultSeed
Seed string (seeds.seed)
Definition: QwBlinder.h:237
static void DefineOptions(QwOptions &options)
Definition: QwBlinder.cc:54
UInt_t fSeedID
Maximum blinding factor (in % from identity)
Definition: QwBlinder.h:235
std::vector< double > fTestValues
Checksum in ASCII hex.
Definition: QwBlinder.h:242
void WriteChecksum(QwParityDB *db)
Definition: QwBlinder.cc:725
void InitTestValues(const int n)
Initializes fBlindingFactor from fSeed.
Definition: QwBlinder.cc:525
Double_t GetValue(size_t element) const
static const Double_t kMaximumBlindingFactor
Maximum blinding asymmetry (in ppm)
Definition: QwBlinder.h:233
EQwWienMode
Double Wien configuration.
Definition: QwTypes.h:302
UInt_t GetAnalysisID()
Definition: QwParityDB.h:71
void WriteFinalValuesToDB(QwParityDB *db)
Definition: QwBlinder.cc:508
void SetAnalysisID(UInt_t id)
Int_t fIHWPPolarity
Definition: QwBlinder.h:203
EQwBlinderStatus CheckBlindability()
Definition: QwBlinder.cc:1079
void PrintFinalValues()
Definition: QwBlinder.cc:880
std::vector< UChar_t > fDigest
Default seed.
Definition: QwBlinder.h:239
po::options_description_easy_init AddOptions(const std::string &blockname="Specialized options")
Add an option to a named block or create new block.
Definition: QwOptions.h:164
std::string fChecksum
Checksum in raw hex.
Definition: QwBlinder.h:240
T GetValue(const std::string &key)
Get a templated value.
Definition: QwOptions.h:240
EQwBlindingStrategy
Available blinding strategies.
Definition: QwBlinder.h:69
Virtual base class for the parity subsystems.
void SetTargetBlindability(EQwBlinderStatus status)
Definition: QwBlinder.cc:1046
#define QwDebug
Predefined log drain for debugging output.
Definition: QwLog.h:60
EQwWienMode fWienMode_firstread
Definition: QwBlinder.h:200
Double_t fBlindingOffset
Blinding strategy.
Definition: QwBlinder.h:227
A logfile class, based on an identical class in the Hermes analyzer.
TString GetDataString(const string &tag) const
void Update(QwParityDB *db)
Update the status with new external information.
Definition: QwBlinder.cc:138
void SetIHWPPolarity(Int_t ihwppolarity)
Definition: QwBlinder.cc:1068
unsigned long long ULong64_t
Definition: QwBlinder.h:27
Int_t fIHWPPolarity_firstread
Definition: QwBlinder.h:202
mysqlpp::Query Query(const char *qstr=0)
Definition: QwDatabase.h:66
EQwWienMode DetermineWienMode() const
Bool_t fBeamIsPresent
Definition: QwBlinder.h:210
EQwBlinderStatus fTargetBlindability
Definition: QwBlinder.h:198
void FillDB(QwParityDB *db, TString datatype)
Write to the database.
Definition: QwBlinder.cc:937
EQwBlinderErrorCounterIndices
Blinder event counter indices.
Definition: QwBlinder.cc:25
Int_t UseMD5(const TString &barestring)
Recomputes fBlindTestValue to check for memory errors.
Definition: QwBlinder.cc:682
void SetN(UInt_t in)
static const Double_t kMaximumBlindingAsymmetry
The factor to be mutliplied to detector asymmetries.
Definition: QwBlinder.h:232
virtual ~QwBlinder()
Default destructor.
Definition: QwBlinder.cc:100
A class for blinding data, adapted from G0 blinder class.
QwBlinder(const EQwBlindingStrategy blinding_strategy=kAdditive)
Default constructor with optional database.
Definition: QwBlinder.cc:68
Int_t ReadSeed(QwParityDB *db, const UInt_t seed_id)
Reads the seed with specified id from the database object.
Definition: QwBlinder.cc:360
void SetErrorCodeId(UInt_t in)
std::vector< double > fBlindTestValues
Vector of test values, original.
Definition: QwBlinder.h:243
void AddThisEntryToList(std::vector< T > &list)
static std::ostream & endl(std::ostream &)
End of the line.
Definition: QwLog.cc:299
void SetDeviceID(UInt_t id)
static const TString fStatusName[4]
Definition: QwBlinder.h:82
UInt_t GetRunNumber()
Definition: QwParityDB.h:67
void UnBlindValue(Double_t &value) const
Asymmetry unblinding.
Definition: QwBlinder.h:136
void WriteTestValues(QwParityDB *db)
Writes fSeedID and fBFChecksum to DB for this analysis ID.
Definition: QwBlinder.cc:759
Double_t fBeamCurrentThreshold
Definition: QwBlinder.h:209
Bool_t fBlinderIsOkay
Definition: QwBlinder.h:213
#define QwWarning
Predefined log drain for warnings.
Definition: QwLog.h:45
void SetWienState(EQwWienMode wienmode)
Definition: QwBlinder.cc:1057
EQwBlinderStatus
Status of the blinding process or intermediate steps of the process.
Definition: QwBlinder.h:76
Bool_t CheckTestValues()
Definition: QwBlinder.cc:807
const EQwBlindingStrategy fBlindingStrategy
Definition: QwBlinder.h:223
std::vector< Int_t > fPatternCounters
Counts the number of events in each failure mode.
Definition: QwBlinder.h:273
std::vector< double > fUnBlindTestValues
Vector of test values, after blinding.
Definition: QwBlinder.h:244
std::vector< UChar_t > GenerateDigest(const TString &input) const
Writes fTestNumber and fBlindTestValue to DB for this analysis ID.
Definition: QwBlinder.cc:855
TString fSeed
ID of seed used (seeds.seed_id)
Definition: QwBlinder.h:236
std::string WienModeName(EQwWienMode type)
Definition: QwTypes.cc:145
#define QwError
Predefined log drain for errors.
Definition: QwLog.h:40