Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DFCALHit_factory.cc
Go to the documentation of this file.
1 // $Id$
2 //
3 // File: DFCALHit_factory.cc
4 // Created: Tue Aug 6 12:23:43 EDT 2013
5 // Creator: davidl (on Darwin harriet.jlab.org 11.4.2 i386)
6 //
7 
8 
9 #include <iostream>
10 #include <iomanip>
11 using namespace std;
12 
13 #include "FCAL/DFCALDigiHit.h"
14 #include "FCAL/DFCALGeometry.h"
15 #include "FCAL/DFCALHit_factory.h"
16 #include "DAQ/Df250PulseIntegral.h"
17 #include "DAQ/Df250PulsePedestal.h"
18 #include "DAQ/Df250Config.h"
19 #include "TTAB/DTTabUtilities.h"
20 using namespace jana;
21 
22 //------------------
23 // init
24 //------------------
25 jerror_t DFCALHit_factory::init(void)
26 {
27  // initialize calibration tables
28  vector< vector<double > > new_gains(DFCALGeometry::kBlocksTall,
29  vector<double>(DFCALGeometry::kBlocksWide));
30  vector< vector<double > > new_pedestals(DFCALGeometry::kBlocksTall,
31  vector<double>(DFCALGeometry::kBlocksWide));
32  vector< vector<double > > new_t0s(DFCALGeometry::kBlocksTall,
33  vector<double>(DFCALGeometry::kBlocksWide));
34  vector< vector<double > > new_qualities(DFCALGeometry::kBlocksTall,
35  vector<double>(DFCALGeometry::kBlocksWide));
36  // Get ADC offsets
37  vector< vector<double > > ADC_offsets(DFCALGeometry::kBlocksTall,
38  vector<double>(DFCALGeometry::kBlocksWide));
39 
40  gains = new_gains;
41  pedestals = new_pedestals;
42  time_offsets = new_t0s;
43  block_qualities = new_qualities;
44  ADC_Offsets = ADC_offsets;
45 
46  // set the base conversion scales --
47  // a_scale should definitely come from
48  // the DB so set it to a value that will
49  // be noticeably wrong
50  a_scale = 0.0; // GeV/FADC integral unit
51  t_scale = 0.0625; // 62.5 ps/count
52  t_base = 0.; // ns
53 
54  CHECK_FADC_ERRORS = true;
55  gPARMS->SetDefaultParameter("FCAL:CHECK_FADC_ERRORS", CHECK_FADC_ERRORS, "Set to 1 to reject hits with fADC250 errors, ser to 0 to keep these hits");
56 
57  return NOERROR;
58 }
59 
60 //------------------
61 // brun
62 //------------------
63 jerror_t DFCALHit_factory::brun(jana::JEventLoop *eventLoop, int32_t runnumber)
64 {
65  // Only print messages for one thread whenever run number change
66  static pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER;
67  static set<int> runs_announced;
68  pthread_mutex_lock(&print_mutex);
69  bool print_messages = false;
70  if(runs_announced.find(runnumber) == runs_announced.end()){
71  print_messages = true;
72  runs_announced.insert(runnumber);
73  }
74  pthread_mutex_unlock(&print_mutex);
75 
76  // extract the FCAL Geometry
77  vector<const DFCALGeometry*> fcalGeomVect;
78  eventLoop->Get( fcalGeomVect );
79  if (fcalGeomVect.size() < 1)
80  return OBJECT_NOT_AVAILABLE;
81  const DFCALGeometry& fcalGeom = *(fcalGeomVect[0]);
82 
83  /// Read in calibration constants
84  vector< double > raw_gains;
85  vector< double > raw_pedestals;
86  vector< double > raw_time_offsets;
87  vector< double > raw_block_qualities; // we should change this to an int?
88  vector< double > raw_ADCoffsets;
89 
90  if(print_messages) jout << "In DFCALHit_factory, loading constants..." << endl;
91 
92  // load scale factors
93  map<string,double> scale_factors;
94  if (eventLoop->GetCalib("/FCAL/digi_scales", scale_factors))
95  jout << "Error loading /FCAL/digi_scales !" << endl;
96  if (scale_factors.find("FCAL_ADC_ASCALE") != scale_factors.end())
97  a_scale = scale_factors["FCAL_ADC_ASCALE"];
98  else
99  jerr << "Unable to get FCAL_ADC_ASCALE from /FCAL/digi_scales !" << endl;
100  if (scale_factors.find("FCAL_ADC_TSCALE") != scale_factors.end())
101  t_scale = scale_factors["FCAL_ADC_TSCALE"];
102  else
103  jerr << "Unable to get FCAL_ADC_TSCALE from /FCAL/digi_scales !" << endl;
104 
105  // load base time offset
106  map<string,double> base_time_offset;
107  if (eventLoop->GetCalib("/FCAL/base_time_offset",base_time_offset))
108  jout << "Error loading /FCAL/base_time_offset !" << endl;
109  if (base_time_offset.find("FCAL_BASE_TIME_OFFSET") != base_time_offset.end())
110  t_base = base_time_offset["FCAL_BASE_TIME_OFFSET"];
111  else
112  jerr << "Unable to get FCAL_BASE_TIME_OFFSET from /FCAL/base_time_offset !" << endl;
113 
114  // load constant tables
115  if (eventLoop->GetCalib("/FCAL/gains", raw_gains))
116  jout << "Error loading /FCAL/gains !" << endl;
117  if (eventLoop->GetCalib("/FCAL/pedestals", raw_pedestals))
118  jout << "Error loading /FCAL/pedestals !" << endl;
119  if (eventLoop->GetCalib("/FCAL/timing_offsets", raw_time_offsets))
120  jout << "Error loading /FCAL/timing_offsets !" << endl;
121  if (eventLoop->GetCalib("/FCAL/block_quality", raw_block_qualities))
122  jout << "Error loading /FCAL/block_quality !" << endl;
123  if (eventLoop->GetCalib("/FCAL/ADC_Offsets", raw_ADCoffsets))
124  jout << "Error loading /FCAL/ADC_Offsets !" << endl;
125 
126  FillCalibTable(gains, raw_gains, fcalGeom);
127  FillCalibTable(pedestals, raw_pedestals, fcalGeom);
128  FillCalibTable(time_offsets, raw_time_offsets, fcalGeom);
129  FillCalibTable(block_qualities, raw_block_qualities, fcalGeom);
130  FillCalibTable(ADC_Offsets, raw_ADCoffsets, fcalGeom);
131 
132  return NOERROR;
133 }
134 
135 //------------------
136 // evnt
137 //------------------
138 jerror_t DFCALHit_factory::evnt(JEventLoop *loop, uint64_t eventnumber)
139 {
140  /// Generate DFCALHit object for each DFCALDigiHit object.
141  /// This is where the first set of calibration constants
142  /// is applied to convert from digitzed units into natural
143  /// units.
144  ///
145  /// Note that this code does NOT get called for simulated
146  /// data in HDDM format. The HDDM event source will copy
147  /// the precalibrated values directly into the _data vector.
148  char str[256];
149 
150  // extract the FCAL Geometry (for positionOnFace())
151  vector<const DFCALGeometry*> fcalGeomVect;
152  eventLoop->Get( fcalGeomVect );
153  if (fcalGeomVect.size() < 1)
154  return OBJECT_NOT_AVAILABLE;
155  const DFCALGeometry& fcalGeom = *(fcalGeomVect[0]);
156 
157  const DTTabUtilities* locTTabUtilities = nullptr;
158  loop->GetSingle(locTTabUtilities);
159 
160  vector<const DFCALDigiHit*> digihits;
161  loop->Get(digihits);
162  for (unsigned int i=0; i < digihits.size(); i++) {
163 
164  const DFCALDigiHit *digihit = digihits[i];
165 
166  // Throw away hits with firmware errors (post-summer 2016 firmware)
167  if(CHECK_FADC_ERRORS && !locTTabUtilities->CheckFADC250_NoErrors(digihit->QF))
168  continue;
169 
170  // Check to see if the hit corresponds to a valid channel
171  if (fcalGeom.isBlockActive(digihit->row,digihit->column) == false) {
172  sprintf(str, "DFCALHit corresponds to inactive channel! "
173  "row=%d, col=%d",
174  digihit->row, digihit->column);
175  throw JException(str);
176  }
177 
178  // throw away hits from bad or noisy channels
179  fcal_quality_state quality =
180  static_cast<fcal_quality_state>(block_qualities[digihit->row][digihit->column]);
181  if ( (quality==BAD) || (quality==NOISY) ) continue;
182 
183  // get pedestal from CCDB -- we should use it instead
184  // of the event-by-event pedestal
185  // Corresponds to the value of the pedestal for a single sample
186  double pedestal = pedestals[digihit->row][digihit->column];
187 
188  // we should use the fixed database pedestal
189  // object as it is less susceptible to noise
190  // than the event-by-event pedestal
191  double nsamples_integral = digihit->nsamples_integral;
192  double nsamples_pedestal = digihit->nsamples_pedestal;
193 
194  // if the database pedestal is zero then try
195  // the event-by-event one:
196  if(pedestal == 0) {
197  // nsamples_pedestal should always be positive for valid data - err on the side of caution for now
198  if(nsamples_pedestal == 0) {
199  jerr << "DFCALDigiHit with nsamples_pedestal == 0 ! Event = " << eventnumber << endl;
200  continue;
201  }
202 
203  // digihit->pedestal is the sum of "nsamples_pedestal" samples
204  // Calculate the average pedestal per sample
205  if( (digihit->pedestal>0) && locTTabUtilities->CheckFADC250_PedestalOK(digihit->QF) ) {
206  pedestal = (double)digihit->pedestal/nsamples_pedestal;
207  }
208  }
209 
210  // Subtract pedestal from pulse peak
211  if (digihit->pulse_time == 0 || digihit->pedestal == 0 || digihit->pulse_peak == 0) continue;
212  double pulse_amplitude = digihit->pulse_peak - pedestal;
213 
214  double integratedPedestal = pedestal * nsamples_integral;
215 
216  // Build hit object
217  DFCALHit *hit = new DFCALHit;
218  hit->row = digihit->row;
219  hit->column = digihit->column;
220 
221  // Apply calibration constants
222  double A = (double)digihit->pulse_integral;
223  double T = (double)digihit->pulse_time;
224  hit->E = a_scale * gains[hit->row][hit->column] * (A - integratedPedestal);
225  hit->t = t_scale * T - time_offsets[hit->row][hit->column] + t_base + ADC_Offsets[hit->row][hit->column];;
226 
227  // Get position of blocks on front face. (This should really come from
228  // hdgeant directly so the poisitions can be shifted in mcsmear.)
229  DVector2 pos = fcalGeom.positionOnFace(hit->row, hit->column);
230  hit->x = pos.X();
231  hit->y = pos.Y();
232 
233  // recored the pulse integral to peak ratio since this is
234  // a useful quality metric for the PMT pulse
235  hit->intOverPeak = ( A - integratedPedestal ) / pulse_amplitude;
236 
237  // do some basic quality checks before creating the objects
238  if( ( hit->E > 0 ) &&
239  ( digihit->pulse_time > 0 ) ) {
240  hit->AddAssociatedObject(digihit);
241  _data.push_back(hit);
242  } else {
243  delete hit;
244  }
245  }
246 
247  return NOERROR;
248 }
249 
250 //------------------
251 // erun
252 //------------------
254 {
255  return NOERROR;
256 }
257 
258 //------------------
259 // fini
260 //------------------
262 {
263  return NOERROR;
264 }
265 
266 //------------------
267 // FillCalibTable
268 //------------------
270  const vector<double> &raw_table,
271  const DFCALGeometry &fcalGeom)
272 {
273  char str[256];
274 
275  // sanity check that we have the right geometry
276  // (deprecate this?)
277  if (fcalGeom.numActiveBlocks() != FCAL_MAX_CHANNELS) {
278  sprintf(str, "FCAL geometry is wrong size! channels=%d (should be %d)",
279  fcalGeom.numActiveBlocks(), FCAL_MAX_CHANNELS);
280  throw JException(str);
281  }
282 
283  // check to see if the table is the right size
284  if ( fcalGeom.numActiveBlocks() != static_cast<int>(raw_table.size()) ) {
285  sprintf(str, "FCAL constant table is wrong size! channels=%d (should be %d)",
286  fcalGeom.numActiveBlocks(), static_cast<int>(raw_table.size()));
287  throw JException(str);
288  }
289 
290  for (int channel=0; channel < static_cast<int>(raw_table.size()); channel++)
291  {
292  // make sure that we don't try to load info for channels that don't exist
293  if (channel == fcalGeom.numActiveBlocks())
294  break;
295 
296  int row = fcalGeom.row(channel);
297  int col = fcalGeom.column(channel);
298 
299  // results from DFCALGeometry should be self consistent, but add in some
300  // sanity checking just to be sure
301  if (fcalGeom.isBlockActive(row,col) == false) {
302  sprintf(str, "Loading FCAL constant for inactive channel! "
303  "row=%d, col=%d", row, col);
304  throw JException(str);
305  }
306 
307  table[row][col] = raw_table[channel];
308  }
309 }
310 
311 //------------------------------------
312 // GetConstant
313 // Allow a few different interfaces
314 //------------------------------------
316  const int in_row,
317  const int in_column) const
318 {
319  char str[256];
320 
321  if ( (in_row <= 0) || (in_row > DFCALGeometry::kBlocksTall)) {
322  sprintf(str, "Bad row # requested in DFCALHit_factory::GetConstant()!"
323  " requested=%d , should be %ud", in_row, DFCALGeometry::kBlocksTall);
324  cerr << str << endl;
325  throw JException(str);
326  }
327  if ( (in_column <= 0) || (in_column > DFCALGeometry::kBlocksWide)) {
328  sprintf(str, "Bad column # requested in DFCALHit_factory::GetConstant()!"
329  " requested=%d , should be %ud", in_column, DFCALGeometry::kBlocksWide);
330  cerr << str << endl;
331  throw JException(str);
332  }
333 
334  return the_table[in_row][in_column];
335 }
336 
338  const DFCALDigiHit *in_digihit) const
339 {
340  char str[256];
341 
342  if ( (in_digihit->row <= 0) || (in_digihit->row > DFCALGeometry::kBlocksTall)) {
343  sprintf(str, "Bad row # requested in DFCALHit_factory::GetConstant()!"
344  " requested=%d , should be %ud",
345  in_digihit->row, DFCALGeometry::kBlocksTall);
346  cerr << str << endl;
347  throw JException(str);
348  }
349  if ( (in_digihit->column <= 0) || (in_digihit->column > DFCALGeometry::kBlocksWide)) {
350  sprintf(str, "Bad column # requested in DFCALHit_factory::GetConstant()!"
351  " requested=%d , should be %ud",
352  in_digihit->column, DFCALGeometry::kBlocksWide);
353  cerr << str << endl;
354  throw JException(str);
355  }
356 
357  return the_table[in_digihit->row][in_digihit->column];
358 }
359 
361  const DFCALHit *in_hit) const {
362 
363  char str[256];
364 
365  if ( (in_hit->row <= 0) || (in_hit->row > DFCALGeometry::kBlocksTall)) {
366  sprintf(str, "Bad row # requested in DFCALHit_factory::GetConstant()! "
367  "requested=%d , should be %ud", in_hit->row, DFCALGeometry::kBlocksTall);
368  cerr << str << endl;
369  throw JException(str);
370  }
371  if ( (in_hit->column <= 0) || (in_hit->column > DFCALGeometry::kBlocksWide)) {
372  sprintf(str, "Bad column # requested in DFCALHit_factory::GetConstant()!"
373  " requested=%d , should be %ud",
375  cerr << str << endl;
376  throw JException(str);
377  }
378 
379  return the_table[in_hit->row][in_hit->column];
380 }
381 /*
382  const double DFCALHit_factory::GetConstant(const fcal_digi_constants_t &the_table,
383  const DTranslationTable *ttab,
384  const int in_rocid,
385  const int in_slot,
386  const int in_channel) const
387  {
388  char str[256];
389 
390  DTranslationTable::csc_t daq_index = { in_rocid, in_slot, in_channel };
391  DTranslationTable::DChannelInfo channel_info = ttab->GetDetectorIndex(daq_index);
392 
393  if ( (channel_info.fcal.row <= 0)
394  || (channel_info.fcal.row > static_cast<unsigned int>(DFCALGeometry::kBlocksTall))) {
395  sprintf(str, "Bad row # requested in DFCALHit_factory::GetConstant()!"
396  " requested=%d , should be %ud",
397  channel_info.fcal.row, DFCALGeometry::kBlocksTall);
398  cerr << str << endl;
399  throw JException(str);
400  }
401  if ( (channel_info.fcal.col <= 0)
402  || (channel_info.fcal.col > static_cast<unsigned int>(DFCALGeometry::kBlocksWide))) {
403  sprintf(str, "Bad column # requested in DFCALHit_factory::GetConstant()!"
404  " requested=%d , should be %ud",
405  channel_info.fcal.row, DFCALGeometry::kBlocksWide);
406  cerr << str << endl;
407  throw JException(str);
408  }
409 
410  return the_table[channel_info.fcal.row][channel_info.fcal.col];
411  }
412  */
uint32_t QF
Quality Factor from FPGA algorithms.
Definition: DFCALDigiHit.h:23
jerror_t fini(void)
Called after last event of last event source has been processed.
vector< vector< double > > fcal_digi_constants_t
const double GetConstant(const fcal_digi_constants_t &the_table, const int in_row, const int in_column) const
bool CheckFADC250_NoErrors(uint32_t QF) const
char str[256]
TVector2 DVector2
Definition: DVector2.h:9
uint32_t pulse_peak
maximum sample in pulse
Definition: DFCALDigiHit.h:26
uint32_t nsamples_integral
number of samples used in integral
Definition: DFCALDigiHit.h:24
sprintf(text,"Post KinFit Cut")
uint32_t pulse_time
identified pulse time as returned by FPGA algorithm
Definition: DFCALDigiHit.h:21
DVector2 positionOnFace(int row, int column) const
uint32_t pedestal
pedestal info used by FPGA (if any)
Definition: DFCALDigiHit.h:22
int row
Definition: DFCALHit.h:23
uint32_t pulse_integral
identified pulse integral as returned by FPGA algorithm
Definition: DFCALDigiHit.h:20
jerror_t erun(void)
Called everytime run number changes, provided brun has been called.
uint32_t nsamples_pedestal
number of samples used in pedestal
Definition: DFCALDigiHit.h:25
float y
Definition: DFCALHit.h:26
int column(int channel) const
Definition: DFCALGeometry.h:65
jerror_t brun(jana::JEventLoop *eventLoop, int32_t runnumber)
Called everytime a new run number is detected.
bool CheckFADC250_PedestalOK(uint32_t QF) const
void FillCalibTable(fcal_digi_constants_t &table, const vector< double > &raw_table, const DFCALGeometry &fcalGeom)
jerror_t evnt(jana::JEventLoop *eventLoop, uint64_t eventnumber)
Called every event.
static TH1I * pedestal[nChan]
jerror_t init(void)
Called once at program start.2.
int row(int channel) const
Definition: DFCALGeometry.h:64
float x
Definition: DFCALHit.h:25
float E
Definition: DFCALHit.h:27
bool isBlockActive(int row, int column) const
float t
Definition: DFCALHit.h:28
int column
Definition: DFCALHit.h:24
float intOverPeak
Definition: DFCALHit.h:29
int numActiveBlocks() const
Definition: DFCALGeometry.h:56