QwAnalysis
QwMockDataGenerator.cc
Go to the documentation of this file.
1 /*------------------------------------------------------------------------*//*!
2 
3  \file QwMockDataGenerator.cc
4 
5  \brief Parity mock data generator, test code
6 
7 *//*-------------------------------------------------------------------------*/
8 
9 // C and C++ headers
10 #include <iostream>
11 
12 // Boost math library for random number generation
13 #include <boost/random.hpp>
14 
15 // Qweak headers
16 #include "QwLog.h"
17 #include "QwBeamLine.h"
18 #include "QwOptionsParity.h"
19 #include "QwEventBuffer.h"
20 #include "QwHelicity.h"
21 #include "QwHelicityPattern.h"
22 #include "QwMainCerenkovDetector.h"
23 #include "QwLumi.h"
24 #include "QwScanner.h"
25 #include "QwSubsystemArrayParity.h"
26 
27 
28 // Number of variables to correlate
29 #define NVARS 3
30 
31 
32 // Multiplet structure
33 static const int kMultiplet = 4;
34 
35 // Beam trips on qwk_bcm0l03
36 static const bool kBeamTrips = true;
37 
38 // Debug
39 static const bool kDebug = false;
40 
41 // Stringify
42 inline std::string stringify(int i) {
43  std::ostringstream stream;
44  stream << i;
45  return stream.str();
46 }
47 
48 int main(int argc, char* argv[])
49 {
50  // First, we set the command line arguments and the configuration filename,
51  // and we define the options that can be used in them (using QwOptions).
52  gQwOptions.SetCommandLine(argc, argv);
53  gQwOptions.SetConfigFile("qwmockdataanalysis.conf");
54  // Define the command line options
56 
57  // Fill the search paths for the parameter files; this sets a static
58  // variable within the QwParameterFile class which will be used by
59  // all instances.
60  // The "scratch" directory should be first.
62  QwParameterFile::AppendToSearchPath(getenv_safe_string("QWANALYSIS") + "/Analysis/prminput");
63  QwParameterFile::AppendToSearchPath(getenv_safe_string("QWANALYSIS") + "/Parity/prminput");
64 
65  // Event buffer
66  QwEventBuffer eventbuffer;
67 
68  // Detector array
70  detectors.ProcessOptions(gQwOptions);
71 
72  // Get the helicity
73  QwHelicity* helicity = dynamic_cast<QwHelicity*>(detectors.GetSubsystemByName("Helicity Info"));
74  if (! helicity) QwWarning << "No helicity subsystem defined!" << QwLog::endl;
75 
76  // Possible scenarios:
77  // - everything is random, no correlations at all, no asymmetries at all
78  // - variations in the mean of position, current, yield over the course of
79  // a run (linearly with run number, change mean/sigma as function of event
80  // number)
81  // - one parameter has a helicity-correlated asymmetry, every other parameter
82  // is random and independently distributed
83  // - two parameters have independent helicity-correlated asymmetries
84  // - two parameters have correlated helicity-correlated asymmetries
85  // - beam modulation
86 
87  // Get the beamline channels we want to correlate
88  QwBeamLine* beamline = dynamic_cast<QwBeamLine*>(detectors.GetSubsystemByName("Injector BeamLine"));
89  if (! beamline) QwWarning << "No beamline subsystem defined!" << QwLog::endl;
90 
91  // Set the BCM mean, sigma, and asymmetries
92  std::vector<std::string> bcm_name;
93  std::vector<double> bcm_asym;
94  double bcm_mean, bcm_sigma;
95  bcm_mean = 2.5e7; bcm_sigma = 2.5e6;
96  bcm_name.push_back("qwk_bcm0l00"); bcm_asym.push_back(0.0e-0);
97  bcm_name.push_back("qwk_bcm0l01"); bcm_asym.push_back(1.0e-1);
98  bcm_name.push_back("qwk_bcm0l02"); bcm_asym.push_back(2.0e-2);
99  bcm_name.push_back("qwk_bcm0l03"); bcm_asym.push_back(3.0e-3);
100  bcm_name.push_back("qwk_bcm0l04"); bcm_asym.push_back(4.0e-4);
101  bcm_name.push_back("qwk_bcm0l05"); bcm_asym.push_back(5.0e-5);
102  bcm_name.push_back("qwk_bcm0l06"); bcm_asym.push_back(6.0e-6);
103  bcm_name.push_back("qwk_bcm0l07"); bcm_asym.push_back(7.0e-7);
104  for (unsigned int i = 0; i < bcm_name.size(); i++) {
105  VQwBCM* bcm = beamline->GetBCM(bcm_name[i]);
106  if (! bcm) continue;
107  // Set the mean, sigma, and asymmetry
108  bcm->SetRandomEventParameters(bcm_mean, bcm_sigma);
109  bcm->SetRandomEventAsymmetry(bcm_asym[i]);
110  // Set a current noise component (amplitudeto, phase, frequency)
111  bcm->AddRandomEventDriftParameters(0.10*bcm_mean, 0, 60*Qw::Hz);
112  bcm->AddRandomEventDriftParameters(0.06*bcm_mean, 0, 120*Qw::Hz);
113  bcm->AddRandomEventDriftParameters(0.03*bcm_mean, 0, 180*Qw::Hz);
114  bcm->AddRandomEventDriftParameters(0.01*bcm_mean, 0, 240*Qw::Hz);
115  }
116 
117 
118  // Set the BPM mean and sigma
119  std::vector<std::string> bpm_name;
120  std::vector<double> bpm_asym, bpm_meanX, bpm_sigmaX, bpm_meanY, bpm_sigmaY;
121  bpm_name.push_back("qwk_0r06"); bpm_asym.push_back(1.0e-3);
122  bpm_name.push_back("qwk_0l06"); bpm_asym.push_back(1.0e-3);
123  bpm_meanX.push_back(6.0); bpm_sigmaX.push_back(3.0e-3);
124  bpm_meanX.push_back(6.0); bpm_sigmaX.push_back(3.0e-3);
125  bpm_meanY.push_back(-1.5); bpm_sigmaY.push_back(4.0e-3);
126  bpm_meanY.push_back(-1.5); bpm_sigmaY.push_back(4.0e-3);
127  for (unsigned int i = 0; i < 2; i++) {
128  VQwBPM* bpm = beamline->GetBPMStripline(bpm_name[i]);;
129  if (! bpm) continue;
130  // Set the mean and sigma
131  bpm->SetRandomEventParameters(bpm_meanX[i], bpm_sigmaX[i], bpm_meanY[i], bpm_sigmaY[i]);
132  }
133 
134  // Get the main detector channels we want to correlate
135  QwMainCerenkovDetector* maindetector =
136  dynamic_cast<QwMainCerenkovDetector*>(detectors.GetSubsystemByName("Main Detector"));
137  if (! maindetector) QwWarning << "No main detector subsystem defined!" << QwLog::endl;
138  Double_t bar_mean = 2.0e7;
139  Double_t bar_sigma = 3.0e4;
140  Double_t bar_asym = 4.0e-4;
141  maindetector->SetRandomEventParameters(bar_mean, bar_sigma);
142  maindetector->SetRandomEventAsymmetry(bar_asym);
143  // Specific values
144  /* disabled, wdc, 2010-07-23
145  maindetector->GetIntegrationPMT("MD2Neg")->SetRandomEventAsymmetry(2.0e-2);
146  maindetector->GetIntegrationPMT("MD2Pos")->SetRandomEventAsymmetry(2.0e-2);
147  maindetector->GetIntegrationPMT("MD3Neg")->SetRandomEventAsymmetry(3.0e-3);
148  maindetector->GetIntegrationPMT("MD3Pos")->SetRandomEventAsymmetry(3.0e-3);
149  maindetector->GetIntegrationPMT("MD4Neg")->SetRandomEventAsymmetry(4.0e-4);
150  maindetector->GetIntegrationPMT("MD4Pos")->SetRandomEventAsymmetry(4.0e-4);
151  maindetector->GetIntegrationPMT("MD5Neg")->SetRandomEventAsymmetry(5.0e-5);
152  maindetector->GetIntegrationPMT("MD5Pos")->SetRandomEventAsymmetry(5.0e-5);
153  maindetector->GetIntegrationPMT("MD6Neg")->SetRandomEventAsymmetry(6.0e-6);
154  maindetector->GetIntegrationPMT("MD6Pos")->SetRandomEventAsymmetry(6.0e-6);
155  maindetector->GetIntegrationPMT("MD7Neg")->SetRandomEventAsymmetry(7.0e-7);
156  maindetector->GetIntegrationPMT("MD7Pos")->SetRandomEventAsymmetry(7.0e-7);
157  maindetector->GetIntegrationPMT("MD8Neg")->SetRandomEventAsymmetry(8.0e-8);
158  maindetector->GetIntegrationPMT("MD8Pos")->SetRandomEventAsymmetry(8.0e-8);
159 
160  // Set a asymmetric helicity asymmetry on one of the bars
161  maindetector->GetIntegrationPMT("MD1Neg")->SetRandomEventAsymmetry(5.0e-5);
162  maindetector->GetIntegrationPMT("MD1Pos")->SetRandomEventAsymmetry(-5.0e-5);
163 
164  // Set a drift component (amplitude, phase, frequency)
165  maindetector->GetIntegrationPMT("MD3Neg")->AddRandomEventDriftParameters(3.0e6, 0, 60*Qw::Hz);
166  maindetector->GetIntegrationPMT("MD3Neg")->AddRandomEventDriftParameters(6.0e5, 0, 120*Qw::Hz);
167  maindetector->GetIntegrationPMT("MD3Neg")->AddRandomEventDriftParameters(4.5e5, 0, 240*Qw::Hz);
168  */
169 
170 
171 
172  // Get the lumi detector channels we want to correlate
173  QwLumi* lumidetector = dynamic_cast<QwLumi*>(detectors.GetSubsystemByName("Lumi Detector"));
174  if (! lumidetector) QwWarning << "No lumi detector subsystem defined!" << QwLog::endl;
175  Double_t lumi_mean = 2.5e7;
176  Double_t lumi_sigma = 2.5e6;
177  Double_t lumi_asym = 1.0e-7;
178  lumidetector->SetRandomEventParameters(lumi_mean, lumi_sigma);
179  lumidetector->SetRandomEventAsymmetry(lumi_asym);
180  // Specific values
181  /* disabled, wdc, 2010-07-23
182  lumidetector->GetIntegrationPMT("dlumi3")->SetRandomEventAsymmetry(1.0e-3);
183  lumidetector->GetIntegrationPMT("dlumi4")->SetRandomEventAsymmetry(1.0e-4);
184  lumidetector->GetIntegrationPMT("dlumi5")->SetRandomEventAsymmetry(1.0e-5);
185  */
186 
187 
188  // Initialize randomness provider and distribution
189  boost::mt19937 randomnessGenerator(999); // Mersenne twister with seed (see below)
190  boost::normal_distribution<double> normalDistribution;
191  boost::variate_generator
192  < boost::mt19937, boost::normal_distribution<double> >
193  normal(randomnessGenerator, normalDistribution);
194  // WARNING: This variate_generator will return the SAME random values as the
195  // variate_generator in QwVQWK_Channel when used with the same default seed!
196  // Therefore you really should give an explicitly different seed for the
197  // mt19937 randomness generator.
198 
199 
200 
201  // Loop over all runs
202  UInt_t runnumber_min = (UInt_t) gQwOptions.GetIntValuePairFirst("run");
203  UInt_t runnumber_max = (UInt_t) gQwOptions.GetIntValuePairLast("run");
204  for (UInt_t run = runnumber_min;
205  run <= runnumber_max;
206  run++) {
207 
208  // Open new output file
209  // (giving run number as argument to OpenDataFile confuses the segment search)
210  TString filename = Form("QwMock_%u.log", run);
211  if (eventbuffer.OpenDataFile(filename,"W") != CODA_OK) {
212  std::cout << "Error: could not open file!" << std::endl;
213  return 0;
214  }
215  eventbuffer.ResetControlParameters();
216  eventbuffer.EncodePrestartEvent(run, 0); // prestart: runnumber, runtype
217  eventbuffer.EncodeGoEvent();
218 
219 
220  // Helicity initialization loop
221  helicity->SetEventPatternPhase(-1, -1, -1);
222  // 24-bit seed, should be larger than 0x1, 0x55 = 0101 0101
223  // Consecutive runs should have no trivially related seeds:
224  // e.g. with 0x2 * run, the first two files will be just 1 MPS offset...
225  unsigned int seed = 0x1234 ^ run;
226  helicity->SetFirstBits(24, seed & 0xFFFFFF);
227 
228 
229  // Retrieve the requested range of event numbers
230  if (kDebug) std::cout << "Starting event loop..." << std::endl;
231  Int_t eventnumber_min = gQwOptions.GetIntValuePairFirst("event");
232  Int_t eventnumber_max = gQwOptions.GetIntValuePairLast("event");
233 
234  // Warn when only few events are requested, probably a problem in the input
235  if (abs(eventnumber_max - eventnumber_min) < 10)
236  QwWarning << "Only " << abs(eventnumber_max - eventnumber_min)
237  << " events will be generated." << QwLog::endl;
238 
239  // Event generation loop
240  for (Int_t event = eventnumber_min; event <= eventnumber_max; event++) {
241 
242  // First clear the event
243  detectors.ClearEventData();
244 
245  // Set the event, pattern and phase number
246  // - event number increments for every event
247  // - pattern number increments for every multiplet
248  // - phase number gives position in multiplet
249  helicity->SetEventPatternPhase(event, event / kMultiplet, event % kMultiplet + 1);
250 
251  // Run the helicity predictor
252  helicity->RunPredictor();
253  // Concise helicity printout
254  if (kDebug) {
255  // - actual helicity
256  if (helicity->GetHelicityActual() == 0) std::cout << "-";
257  else if (helicity->GetHelicityActual() == 1) std::cout << "+";
258  else std::cout << "?";
259  // - delayed helicity
260  if (helicity->GetHelicityDelayed() == 0) std::cout << "(-) ";
261  else if (helicity->GetHelicityDelayed() == 1) std::cout << "(+) ";
262  else std::cout << "(?) ";
263  if (event % kMultiplet + 1 == 4) {
264  std::cout << std::hex << helicity->GetRandomSeedActual() << std::dec << ", \t";
265  std::cout << std::hex << helicity->GetRandomSeedDelayed() << std::dec << std::endl;
266  }
267  }
268 
269  // Calculate the time assuming one ms for every helicity window
270  double helicity_window = Qw::ms;
271  double time = event * helicity_window;
272 
273 
274  // Cause a beam trip :-)
275  //
276  // If the kBeamTrips flag is set, beam trips are included every 'period'
277  // events. The beam trip has a length of 'length' events. The BCM is
278  // still randomized, but the mean is adjusted by a linear ramp down. It
279  // then jumps up immediately again.
280  if (kBeamTrips) {
281 
282  // Period = time between trips
283  // Length = length of a trip
284  double period = Qw::hour / 17.0;
285  double length = 1.0 * Qw::sec;
286 
287  // Periodicity
288  if (fmod(time, period) >= period - length) {
289  // Do the ramp down
290  VQwBCM* bcm = beamline->GetBCM(bcm_name[2]);
291  double scale = double(period - fmod(time, period)) / double(length);
292  bcm->SetRandomEventParameters(bcm_mean * scale, bcm_sigma);
293  }
294 
295  // Set the scale back to what it was after a trip
296  if (fmod(time, period) < helicity_window) {
297  VQwBCM* bcm = beamline->GetBCM(bcm_name[2]);
298  bcm->SetRandomEventParameters(bcm_mean, bcm_sigma);
299  }
300  } // end of beam trips
301 
302 
303  // Fill the detectors with randomized data
304  int myhelicity = helicity->GetHelicityActual() ? +1 : -1;
305 
306 
307 
308  // Secondly introduce correlations between variables
309  //
310  // N-dimensional correlated normal random variables:
311  // X = C' * Z
312  // with
313  // X correlated and normally distributed,
314  // Z independent and normally distributed,
315  // C the Cholesky decomposition of the positive-definite covariance matrix
316  // (C should probably be calculated offline)
317  //
318  /* Sigma =
319  1.00000 0.50000 0.50000
320  0.50000 2.00000 0.30000
321  0.50000 0.30000 1.50000
322 
323  C =
324  1.00000 0.50000 0.50000
325  0.00000 1.32288 0.03780
326  0.00000 0.00000 1.11739
327 
328  Sigma = C' * C
329  */
330  double z[NVARS], x[NVARS];
331  double C[NVARS][NVARS];
332  for (int var = 0; var < NVARS; var++) {
333  x[var] = 0.0;
334  z[var] = normal();
335  C[var][var] = 1.0;
336  }
337  C[0][0] = 1.0; C[0][1] = 0.5; C[0][2] = 0.5;
338  C[1][0] = 0.0; C[1][1] = 1.32288; C[1][2] = 0.03780;
339  C[2][0] = 0.0; C[2][1] = 0.0; C[2][2] = 1.11739;
340  for (int i = 0; i < NVARS; i++)
341  for (int j = 0; j < NVARS; j++)
342  x[i] += C[j][i] * z[j];
343 
344  // Assign to data elements
345  //maindetector->GetChannel("MD2Neg")->SetExternalRandomVariable(x[0]);
346  //lumidetector->GetChannel("dlumi1")->SetExternalRandomVariable(x[1]);
347  //beamline->GetBCM("qwk_bcm0l07")->SetExternalRandomVariable(x[2]);
348 
349 
350 
351 
352  // Randomize data for this event
353  detectors.RandomizeEventData(myhelicity, time);
354 
355  // Write this event to file
356  eventbuffer.EncodeSubsystemData(detectors);
357 
358  // Periodically print event number
359  if ((kDebug && event % 1000 == 0)
360  || event % 10000 == 0)
361  std::cout << "Generated " << event << " events." << std::endl;
362 
363 
364  } // end of event loop
365 
366 
367  eventbuffer.EncodeEndEvent();
368  eventbuffer.CloseDataFile();
369  eventbuffer.ReportRunSummary();
370 
371  QwMessage << "Wrote mock data run " << filename << " successfully." << QwLog::endl;
372 
373  } // end of run loop
374 
375 } // end of main
int GetIntValuePairFirst(const std::string &key)
Get the first of a pair of integer values.
Definition: QwOptions.h:266
virtual void SetRandomEventAsymmetry(Double_t asymmetry)=0
static const double ms
Time units: base unit is ms.
Definition: QwUnits.h:72
#define QwMessage
Predefined log drain for regular messages.
Definition: QwLog.h:50
static void AppendToSearchPath(const TString &searchdir)
Add a directory to the search path.
Definition: VQwBCM.h:32
void SetFirstBits(UInt_t nbits, UInt_t firstbits)
Definition: QwHelicity.cc:1096
static const double Hz
Frequency units: base unit is kHz.
Definition: QwUnits.h:83
void SetRandomEventAsymmetry(Double_t asymmetry)
void DefineOptionsParity(QwOptions &options)
Int_t EncodeEndEvent()
static const double sec
Definition: QwUnits.h:75
static const double e
Definition: QwUnits.h:91
QwOptions gQwOptions
Definition: QwOptions.cc:27
void ProcessOptions(QwOptions &options)
Process configuration options (default behavior)
virtual void SetRandomEventParameters(Double_t meanX, Double_t sigmaX, Double_t meanY, Double_t sigmaY)
Definition: VQwBPM.h:203
UInt_t GetRandomSeedActual()
Definition: QwHelicity.h:86
Int_t OpenDataFile(UInt_t current_run, Short_t seg)
void SetRandomEventParameters(Double_t mean, Double_t sigma)
Int_t EncodePrestartEvent(int runnumber, int runtype=0)
Int_t GetHelicityDelayed()
Definition: QwHelicity.cc:1069
Virtual base class for the parity subsystems.
VQwBCM * GetBCM(const TString name)
Definition: QwBeamLine.cc:1776
void SetConfigFile(const std::string &configfile)
Set a configuration file.
Definition: QwOptions.h:192
#define NVARS
A logfile class, based on an identical class in the Hermes analyzer.
Int_t EncodeSubsystemData(QwSubsystemArray &subsystems)
Load the options for the parity subsystems.
static const bool kBeamTrips
static const int kMultiplet
virtual void SetRandomEventParameters(Double_t mean, Double_t sigma)=0
std::string stringify(int i)
Int_t EncodeGoEvent()
void SetEventPatternPhase(Int_t event, Int_t pattern, Int_t phase)
Definition: QwHelicity.cc:1089
virtual void AddRandomEventDriftParameters(Double_t amplitude, Double_t phase, Double_t frequency)=0
void SetRandomEventParameters(Double_t mean, Double_t sigma)
Definition: QwLumi.cc:483
UInt_t GetRandomSeedDelayed()
Definition: QwHelicity.h:87
static std::ostream & endl(std::ostream &)
End of the line.
Definition: QwLog.cc:299
Definition: VQwBPM.h:34
Int_t CloseDataFile()
const std::string getenv_safe_string(const char *name)
Definition: QwOptions.h:37
void SetRandomEventAsymmetry(Double_t asymmetry)
Definition: QwLumi.cc:490
Definition: QwLumi.h:57
static const double hour
Definition: QwUnits.h:77
void RunPredictor()
Definition: QwHelicity.cc:1608
VQwSubsystemParity * GetSubsystemByName(const TString &name)
Get the subsystem with the specified name.
#define QwWarning
Predefined log drain for warnings.
Definition: QwLog.h:45
static const bool kDebug
Int_t GetHelicityActual()
Definition: QwHelicity.cc:1064
int main(int argc, char **argv)
Definition: QwRoot.cc:20
VQwBPM * GetBPMStripline(const TString name)
Definition: QwBeamLine.cc:1748
int GetIntValuePairLast(const std::string &key)
Get the last of a pair of integer values.
Definition: QwOptions.h:271
void RandomizeEventData(int helicity=0, double time=0.0)
Randomize the data in this event.
void SetCommandLine(int argc, char *argv[], bool default_config_file=true)
Set the command line arguments.
Definition: QwOptions.cc:112