Diana Software
MCoincidence.cc
Go to the documentation of this file.
1 #include "MCoincidence.hh"
2 #include "QEvent.hh"
3 #include "QRawEvent.hh"
4 #include "QEventList.hh"
5 #include "QBaseType.hh"
6 #include "QCoincidenceData.hh"
7 #include "QRunDataHandle.hh"
8 #include "QJitter.hh"
9 #include "QJitterHandle.hh"
10 #include <cmath>
11 #include <cstdlib>
12 #include <string>
13 
14 using std::vector;
15 using std::string;
16 using std::ifstream;
17 using namespace Diana;
18 
20 
21 
22 void MCoincidence::Init(QEvent& ev)
23 {
24  // called before event loop
25  fCoincidenceWindow = GetDouble("CoincidenceWindow", 0.100);
26  fCoincidenceRadius = GetDouble("CoincidenceRadius", 1200.);
27  ev.Add<QCoincidenceData>("CoincidenceData");
28  fEnergyLabel = GetString("EnergyLabel","ApplyCalibration@Energy");
29  vector<string> defaults;
30  fPSALabels = GetVectorString("PSALabels",defaults);
31  std::string timeVariableStr = GetString("TimeVariable","Raw");
32  if(timeVariableStr == "Raw") {
33  fTimeVariable = TV_RAW;
34  } else if(timeVariableStr == "OF") {
35  fTimeVariable = TV_OF;
36  } else {
37  Warn("Unrecognized time variable, setting it to Raw");
38  fTimeVariable = TV_RAW;
39  }
40 
41  // get dataset
42  GlobalHandle<QInt> dHandle("Dataset");
43  GlobalData().Get("",&dHandle,"");
44  fDataset = dHandle.Get();
45 
46  fSyncTime = GetBool("SyncTime",false);
47  if(fSyncTime) {
48  fSyncType = GetString("SyncType","coincidence");
49  if (fSyncType == "coincidence")
50  {
51  fSyncSource = GetString("SyncSource","jitter.txt");
52  fSyncTowerSource = GetString("SyncTowerSource","jitter_tower.txt");
53  }
54  else if (fSyncType == "delay")
55  {
56  fSyncTowerSource = GetString("SyncTowerSource","jitter_tower.txt");
57  }
58  else {
59  Warn("Unrecognized SyncType variable, setting it to default (coincidence)");
60  fSyncType = "coincidence";
61  }
62  }
63  fOkInvalidTotalEnergy = GetBool("OkInvalidTotalEnergy",false,false);
64  ev.Add<QDouble>("TotalEnergy");
65  ev.Add<QDouble>("Time");
66  ev.Add<QDouble>("Radius"); // DEBUG
67  fUseRunningWindow = GetBool("UseRunningWindow",true);
68  fStorePosition = GetBool("StorePosition",true,false);
69  fThisRun = -1;
70 
71  ev.Require<QPulseInfo>("DAQ","PulseInfo");
72  ev.Require<QHeader>("DAQ","Header");
73  if(!fPSALabels.empty()) {
74  for(size_t p = 0; p < fPSALabels.size(); p++) {
75  ev.RequireByLabel<QDouble>(fPSALabels[p]);
76  }
77  }
78  ev.RequireByLabel<QDouble>(fEnergyLabel);
79 
80  fOFLabel = GetString("OFLabel","COF"); // to maintain backwards compatibility
81  if(fTimeVariable == TV_OF) ev.Require<QDouble>(fOFLabel,"Jitter");
82 
83 }
84 
85 void MCoincidence::Do(QEvent& ev, const QEventList& n_neighbours)
86 {
87  const QHeader& hdr = ev.Get<QHeader>("DAQ","Header");
88  const int run = hdr.GetRun();
89  // const int chan = pi.GetChannelId();
90 
91  if(fThisRun != run) {
92  fThisRun = run;
93  QRunDataHandle rHandle(fThisRun);
94  GlobalData().Get("DAQ",&rHandle,"");
95  fRunData = rHandle.Get();
96  }
97 
98 
99  // Get the energy of the main event
100  bool validTotalEnergy = true;
101  double tot_ene;
102  GetEventEnergy(ev,tot_ene,validTotalEnergy);
103 
104  QCoincidenceData& coincData = ev.Get<QCoincidenceData>("CoincidenceData");
105  coincData.fOrderInMultiple = 1;
106  coincData.fMultiplicity = 1;
107  coincData.fCoincidentChannels.clear();
108  double LargestDeltaT = 0;
109  double SmallestDeltaT = Q_DOUBLE_DEFAULT;
110  const double time = GetTime(ev);// depends on the cfg options what "time" is used
111  ev.Get<QDouble>("Time") = time;
112 
113  // order neighbours according to our time variable;
114  std::map<double,int> indices; // map of <time,index>
115  for(size_t i = 0; i < n_neighbours.Size(); i++) {
116  double o_time = GetTime(n_neighbours[i]);
117  if(indices.find(o_time) != indices.end()) o_time+=(i+1)*1.e-09;
118  indices[o_time] = i;
119  }
120  QEventList neighbours;
121  double radius = 0.;
122  std::map<double,int>::const_iterator index = indices.begin();
123  while(index != indices.end()) {
124  // implement here radial cut
125  // will be possible to compute maximum radius of events after time selection is performed (i.e. leftIndex and rightIndex are defined)
126  radius = GetDistanceMm(ev, &n_neighbours[index->second]);
127  if( radius <= fCoincidenceRadius )neighbours.Push(&n_neighbours[index->second]);
128  index++;
129  }
130 
131  // create left and right index of the neighbours list == perform time selection
132  int leftIndex = 1, rightIndex = -1;
133  double l_time = time, r_time = time;
134  for(int i = int(neighbours.Size())-1; i >= 0; i--) {// inverse loop on neigh.
135  const double o_time = GetTime(neighbours[i]);
136  const double deltaT = o_time - l_time;
137  if(deltaT < 0) {
138  if(fabs(deltaT) < fCoincidenceWindow) {
139  if(fUseRunningWindow)
140  l_time = GetTime(neighbours[i]);
141  leftIndex = i;
142  }
143  } else if(fabs(deltaT) < fCoincidenceWindow) {
144  leftIndex = i;
145  }
146  }
147  for(size_t i = leftIndex; i < neighbours.Size(); i++) {
148  const double o_time = GetTime(neighbours[i]);
149  const double deltaT = o_time - r_time;
150  if(deltaT > 0) {
151  if(fabs(deltaT) < fCoincidenceWindow) {
152  if(fUseRunningWindow)
153  r_time = GetTime(neighbours[i]);
154  rightIndex = i;
155  }
156  } else if(fabs(deltaT) < fCoincidenceWindow) {
157  rightIndex = i;
158  }
159  }
160  // end of time selection
161 
162  int tower = -1;
163  int floor = -1;
164  int position = -1;
165  if(fStorePosition)
166  {
167 // tower = dccHandle.Get().Get(chan).fTd.fTdTower;
168 // floor = dccHandle.Get().Get(chan).fTd.fTdFloor;
169 // position = dccHandle.Get().Get(chan).fTd.fTdPos;
170  }
171 
172 
173  // fill informations
174  double maxradius = 0.;
175  for(int i = leftIndex; i <= rightIndex; i++) {
176  const QEvent& other = neighbours[i];
177  const QPulseInfo& o_pi = other.Get<QPulseInfo>("","PulseInfo");
178  const double o_time = GetTime(neighbours[i]);
179  const int o_channel = o_pi.GetChannelId();
180  const double deltaT = o_time - time;
181 
182  double o_energy;
183  bool validEnergy;
184  GetEventEnergy(other,o_energy,validEnergy);
185  validTotalEnergy&=validEnergy;
186 
187  int o_tower = -1;
188  int o_floor = -1;
189  int o_position = -1;
190  if(fStorePosition)
191  {
192 // o_tower = dccHandle.Get().Get(o_channel).fTd.fTdTower;
193 // o_floor = dccHandle.Get().Get(o_channel).fTd.fTdFloor;
194 // o_position = dccHandle.Get().Get(o_channel).fTd.fTdPos;
195  }
196  if(deltaT < 0.) coincData.fOrderInMultiple++;
197  // this is to get unique ordering when channels have same time.
198  if(deltaT == 0. && ev.GetReadNumber() > other.GetReadNumber()) {
199  coincData.fOrderInMultiple++;
200  }
201 
202  coincData.fMultiplicity++;
203  if(validEnergy)
204  tot_ene += o_energy;
205 
206  // compute maximum distance btw main && coincident channels FIXME <-- maybe energy center vs {coincidents + main}?
207  double o_radius = GetDistanceMm(ev,&other); // dist(Main <-> Coincident)
208  if(o_radius > maxradius)maxradius = o_radius;
209 
210  if(fabs(deltaT) > fabs(LargestDeltaT))
211  LargestDeltaT = deltaT;
212  if(fabs(deltaT) < fabs(SmallestDeltaT))
213  SmallestDeltaT = deltaT;
215  cc.fChannelId = o_channel;
216  cc.fDeltaT = deltaT;
217  cc.fEnergy = o_energy;
218  for(size_t p = 0; p < fPSALabels.size(); p++) {
219  cc.fPSAVariables.push_back(other.GetByLabel<QDouble>(fPSALabels[p]));
220  }
221  cc.fDeltaTower = o_tower-tower;
222  cc.fDeltaFloor = o_floor-floor;
223  cc.fDeltaPosition = o_position-position;
224  cc.fEventNumber = other.Get<QHeader>("DAQ","Header").GetEventNumber();
225  coincData.fCoincidentChannels.push_back(cc);
226  }
227  ev.Get<QDouble>("Radius") = maxradius; // write radius into event
228 
229  coincData.fNearestCoincidentIndex = -1;
230  coincData.fFarthestCoincidentIndex = -1;
231  for(size_t c = 0; c < coincData.fCoincidentChannels.size(); c++) {
232  if(coincData.fCoincidentChannels[c].fDeltaT == SmallestDeltaT)
233  coincData.fNearestCoincidentIndex = c;
234  if(coincData.fCoincidentChannels[c].fDeltaT == LargestDeltaT)
235  coincData.fFarthestCoincidentIndex = c;
236  }
237  if(validTotalEnergy)
238  ev.Get<QDouble>("TotalEnergy") = tot_ene;
239 }
240 
242 {
243  // called at the end of the event loop
244 }
245 
246 double MCoincidence::GetTime(const QEvent& ev)
247 {
248  const QHeader& header = ev.Get<QHeader>("DAQ","Header");
249  const QPulseInfo& pi = ev.Get<QPulseInfo>("DAQ","PulseInfo");
250  double time = double(header.GetTime().GetFromStartRunNs())/1e09;
251  double preTriggerTime = 0;
252 
253  switch(fTimeVariable) {
254  case TV_RAW:
255  {
256  break;
257  }
258  case TV_OF:
259  {
260  const QDouble& ofjitter = ev.Get<QDouble>(fOFLabel.c_str(),"Jitter");
261  time += ofjitter/1000;
262  break;
263  }
264 
265  }
266 
267  // response sinchronisation using by default jitter by coincidence and jitter by delay only for the reference channels
268  if(fSyncTime && fSyncType == "coincidence") {
269  const int channel = pi.GetChannelId();
270 
271  // get jitter handle for this channel
272  QJitterHandle jHandle(channel,fDataset);
273  GlobalData().Get("JitterByCoincidence",&jHandle,fSyncSource);
274 
275  if(!jHandle.IsValid()) {
276  if(fBlackList.count(channel)) return time;
277  fBlackList.insert(channel);
278  Error("Channel %d, has no jitter. Cannot be synced: %s",channel,jHandle.GetError().GetDescription().c_str());
279  return time;
280  }
281  else {
282  const QJitter& jitters = jHandle.Get();
283 
284  // get jitter for the reference channel of the given channel
285  QJitterHandle jdhandle(jitters.fRefChannel,fDataset);
286  GlobalData().Get("JitterByDelay",&jdhandle,fSyncTowerSource);
287 
288  if(!jdhandle.IsValid()) {
289  Error("Reference channel %d, has no jitter. The relative tower cannot be synced: %s",jitters.fRefChannel,jdhandle.GetError().GetDescription().c_str());
290  return time;
291  }
292 
293  const QJitter& jittersTower = jdhandle.Get();
294  time = time + jitters.fJitter - jittersTower.fJitter/1000. + preTriggerTime;
295  }
296  }
297 
298  // response sinchronisation using only jitter by delay
299  if(fSyncTime && fSyncType == "delay") {
300  const int channel = pi.GetChannelId();
301 
302  // get jitter handle for this channel
303  QJitterHandle jHandle(channel,fDataset);
304  GlobalData().Get("JitterByDelay",&jHandle,fSyncTowerSource);
305 
306  if(!jHandle.IsValid()) {
307  if(fBlackList.count(channel)) return time;
308  fBlackList.insert(channel);
309  Error("Channel %d, has no jitter. Cannot be synced: %s",channel,jHandle.GetError().GetDescription().c_str());
310  return time;
311  }
312  else {
313  const QJitter& jitters = jHandle.Get();
314  time = time - jitters.fJitter/1000. + preTriggerTime;
315  }
316  }
317 
318  return time;
319 }
320 
321 void MCoincidence::GetEventEnergy(const Diana::QEvent &ev,double &energy,bool &valid) const {
322 
323  Diana::QEventLabel branchToSelect = fEnergyLabel;
324  Diana::ReadHandle<Diana::QDouble> evHandle(branchToSelect.GetName().c_str());
325 
326  ev.Get(branchToSelect.GetOwner().c_str(),evHandle);
327  valid=true;
328  energy = Q_DOUBLE_DEFAULT;
329 
330  // If its Ok to have invalid total energy, only access the event
331  // energy if its valid.
332  if(fOkInvalidTotalEnergy) {
333  if(evHandle.IsValid()) {
334  energy = evHandle.Get();
335  }
336  else
337  valid = false;
338  }
339  else
340  // If its not ok to have invalid total energy, then this will
341  // throw if the value is invalid
342  energy = evHandle.Get();
343 }
344 
345 double MCoincidence::GetDistanceMm(const Diana::QEvent &ev,const Diana::QEvent* coincident){
346  // get channel ids
347  const int ch1 = ev.Get<QPulseInfo>("DAQ","PulseInfo").GetChannelId();
348  const int ch2 = coincident->Get<QPulseInfo>("DAQ","PulseInfo").GetChannelId();
349  /* compute distance
350  double x1,y1,z1,x2,y2,z2;
351  QChannelUtils::ChannelPosition(ch1,x1,y1,z1);
352  QChannelUtils::ChannelPosition(ch2,x2,y2,z2);
353  if(!check)Error("Could not load position of channel %d and %d.",ch1,ch2);
354  return sqrt( pow(x1-x2,2) + pow(y1-y2,2) + pow(z1-z2,2) );
355  */
356  double x1,y1,z1,x2,y2,z2;
357  x1 = fChannelPositionX[ch1];
358  y1 = fChannelPositionY[ch1];
359  z1 = fChannelPositionZ[ch1];
360  x2 = fChannelPositionX[ch2];
361  y2 = fChannelPositionY[ch2];
362  z2 = fChannelPositionZ[ch2];
363  return sqrt( pow(x1-x2,2) + pow(y1-y2,2) + pow(z1-z2,2) );
364 }
365 
366 
QRunDataHandle rHandle(753)
const int channel
Diana::QComplex pow(const Diana::QComplex &z, double a)
Raise a complex number to a real power.
Definition: QComplex.cc:246
#define Q_DOUBLE_DEFAULT
Definition: QDiana.hh:24
#define REGISTER_MODULE(clazz)
Definition: QDriver.hh:133
Version of MCoincidenceMultiplicity that uses neighbours.
Definition: MCoincidence.hh:72
void Done()
Done method.
void Do(Diana::QEvent &ev, const Diana::QEventList &neighbours)
Do method.
Definition: MCoincidence.cc:85
void GetEventEnergy(const Diana::QEvent &ev, double &energy, bool &valid) const
Get the energy of the event. Throws if event is invalid and fOkInvalidTotalEnergy is false.
double GetDistanceMm(const Diana::QEvent &ev, const Diana::QEvent *coincident)
Get the distance in mm between the centers of the main and the coincident crystals.
double GetTime(const Diana::QEvent &ev)
Get time of the event.
base types wrapped into a QObject. Currently implemented types are QInt QDouble and QFloat....
Definition: QBaseType.hh:17
coincidence data
std::vector< QCoincidentChannel > fCoincidentChannels
data of coincident channel
std::vector< double > fPSAVariables
list of references to const QEvent (s)
Definition: QEventList.hh:21
void Push(const QEvent *obj)
add a QEvent
Definition: QEventList.cc:17
size_t Size() const
number of QEvent (s)
Definition: QEventList.hh:36
diana event
Definition: QEvent.hh:46
const Q & GetByLabel(const QEventLabel &label) const
Get a QObject in read mode by label.
Definition: QEvent.hh:135
void Get(const char *owner, ReadHandle< Q > &handle) const
Get a QObject Handle in read mode.
Definition: QEvent.hh:74
unsigned int GetReadNumber() const
return the event number as read by the current reader.
Definition: QEvent.hh:60
Raw event: basic information like run number and time.
Definition: QHeader.hh:16
const Diana::QTime & GetTime() const
get time
Definition: QHeader.hh:28
int GetRun() const
destructor
Definition: QHeader.hh:22
global handle for jitter by coincidence
jitter by coincidence
Definition: QJitter.hh:17
int fRefChannel
Definition: QJitter.hh:28
double fJitter
Definition: QJitter.hh:29
Raw event: bolometer channel, trigger positions and types.
Definition: QPulseInfo.hh:18
const int & GetChannelId() const
Get ChannelId.
Definition: QPulseInfo.hh:22
global handle for QRunData
the Diana namespace is needed because sometimes we use Qt libraries, that use same class names of our...