Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DSCHit_factory.cc
Go to the documentation of this file.
1 // $Id$
2 //
3 // File: DSCHit_factory.cc
4 // Created: Tue Aug 6 12:53:32 EDT 2013
5 // Creator: davidl (on Darwin harriet.jlab.org 11.4.2 i386)
6 //
7 
8 
9 #include <iostream>
10 #include <iomanip>
11 #include <limits>
12 #include <cmath>
13 using namespace std;
14 
17 #include <DAQ/Df250PulsePedestal.h>
18 #include <DAQ/Df250PulseIntegral.h>
19 #include <DAQ/Df250Config.h>
20 #include "DSCHit_factory.h"
21 
22 using namespace jana;
23 
24 bool DSCHit_fadc_cmp(const DSCDigiHit *a,const DSCDigiHit *b)
25 {
26  if (a->sector==b->sector) return (a->pulse_time<b->pulse_time);
27  return (a->sector<b->sector);
28 }
29 
31 {
32  if (a->sector==b->sector) return (a->time<b->time);
33  return (a->sector<b->sector);
34 }
35 
36 //------------------
37 // init
38 //------------------
39 jerror_t DSCHit_factory::init(void)
40 {
41  DELTA_T_ADC_TDC_MAX = 20.0; // ns
42  //DELTA_T_ADC_TDC_MAX = 50.0; // ns
43  //DELTA_T_ADC_TDC_MAX = 3600.0; // ns
44  gPARMS->SetDefaultParameter("SC:DELTA_T_ADC_TDC_MAX", DELTA_T_ADC_TDC_MAX,
45  "Maximum difference in ns between a (calibrated) fADC time and"
46  " F1TDC time for them to be matched in a single hit");
47 
48  HIT_TIME_WINDOW = 60.0; //ns
49  gPARMS->SetDefaultParameter("SC:HIT_TIME_WINDOW", HIT_TIME_WINDOW,
50  "Time window of trigger corrected TDC time in which a hit in"
51  " in the TDC will match to a hit in the fADC to form an ST hit");
52 
53  //ADC_THRESHOLD = 200.; // adc counts (= 50 mV threshold)
54  ADC_THRESHOLD = 120.; // adc counts (= 10 Mv threshold)
55  gPARMS->SetDefaultParameter("SC:ADC_THRESHOLD", ADC_THRESHOLD,
56  "Software pulse integral threshold");
57 
58  USE_TIMEWALK_CORRECTION = 1.;
59  gPARMS->SetDefaultParameter("SC:USE_TIMEWALK_CORRECTION", USE_TIMEWALK_CORRECTION,
60  "Flag to decide if timewalk corrections should be applied.");
61 
62  REQUIRE_ADC_TDC_MATCH=true;
63  gPARMS->SetDefaultParameter("SC:REQUIRE_ADC_TDC_MATCH",
64  REQUIRE_ADC_TDC_MATCH,
65  "Flag to decide if a match between adc and tdc hits is required.");
66 
67  /// set the base conversion scales
68  a_scale = 0.0001;
69  t_scale = 0.0625; // 62.5 ps/count
70  t_base = 0.; // ns
71  t_tdc_base = 0.;
72 
73  CHECK_FADC_ERRORS = true;
74  gPARMS->SetDefaultParameter("SC:CHECK_FADC_ERRORS", CHECK_FADC_ERRORS, "Set to 1 to reject hits with fADC250 errors, ser to 0 to keep these hits");
75 
76  return NOERROR;
77 }
78 
79 //------------------
80 // brun
81 //------------------
82 jerror_t DSCHit_factory::brun(jana::JEventLoop *eventLoop, int32_t runnumber)
83 {
84  // Only print messages for one thread whenever run number change
85  static pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER;
86  static set<int> runs_announced;
87  pthread_mutex_lock(&print_mutex);
88  bool print_messages = false;
89  if(runs_announced.find(runnumber) == runs_announced.end()){
90  print_messages = true;
91  runs_announced.insert(runnumber);
92  }
93  pthread_mutex_unlock(&print_mutex);
94 
95  /// Load geometry - just need the number of sectors
96  DApplication* dapp = dynamic_cast<DApplication*>(eventLoop->GetJApplication());
97  if(!dapp)
98  jerr << "Cannot get DApplication from JEventLoop!" << endl;
99  DGeometry* locGeometry = dapp->GetDGeometry(runnumber);
100 
101  // Get start counter geometry
102  vector<vector<DVector3> >sc_norm;
103  vector<vector<DVector3> >sc_pos;
104  MAX_SECTORS=0;
105  if (locGeometry->GetStartCounterGeom(sc_pos, sc_norm))
106  MAX_SECTORS = sc_pos.size();
107  else
108  jerr << "Cannot load Start Counter geometry information!" << endl;
109 
110  /// Read in calibration constants
111  if(print_messages) jout << "In DSCHit_factory, loading constants..." << endl;
112 
113  // load scale factors
114  map<string,double> scale_factors;
115  // a_scale (SC_ADC_SCALE)
116  if (eventLoop->GetCalib("/START_COUNTER/digi_scales", scale_factors))
117  jout << "Error loading /START_COUNTER/digi_scales !" << endl;
118  if (scale_factors.find("SC_ADC_ASCALE") != scale_factors.end())
119  a_scale = scale_factors["SC_ADC_ASCALE"];
120  else
121  jerr << "Unable to get SC_ADC_ASCALE from /START_COUNTER/digi_scales !"
122  << endl;
123  // t_scale (SC_ADC_SCALE)
124  if (scale_factors.find("SC_ADC_TSCALE") != scale_factors.end())
125  t_scale = scale_factors["SC_ADC_TSCALE"];
126  else
127  jerr << "Unable to get SC_ADC_TSCALE from /START_COUNTER/digi_scales !"
128  << endl;
129 
130  // load base time offset
131  map<string,double> base_time_offset;
132  // t_base (SC_BASE_TIME_OFFSET)
133  if (eventLoop->GetCalib("/START_COUNTER/base_time_offset",base_time_offset))
134  jout << "Error loading /START_COUNTER/base_time_offset !" << endl;
135  if (base_time_offset.find("SC_BASE_TIME_OFFSET") != base_time_offset.end())
136  t_base = base_time_offset["SC_BASE_TIME_OFFSET"];
137  else
138  jerr << "Unable to get SC_BASE_TIME_OFFSET from /START_COUNTER/base_time_offset !" << endl;
139  // t_tdc_base (SC_TDC_BASE_TIME_OFFSET)
140  if (base_time_offset.find("SC_TDC_BASE_TIME_OFFSET") != base_time_offset.end())
141  t_tdc_base = base_time_offset["SC_TDC_BASE_TIME_OFFSET"];
142  else
143  jerr << "Unable to get SC_BASE_TIME_OFFSET from /START_COUNTER/base_time_offset !" << endl;
144 
145  // load constant tables
146  // a_gains (gains)
147  if (eventLoop->GetCalib("/START_COUNTER/gains", a_gains))
148  jout << "Error loading /START_COUNTER/gains !" << endl;
149  // a_pedestals (pedestals)
150  if (eventLoop->GetCalib("/START_COUNTER/pedestals", a_pedestals))
151  jout << "Error loading /START_COUNTER/pedestals !" << endl;
152  // adc_time_offsets (adc_timing_offsets)
153  if (eventLoop->GetCalib("/START_COUNTER/adc_timing_offsets", adc_time_offsets))
154  jout << "Error loading /START_COUNTER/adc_timing_offsets !" << endl;
155  // tdc_time_offsets (tdc_timing_offsets)
156  if (eventLoop->GetCalib("/START_COUNTER/tdc_timing_offsets", tdc_time_offsets))
157  jout << "Error loading /START_COUNTER/tdc_timing_offsets !" << endl;
158  // timewalk_parameters (timewalk_parms)
159  if(eventLoop->GetCalib("START_COUNTER/timewalk_parms_v2", timewalk_parameters))
160  jout << "Error loading /START_COUNTER/timewalk_parms_v2 !" << endl;
161 
162 
163  return NOERROR;
164 }
165 
166 //------------------
167 // evnt
168 //------------------
169 jerror_t DSCHit_factory::evnt(JEventLoop *loop, uint64_t eventnumber)
170 {
171  /// Generate DSCHit object for each DSCDigiHit object.
172  /// This is where the first set of calibration constants
173  /// is applied to convert from digitzed units into natural
174  /// units.
175  ///
176  /// Note that this code does NOT get called for simulated
177  /// data in HDDM format. The HDDM event source will copy
178  /// the precalibrated values directly into the _data vector.
179 
180  // First, make hits out of all fADC250 hits
181  vector<const DSCDigiHit*> digihits;
182  loop->Get(digihits);
183  sort(digihits.begin(),digihits.end(),DSCHit_fadc_cmp);
184 
185  const DTTabUtilities* locTTabUtilities = nullptr;
186  loop->GetSingle(locTTabUtilities);
187 
188  char str[256];
189  vector<DSCHit *>temp_schits;
190 
191  for (unsigned int i = 0; i < digihits.size(); i++) {
192  const DSCDigiHit *digihit = digihits[i];
193 
194  // Make sure sector is in valid range
195  if( (digihit->sector <= 0) && (digihit->sector > MAX_SECTORS)) {
196  sprintf(str, "DSCDigiHit sector out of range! sector=%d (should be 1-%d)",
197  digihit->sector, MAX_SECTORS);
198  throw JException(str);
199  }
200 
201  // Throw away hits with firmware errors (post-summer 2016 firmware)
202  if(CHECK_FADC_ERRORS && !locTTabUtilities->CheckFADC250_NoErrors(digihit->QF))
203  continue;
204  if (digihit->pulse_time == 0 || digihit->pedestal == 0 || digihit->pulse_peak == 0) continue;
205  // Find the time from the pulse and apply calibration constants
206  double T = (double)digihit->pulse_time;
207  double t_fadc= t_scale * T - adc_time_offsets[digihit->sector-1] + t_base;
208  if (fabs(t_fadc) > HIT_TIME_WINDOW) continue;
209 
210  // Initialize pedestal to one found in CCDB, but override it
211  // with one found in event if is available (?)
212  // For now, only keep events with a correct pedestal
213  double pedestal = a_pedestals[digihit->sector-1];
214  double nsamples_integral = digihit->nsamples_integral;
215  double nsamples_pedestal = digihit->nsamples_pedestal;
216 
217  // nsamples_pedestal should always be positive for valid data - err on the side of caution for now
218  if(nsamples_pedestal == 0) {
219  jerr << "DSCDigiHit with nsamples_pedestal == 0 ! Event = " << eventnumber << endl;
220  continue;
221  }
222 
223  // digihit->pedestal is the sum of "nsamples_pedestal" samples
224  // Calculate the average pedestal per sample
225  if( (digihit->pedestal>0) && locTTabUtilities->CheckFADC250_PedestalOK(digihit->QF) ) {
226  pedestal = (double)digihit->pedestal/nsamples_pedestal;
227  }
228  // Subtract pedestal from pulse peak
229  double pulse_peak = digihit->pulse_peak - pedestal;
230 
231  // Subtract pedestal from pulse integral
232  double A = (double)digihit->pulse_integral;
233  A -= pedestal*nsamples_integral;
234 
235  //if ( ((double)digihit->pulse_integral) < ADC_THRESHOLD) continue; // Will comment out until this is set to something useful by default
236 
237  DSCHit *hit = new DSCHit;
238  // Sectors are numbered from 1-30
239  hit->sector = digihit->sector;
240 
241  hit->dE = a_scale * a_gains[digihit->sector-1] * A;
242  hit->t_fADC = t_fadc;
243  hit->t_TDC = numeric_limits<double>::quiet_NaN();
244 
245  hit->has_TDC = false;
246  hit->has_fADC = true;
247 
248  hit->t = hit->t_fADC; // set time from fADC in case no TDC hit
249  hit->pulse_height = pulse_peak;
250 
251  hit->AddAssociatedObject(digihit);
252 
253  temp_schits.push_back(hit);
254  }
255 
256 
257  // Next, loop over TDC hits, matching them to the
258  // existing fADC hits where possible and updating
259  // their time information. If no match is found, then
260  // create a new hit with just the TDC info.
261  vector<const DSCTDCDigiHit*> tdcdigihits;
262  loop->Get(tdcdigihits);
263  sort(tdcdigihits.begin(),tdcdigihits.end(),DSCHit_tdc_cmp);
264 
265  for (unsigned int i = 0; i < tdcdigihits.size(); i++) {
266  const DSCTDCDigiHit *digihit = tdcdigihits[i];
267 
268  // Make sure sector is in valid range
269  if((digihit->sector <= 0) && (digihit->sector > MAX_SECTORS)) {
270  sprintf(str, "DSCDigiHit sector out of range! sector=%d (should be 1-%d)",
271  digihit->sector, MAX_SECTORS);
272  throw JException(str);
273  }
274 
275  unsigned int id = digihit->sector - 1;
276  double T = locTTabUtilities->Convert_DigiTimeToNs_F1TDC(digihit) - tdc_time_offsets[id] + t_tdc_base;
277 
278  // Look for existing hits to see if there is a match
279  // or create new one if there is no match
280  // Require that the trigger corrected TDC time fall within
281  // a reasonable time window so that when a hit is associated with
282  // a hit in the TDC and not the ADC it is a "decent" TDC hit
283  if (fabs(T) < HIT_TIME_WINDOW) {
284  DSCHit *hit = FindMatch(temp_schits,digihit->sector, T);
285  if (hit == nullptr) {
286  hit = new DSCHit;
287  hit->sector = digihit->sector;
288  hit->dE = 0.0;
289  hit->t_fADC= numeric_limits<double>::quiet_NaN();
290  hit->has_fADC=false;
291  temp_schits.push_back(hit);
292  }
293 
294  hit->has_TDC=true;
295  hit->t_TDC=T;
296 
297  if (USE_TIMEWALK_CORRECTION && (hit->dE > 0.0) ) {
298  // Correct for time walk
299  // The correction is the form t=t_tdc- C1 (A^C2 - A0^C2)
300  // double A = hit->dE;
301  // double C1 = timewalk_parameters[id][1];
302  // double C2 = timewalk_parameters[id][2];
303  // double A0 = timewalk_parameters[id][3];
304  // T -= C1*(pow(A,C2) - pow(A0,C2));
305 
306  // Correct for timewalk using pulse peak instead of pulse integral
307  double A = hit->pulse_height;
308  // double C0 = timewalk_parameters[id][0];
309  double C1 = timewalk_parameters[id][1];
310  double C2 = timewalk_parameters[id][2];
311  double A_THRESH = timewalk_parameters[id][3];
312  double A0 = timewalk_parameters[id][4];
313  // do correction
314  T -= C1*(pow(A/A_THRESH, C2) - pow(A0/A_THRESH, C2));
315  }
316 
317  hit->t=T;
318 
319  hit->AddAssociatedObject(digihit);
320  } // Hit time window cut
321 
322  }
323 
324  for (unsigned int i=0;i<temp_schits.size();i++){
325  if (REQUIRE_ADC_TDC_MATCH==false){
326  _data.push_back(temp_schits[i]);
327  }
328  else if (temp_schits[i]->has_fADC && temp_schits[i]->has_TDC){
329  _data.push_back(temp_schits[i]);
330  }
331  else delete temp_schits[i];
332  }
333 
334 
335 
336 
337  return NOERROR;
338 }
339 
340 //------------------
341 // FindMatch
342 //------------------
343 DSCHit* DSCHit_factory::FindMatch(vector<DSCHit*>&schits,int sector, double T)
344 {
345  DSCHit *best_match = nullptr;
346 
347  // Loop over existing hits (from fADC) and look for a match
348  // in both the sector and the time.
349  for(unsigned int i = 0; i < schits.size(); i++)
350  {
351  DSCHit *hit = schits[i];
352 
353  if (! isfinite(hit->t_fADC))
354  continue; // only match to fADC hits, not bachelor TDC hits
355 
356  if (hit->sector != sector)
357  continue; // require identical sectors fired
358 
359  double delta_T = fabs(hit->t - T);
360  if (delta_T > DELTA_T_ADC_TDC_MAX)
361  continue;
362 
363  if (best_match != nullptr)
364  {
365  if (delta_T < fabs(best_match->t - T))
366  best_match = hit;
367  } else best_match = hit;
368  }
369 
370  return best_match;
371 }
372 
373 //------------------
374 // erun
375 //------------------
376 jerror_t DSCHit_factory::erun(void)
377 {
378  return NOERROR;
379 }
380 
381 //------------------
382 // fini
383 //------------------
384 jerror_t DSCHit_factory::fini(void)
385 {
386  return NOERROR;
387 }
388 
389 
390 //------------------------------------
391 // GetConstant
392 // Allow a few different interfaces
393 //------------------------------------
394 const double DSCHit_factory::GetConstant(const vector<double> &the_table,
395  const int in_sector) const
396 {
397  char str[256];
398 
399  if ( (in_sector < 0) || (in_sector >= MAX_SECTORS))
400  {
401  sprintf(str, "Bad sector # requested in DSCHit_factory::GetConstant()!"
402  " requested=%d , should be %ud", in_sector, MAX_SECTORS);
403  cerr << str << endl;
404  throw JException(str);
405  }
406 
407  return the_table[in_sector];
408 }
409 
410 const double DSCHit_factory::GetConstant(const vector<double> &the_table,
411  const DSCDigiHit *in_digihit) const
412 {
413  char str[256];
414 
415  if ( (in_digihit->sector < 0) || (in_digihit->sector >= MAX_SECTORS))
416  {
417  sprintf(str, "Bad sector # requested in DSCHit_factory::GetConstant()!"
418  " requested=%d , should be %ud",
419  in_digihit->sector, MAX_SECTORS);
420  cerr << str << endl;
421  throw JException(str);
422  }
423 
424  return the_table[in_digihit->sector];
425 }
426 
427 const double DSCHit_factory::GetConstant(const vector<double> &the_table,
428  const DSCHit *in_hit) const
429 {
430 
431  char str[256];
432 
433  if ( (in_hit->sector < 0) || (in_hit->sector >= MAX_SECTORS))
434  {
435  sprintf(str, "Bad sector # requested in DSCHit_factory::GetConstant()!"
436  " requested=%d , should be %ud",
437  in_hit->sector, MAX_SECTORS);
438  cerr << str << endl;
439  throw JException(str);
440  }
441 
442  return the_table[in_hit->sector];
443 }
444 /*
445  const double DSCHit_factory::GetConstant(const vector<double> &the_table,
446  const DTranslationTable *ttab,
447  const int in_rocid,
448  const int in_slot,
449  const int in_channel) const
450  {
451  char str[256];
452 
453  DTranslationTable::csc_t daq_index = { in_rocid, in_slot, in_channel };
454  DTranslationTable::DChannelInfo channel_info = ttab->GetDetectorIndex(daq_index);
455 
456  if( (channel_info.sc.sector <= 0)
457  || (channel_info.sc.sector > static_cast<unsigned int>(MAX_SECTORS))) {
458  sprintf(str, "Bad sector # requested in DSCHit_factory::GetConstant()!"
459  " requested=%d , should be %ud",
460  channel_info.sc.sector, MAX_SECTORS);
461  cerr << str << endl;
462  throw JException(str);
463  }
464 
465  return the_table[channel_info.sc.sector];
466  }
467  */
DApplication * dapp
uint32_t pedestal
pedestal info used by FPGA (if any)
Definition: DSCDigiHit.h:21
bool DSCHit_fadc_cmp(const DSCDigiHit *a, const DSCDigiHit *b)
#define A0
Definition: src/md5.cpp:22
if(locHist_BCALShowerPhiVsZ!=NULL)
jerror_t erun(void)
Called everytime run number changes, provided brun has been called.
float pulse_height
Definition: DSCHit.h:23
char str[256]
bool has_TDC
Definition: DSCHit.h:25
int sector
sector number 1-24
Definition: DSCTDCDigiHit.h:19
uint32_t QF
Quality Factor from FPGA algorithms.
Definition: DSCDigiHit.h:22
sprintf(text,"Post KinFit Cut")
const double GetConstant(const vector< double > &the_table, const int in_sector) const
DSCHit * FindMatch(vector< DSCHit * > &schits, int sector, double T)
jerror_t evnt(jana::JEventLoop *eventLoop, uint64_t eventnumber)
Called every event.
jerror_t init(void)
Called once at program start.
uint32_t pulse_integral
identified pulse integral as returned by FPGA algorithm
Definition: DSCDigiHit.h:19
bool DSCHit_tdc_cmp(const DSCTDCDigiHit *a, const DSCTDCDigiHit *b)
int sector
Definition: DSCHit.h:18
uint32_t time
Definition: DSCTDCDigiHit.h:21
Definition: DSCHit.h:14
uint32_t nsamples_integral
number of samples used in integral
Definition: DSCDigiHit.h:23
jerror_t fini(void)
Called after last event of last event source has been processed.
DGeometry * GetDGeometry(unsigned int run_number)
float t_fADC
Definition: DSCHit.h:22
float t_TDC
Definition: DSCHit.h:21
int sector
Definition: DSCDigiHit.h:18
uint32_t pulse_time
identified pulse time as returned by FPGA algorithm
Definition: DSCDigiHit.h:20
vector< double > a_pedestals
vector< double > tdc_time_offsets
uint32_t nsamples_pedestal
number of samples used in pedestal
Definition: DSCDigiHit.h:24
float dE
Definition: DSCHit.h:19
static TH1I * pedestal[nChan]
uint32_t pulse_peak
maximum sample in pulse
Definition: DSCDigiHit.h:25
bool has_fADC
Definition: DSCHit.h:24
float t
Definition: DSCHit.h:20
vector< double > adc_time_offsets
bool GetStartCounterGeom(vector< vector< DVector3 > > &pos, vector< vector< DVector3 > > &norm) const
Definition: DGeometry.cc:1983
jerror_t brun(jana::JEventLoop *eventLoop, int32_t runnumber)
Called everytime a new run number is detected.