Belle II Software  release-05-02-19
CDCDigitizerModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2012 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Guofu Cao, Martin Heck, CDC group *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <cdc/modules/cdcDigitizer/CDCDigitizerModule.h>
12 #include <cdc/utilities/ClosestApproach.h>
13 
14 #include <framework/datastore/RelationArray.h>
15 //#include <framework/datastore/RelationIndex.h>
16 #include <framework/gearbox/Unit.h>
17 #include <framework/logging/Logger.h>
18 
19 #include <TRandom.h>
20 #include <map>
21 #include <utility>
22 
23 using namespace std;
24 using namespace Belle2;
25 using namespace CDC;
26 
27 
28 // register module
29 REG_MODULE(CDCDigitizer)
31  m_cdcgp(), m_gcp(), m_aCDCSimHit(), m_posFlag(0),
32  m_driftLength(0.0), m_flightTime(0.0), m_globalTime(0.0),
33  m_tdcBinWidth(1.0), m_tdcBinWidthInv(1.0),
34  m_tdcResol(0.9825), m_driftV(4.0e-3),
35  m_driftVInv(250.0), m_propSpeedInv(27.25), m_align(true)
36 {
37  // Set description
38  setDescription("Creates CDCHits from CDCSimHits.");
39  setPropertyFlags(c_ParallelProcessingCertified);
40 
41  // Add parameters
42  // I/O
43  addParam("InputCDCSimHitsName", m_inputCDCSimHitsName, "Name of input array. Should consist of CDCSimHits.", string(""));
44  addParam("OutputCDCHitsName", m_outputCDCHitsName, "Name of output array. Will consist of CDCHits.", string(""));
45  addParam("OutputCDCHitsName4Trg", m_outputCDCHitsName4Trg,
46  "Name of output array for trigger. Can contain several hits per wire, "
47  "if they correspond to different time windows of 32ns.",
48  string("CDCHits4Trg"));
49 
50  //Relations
51  addParam("MCParticlesToCDCSimHitsName", m_MCParticlesToSimHitsName,
52  "Name of relation between MCParticles and CDCSimHits used", string(""));
53  addParam("CDCSimHistToCDCHitsName", m_SimHitsTOCDCHitsName,
54  "Name of relation between the CDCSimHits and the CDCHits used", string(""));
55 
56 
57  //Parameters for Digitization
58  addParam("UseSimpleDigitization", m_useSimpleDigitization,
59  "If true, a simple x-t with a constant velocity is used for the drift-length to -time conversion", false);
60 
61  //float Gauss Parameters
62  addParam("Fraction", m_fraction, "Fraction of first Gaussian used to smear drift length in cm", 1.0);
63  addParam("Mean1", m_mean1, "Mean value of first Gaussian used to smear drift length in cm", 0.0000);
64  addParam("Resolution1", m_resolution1, "Resolution of first Gaussian used to smear drift length in cm", 0.0130);
65  addParam("Mean2", m_mean2, "Mean value of second Gaussian used to smear drift length in cm", 0.0000);
66  addParam("Resolution2", m_resolution2, "Resolution of second Gaussian used to smear drift length in cm", 0.0000);
67 
68  //Switch to control smearing
69  addParam("DoSmearing", m_doSmearing,
70  "If false, drift length will not be smeared.", true);
71 
72  addParam("TrigTimeJitter", m_trigTimeJitter,
73  "Magnitude (w) of trigger timing jitter (ns). The trigger timing is randuminzed uniformly in a time window of [-w/2, +w/2].",
74  0.);
75  //Switches to control time information handling
76  addParam("AddTimeWalk", m_addTimeWalk, "A switch for time-walk (pulse-heght dep. delay); true: on; false: off", true);
77  addParam("AddInWirePropagationDelay", m_addInWirePropagationDelay,
78  "A switch used to control adding propagation delay in the wire into the final drift time or not; this is for signal hits.", true);
79  addParam("AddInWirePropagationDelay4Bg", m_addInWirePropagationDelay4Bg,
80  "The same switch but for beam bg. hits.", true);
81  addParam("AddTimeOfFlight", m_addTimeOfFlight,
82  "A switch used to control adding time of flight into the final drift time or not; this is for signal hits.", true);
83  addParam("AddTimeOfFlight4Bg", m_addTimeOfFlight4Bg,
84  "The same switch but for beam bg. hits.", true);
85  addParam("OutputNegativeDriftTime", m_outputNegativeDriftTime, "Output hits with negative drift time", true);
86  addParam("Output2ndHit", m_output2ndHit,
87  "Output the 2nd hit if exists in the time window. Note that it is not well-simulated at all, partly because no cross-talk betw. channels is simulated.",
88  false);
89  //Switch to control sense wire sag
90  addParam("CorrectForWireSag", m_correctForWireSag,
91  "A switch for sense wire sag effect; true: drift-time is calculated with the sag taken into account; false: not. Here, sag means the perturbative part which corresponds to alignment in case of wire-position. The main part (corresponding to design+displacement in wire-position) is taken into account in FullSim; you can control it via CDCJobCntlParModifier.",
92  true);
93  //Switch for negative-t0 wires
94  addParam("TreatNegT0WiresAsGood", m_treatNegT0WiresAsGood, "Treat wires with negative t0 (calibrated) as good wire4s.", true);
95 
96  //Threshold
97  addParam("TDCThreshold4Outer", m_tdcThreshold4Outer,
98  "TDC threshold (dE in eV) for Layers#8-56. The value corresponds to He-C2H6 gas; for the gas+wire (MaterialDefinitionMode=0) case, (this value)*f will be used, where f is specified by GasToGasWire",
99  25.0);
100  addParam("TDCThreshold4Inner", m_tdcThreshold4Inner,
101  "Same as TDCThreshold4Outer but for Layers#0-7,", 25.0);
102  addParam("GasToGasWire", m_gasToGasWire,
103  "(Approximate) ratio of dE in He/C2H6-gas to dE in gas+wire, where dE is energy deposit.", 1. / 1.478);
104 
105  //ADC Threshold
106  addParam("ADCThreshold", m_adcThreshold,
107  "Threshold for ADC-count (in unit of count). ADC-count < threshold is treated as count=0.", 2);
108  addParam("tMin", m_tMin, "Lower edge of time window in ns", -100.);
109  addParam("tMaxOuter", m_tMaxOuter, "Upper edge of time window in ns for the normal-cell layers", 500.);
110  addParam("tMaxInner", m_tMaxInner, "Upper edge of time window in ns for the small-cell layers", 300.);
111  // The following doesn't make any sense. The only reasonable steerable would be a switch to decide if the jitter shall be
112  // activated. Then there has to be event by event jitter.
113  /* addParam("EventTime", m_eventTime,
114  "It is a timing of event, which includes a time jitter due to the trigger system, set in ns", float(0.0));*/
115 
116  //Switch for database
117  addParam("UseDB4FEE", m_useDB4FEE, "Fetch and use FEE params. from database or not", true);
118  addParam("UseDB4EDepToADC", m_useDB4EDepToADC, "Uuse edep-to-ADC conversion params. from database or not", true);
119  addParam("UseDB4RunGain", m_useDB4RunGain, "Fetch and use run gain from database or not", true);
120  addParam("OverallGainFactor", m_overallGainFactor, "Overall gain factor for adjustment", 1.0);
121 
122  //Some FEE params.
123  addParam("TDCThresholdOffset", m_tdcThresholdOffset, "Offset for TDC (digital) threshold (mV)", 3820.);
124  addParam("AnalogGain", m_analogGain, "Analog gain (V/pC)", 1.1);
125  addParam("DigitalGain", m_digitalGain, "Digital gain (V/pC)", 15.);
126  addParam("ADCBinWidth", m_adcBinWidth, "ADC bin width (mV)", 2.);
127 
128  addParam("AddFudgeFactorForSigma", m_addFudgeFactorForSigma,
129  "Additional fudge factor for space resol. (common to all cells)", 1.);
130  addParam("SpaceChargeEffect", m_spaceChargeEffect, "Switch for space charge effect", true);
131 
132  addParam("AddXTalk", m_addXTalk, "A switch for crosstalk; true: on; false: off", true);
133  addParam("Issue2ndHitWarning", m_issue2ndHitWarning, "=true: issue a warning when a 2nd TDC hit is found.", true);
134  addParam("IncludeEarlyXTalks", m_includeEarlyXTalks, "=true: include earlier x-talks as well than the signal hit in question.",
135  true);
136  addParam("DebugLevel4XTalk", m_debugLevel4XTalk, "Debug level fr crosstalk; 20-29 are usable.", 20);
137 
138 
139 #if defined(CDC_DEBUG)
140  cout << " " << endl;
141  cout << "CDCDigitizer constructor" << endl;
142 #endif
143 }
144 
145 void CDCDigitizerModule::initialize()
146 {
147  m_simHits.isRequired(m_inputCDCSimHitsName);
148 
149  // Register the arrays in the DataStore, that are to be added in this module.
150  m_cdcHits.registerInDataStore(m_outputCDCHitsName);
151  m_simHits.registerRelationTo(m_cdcHits);
152  m_mcParticles.registerRelationTo(m_cdcHits);
153  // Arrays for trigger.
154  m_cdcHits4Trg.registerInDataStore(m_outputCDCHitsName4Trg);
155  m_simHits.registerRelationTo(m_cdcHits4Trg);
156  m_mcParticles.registerRelationTo(m_cdcHits4Trg);
157 
158  m_cdcgp = &(CDCGeometryPar::Instance());
159  CDCGeometryPar& cdcgp = *m_cdcgp;
160  m_tdcBinWidth = cdcgp.getTdcBinWidth();
161  m_tdcBinWidthInv = 1. / m_tdcBinWidth;
162  m_tdcResol = m_tdcBinWidth / sqrt(12.);
163  m_driftV = cdcgp.getNominalDriftV();
164  m_driftVInv = 1. / m_driftV;
165  m_propSpeedInv = 1. / cdcgp.getNominalPropSpeed();
166  m_scaleFac = 1.;
167  if (m_cdcgp->getMaterialDefinitionMode() == 0) { //gas+wire mode
168  m_scaleFac = m_gasToGasWire;
169  }
170  m_scaleFac *= Unit::GeV;
171  m_gcp = &(CDCGeoControlPar::getInstance());
172  m_totalFudgeFactor = m_cdcgp->getFudgeFactorForSigma(2);
173  m_totalFudgeFactor *= m_addFudgeFactorForSigma;
174  B2DEBUG(29, "totalFugeF in Digi= " << m_totalFudgeFactor);
175  /*
176  m_fraction = 1.0;
177  m_resolution1 = cdcgp.getNominalSpaceResol();
178  m_resolution2 = 0.;
179  m_mean1 = 0.;
180  m_mean2 = 0.;
181  */
182 
183  if (m_useDB4FEE) {
184  m_fEElectronicsFromDB = new DBArray<CDCFEElectronics>;
185  if ((*m_fEElectronicsFromDB).isValid()) {
186  (*m_fEElectronicsFromDB).addCallback(this, &CDCDigitizerModule::setFEElectronics);
187  setFEElectronics();
188  } else {
189  B2FATAL("CDCDigitizer:: CDCFEElectronics not valid !");
190  }
191  }
192 
193  /*
194  if (m_useDB4EDepToADC) {
195  m_eDepToADCConversionsFromDB = new DBObjPtr<CDCEDepToADCConversions>;
196  if ((*m_eDepToADCConversionsFromDB).isValid()) {
197  (*m_eDepToADCConversionsFromDB).addCallback(this, &CDCDigitizerModule::setEDepToADCConversions);
198  setEDepToADCConversions();
199  } else {
200  B2FATAL("CDCDigitizer:: CDCEDepToADCConversions not valid !");
201  }
202  }
203  */
204 
205  if (m_useDB4RunGain) {
206  m_runGainFromDB = new DBObjPtr<CDCDedxRunGain>;
207  if ((*m_runGainFromDB).isValid()) {
208  (*m_runGainFromDB).addCallback(this, &CDCDigitizerModule::setRunGain);
209  setRunGain();
210  } else {
211  B2FATAL("CDCDedxRunGain invalid!");
212  }
213  }
214  B2DEBUG(29, "run-gain = " << m_runGain);
215 
216  if (m_addXTalk) {
217  m_xTalkFromDB = new DBObjPtr<CDCCrossTalkLibrary>;
218  if ((*m_xTalkFromDB).isValid()) {
219  } else {
220  B2FATAL("CDCCrossTalkLibrary invalid!");
221  }
222  }
223 
224 #if defined(CDC_DEBUG)
225  cout << " " << endl;
226  cout << "CDCDigitizer initialize" << endl;
227  // cout << "m_tdcOffset= " << m_tdcOffset << endl;
228  cout << "m_tdcBinWidth= " << m_tdcBinWidth << endl;
229  cout << "m_tdcResol= " << m_tdcResol << endl;
230  cout << "m_driftV= " << m_driftV << endl;
231  cout << "m_driftVInv= " << m_driftVInv << endl;
232  cout << "m_propSpeedInv= " << m_propSpeedInv << endl;
233  /*
234  cout << "m_fraction= " << m_fraction << endl;
235  cout << "m_resolution1= " << m_resolution1 << endl;
236  cout << "m_resolution2= " << m_resolution2 << endl;
237  cout << "m_mean1= " << m_mean1 << endl;
238  cout << "m_mean2= " << m_mean2 << endl;
239  */
240 #endif
241 
242  if (m_useDB4EDepToADC) {
243  if (m_cdcgp->getEDepToADCMainFactor(0, 0) == 0.) {
244  B2FATAL("CDCEDepToADCConversion payloads are unavailable!");
245  }
246  }
247 
248 }
249 
250 void CDCDigitizerModule::event()
251 {
252  // Get SimHit array, MCParticle array, and relation between the two.
253  RelationArray mcParticlesToCDCSimHits(m_mcParticles, m_simHits); //RelationArray created by CDC SensitiveDetector
254 
255 
256  //--- Start Digitization --------------------------------------------------------------------------------------------
257  // Merge the hits in the same cell and save them into CDC signal map.
258 
259  // Define signal map
260  map<WireID, SignalInfo> signalMap;
261  map<WireID, SignalInfo>::iterator iterSignalMap;
262  // Define adc map
263  map<WireID, unsigned short> adcMap;
264  map<WireID, unsigned short>::iterator iterADCMap;
265  // map<WireID, double> adcMap;
266  // map<WireID, double>::iterator iterADCMap;
267 
268  // signal map for trigger
269  map<pair<WireID, unsigned>, SignalInfo> signalMapTrg;
270  map<pair<WireID, unsigned>, SignalInfo>::iterator iterSignalMapTrg;
271 
272  // Set trigger timing jitter for this event
273  double trigTiming = m_trigTimeJitter == 0. ? 0. : m_trigTimeJitter * (gRandom->Uniform() - 0.5);
274  // std::cout << "trigTiming= " << trigTiming << std::endl;
275  // Loop over all hits
276  int nHits = m_simHits.getEntries();
277  B2DEBUG(29, "Number of CDCSimHits in the current event: " << nHits);
278  for (int iHits = 0; iHits < nHits; ++iHits) {
279  // Get a hit
280  m_aCDCSimHit = m_simHits[iHits];
281 
282  // Hit geom. info
283  m_wireID = m_aCDCSimHit->getWireID();
284  // B2DEBUG(29, "Encoded wire number of current CDCSimHit: " << m_wireID);
285 
286  m_posFlag = m_aCDCSimHit->getLeftRightPassageRaw();
287  m_boardID = m_cdcgp->getBoardID(m_wireID);
288  // B2DEBUG(29, "m_boardID= " << m_boardID);
289  m_posWire = m_aCDCSimHit->getPosWire();
290  m_posTrack = m_aCDCSimHit->getPosTrack();
291  m_momentum = m_aCDCSimHit->getMomentum();
292  m_flightTime = m_aCDCSimHit->getFlightTime();
293  m_globalTime = m_aCDCSimHit->getGlobalTime();
294  m_driftLength = m_aCDCSimHit->getDriftLength() * Unit::cm;
295 
296  //include alignment effects
297  //basically align flag should be always on since on/off is controlled by the input alignment.xml file itself.
298  m_align = true;
299 
300  TVector3 bwpAlign = m_cdcgp->wireBackwardPosition(m_wireID, CDCGeometryPar::c_Aligned);
301  TVector3 fwpAlign = m_cdcgp->wireForwardPosition(m_wireID, CDCGeometryPar::c_Aligned);
302 
303  TVector3 bwp = m_cdcgp->wireBackwardPosition(m_wireID);
304  TVector3 fwp = m_cdcgp->wireForwardPosition(m_wireID);
305 
306  //skip correction for wire-position alignment if unnecessary
307  if ((bwpAlign - bwp).Mag() == 0. && (fwpAlign - fwp).Mag() == 0.) m_align = false;
308  // std::cout << "a m_align= " << m_align << std::endl;
309 
310  if (m_align || m_correctForWireSag) {
311 
312  bwp = bwpAlign;
313  fwp = fwpAlign;
314 
315  if (m_correctForWireSag) {
316  double zpos = m_posWire.z();
317  double bckYSag = bwp.y();
318  double forYSag = fwp.y();
319 
320  // CDCGeometryPar::EWirePosition set = m_align ?
321  // CDCGeometryPar::c_Aligned : CDCGeometryPar::c_Base;
322  CDCGeometryPar::EWirePosition set = CDCGeometryPar::c_Aligned;
323  const int layerID = m_wireID.getICLayer();
324  const int wireID = m_wireID.getIWire();
325  m_cdcgp->getWireSagEffect(set, layerID, wireID, zpos, bckYSag, forYSag);
326  bwp.SetY(bckYSag);
327  fwp.SetY(forYSag);
328  }
329 
330  const TVector3 L = 5. * m_momentum.Unit(); //(cm) tentative
331  TVector3 posIn = m_posTrack - L;
332  TVector3 posOut = m_posTrack + L;
333  TVector3 posTrack = m_posTrack;
334  TVector3 posWire = m_posWire;
335 
336  // m_driftLength = m_cdcgp->ClosestApproach(bwp, fwp, posIn, posOut, posTrack, posWire);
337  m_driftLength = ClosestApproach(bwp, fwp, posIn, posOut, posTrack, posWire);
338  // std::cout << "base-dl, sag-dl, diff= " << m_aCDCSimHit->getDriftLength() <<" "<< m_driftLength <<" "<< m_driftLength - m_aCDCSimHit->getDriftLength() << std::endl;
339  m_posTrack = posTrack;
340  m_posWire = posWire;
341 
342  double deltaTime = 0.; //tentative (probably ok...)
343  // double deltaTime = (posTrack - m_posTrack).Mag() / speed;
344  m_flightTime += deltaTime;
345  m_globalTime += deltaTime;
346  m_posFlag = m_cdcgp->getNewLeftRightRaw(m_posWire, m_posTrack, m_momentum);
347  }
348 
349  // Calculate measurement time.
350  // Smear drift length
351  double hitDriftLength = m_driftLength;
352  double dDdt = getdDdt(hitDriftLength);
353  if (m_doSmearing) {
354  hitDriftLength = smearDriftLength(hitDriftLength, dDdt);
355  }
356 
357  //set flags
358  bool addTof = m_addTimeOfFlight4Bg;
359  bool addDelay = m_addInWirePropagationDelay4Bg;
360  if (m_aCDCSimHit->getBackgroundTag() == 0) {
361  addTof = m_addTimeOfFlight;
362  addDelay = m_addInWirePropagationDelay;
363  }
364  double hitDriftTime = getDriftTime(hitDriftLength, addTof, addDelay);
365 
366  //add randamized event time for a beam bg. hit
367  if (m_aCDCSimHit->getBackgroundTag() != 0) {
368  hitDriftTime += m_globalTime - m_flightTime;
369  }
370 
371  //add trigger timing jitter
372  hitDriftTime += trigTiming;
373 
374  //apply time window cut
375  double tMin = m_tMin;
376  double tMax = m_tMaxOuter;
377  if (m_wireID.getISuperLayer() == 0) tMax = m_tMaxInner;
378  if (m_useDB4FEE) {
379  tMin = m_lowEdgeOfTimeWindow[m_boardID];
380  tMax = m_uprEdgeOfTimeWindow[m_boardID];
381  }
382  if (hitDriftTime < tMin || hitDriftTime > tMax) continue;
383 
384  //Sum ADC count
385  const double stepLength = m_aCDCSimHit->getStepLength() * Unit::cm;
386  const double costh = m_momentum.z() / m_momentum.Mag();
387  const double hitdE = m_scaleFac * m_aCDCSimHit->getEnergyDep();
388  // B2DEBUG(29, "m_scaleFac,UnitGeV= " << m_scaleFac <<" "<< Unit::GeV);
389  unsigned short layerID = m_wireID.getICLayer();
390  unsigned short cellID = m_wireID.getIWire();
391  // unsigned short adcCount = getADCCount(layerID, cellID, hitdE, stepLength, costh);
392  unsigned short adcCount = getADCCount(m_wireID, hitdE, stepLength, costh);
393  const unsigned short adcTh = m_useDB4FEE ? m_adcThresh[m_boardID] : m_adcThreshold;
394  // B2DEBUG(29, "adcTh,adcCount= " << adcTh <<" "<< adcCount);
395  if (adcCount < adcTh) adcCount = 0;
396  iterADCMap = adcMap.find(m_wireID);
397  if (iterADCMap == adcMap.end()) {
398  adcMap.insert(make_pair(m_wireID, adcCount));
399  // adcMap.insert(make_pair(m_wireID, hitdE));
400  } else {
401  iterADCMap->second += adcCount;
402  // iterADCMap->second += hitdE;
403  }
404 
405  //Apply energy threshold
406  // If hitdE < dEThreshold, the hit is ignored
407  // M. Uchida 2012.08.31
408  double dEThreshold = 0.;
409  if (m_useDB4FEE && m_useDB4EDepToADC) {
410  dEThreshold = (m_tdcThresh[m_boardID] / m_cdcgp->getEDepToADCMainFactor(layerID, cellID)) * Unit::keV;
411  } else {
412  dEThreshold = (m_wireID.getISuperLayer() == 0) ? m_tdcThreshold4Inner : m_tdcThreshold4Outer;
413  dEThreshold *= Unit::eV;
414  }
415  B2DEBUG(29, "hitdE,dEThreshold,driftLength " << hitdE << " " << dEThreshold << " " << hitDriftLength);
416 
417  if (hitdE < dEThreshold) {
418  B2DEBUG(29, "Below Ethreshold: " << hitdE << " " << dEThreshold);
419  continue;
420  }
421 
422  // add one hit per trigger time window to the trigger signal map
423  unsigned short trigWindow = floor((hitDriftTime - m_tMin) * m_tdcBinWidthInv / 32);
424  iterSignalMapTrg = signalMapTrg.find(make_pair(m_wireID, trigWindow));
425  if (iterSignalMapTrg == signalMapTrg.end()) {
426  // signalMapTrg.insert(make_pair(make_pair(m_wireID, trigWindow),
427  // SignalInfo(iHits, hitDriftTime, hitdE)));
428  signalMapTrg.insert(make_pair(make_pair(m_wireID, trigWindow),
429  SignalInfo(iHits, hitDriftTime, adcCount)));
430  } else {
431  if (hitDriftTime < iterSignalMapTrg->second.m_driftTime) {
432  iterSignalMapTrg->second.m_driftTime = hitDriftTime;
433  iterSignalMapTrg->second.m_simHitIndex = iHits;
434  }
435  // iterSignalMapTrg->second.m_charge += hitdE;
436  iterSignalMapTrg->second.m_charge += adcCount;
437  }
438 
439  // Reject totally-dead wire; to be replaced by isDeadWire() in future
440  if (m_cdcgp->isBadWire(m_wireID)) {
441  // std::cout<<"badwire= " << m_wireID.getICLayer() <<" "<< m_wireID.getIWire() << std::endl;
442  continue;
443  }
444  // Reject partly-dead wire as well
445  double eff = 1.;
446  if (m_cdcgp->isDeadWire(m_wireID, eff)) {
447  // std::cout << "wid,eff= " << m_wireID << " " << eff << std::endl;
448  if (eff < gRandom->Uniform()) continue;
449  }
450 
451  // For TOT simulation, calculate drift length from In to the wire, and Out to the wire. The calculation is apprximate ignoring wire sag (this would be ok because TOT simulation is not required to be so accurate).
452  const double a = bwpAlign.X();
453  const double b = bwpAlign.Y();
454  const double c = bwpAlign.Z();
455  const TVector3 fmbAlign = fwpAlign - bwpAlign;
456  const double lmn = 1. / fmbAlign.Mag();
457  const double l = fmbAlign.X() * lmn;
458  const double m = fmbAlign.Y() * lmn;
459  const double n = fmbAlign.Z() * lmn;
460 
461  double dx = m_aCDCSimHit->getPosIn().X() - a;
462  double dy = m_aCDCSimHit->getPosIn().Y() - b;
463  double dz = m_aCDCSimHit->getPosIn().Z() - c;
464  double sub = l * dx + m * dy + n * dz;
465  const double driftLFromIn = sqrt(dx * dx + dy * dy + dz * dz - sub * sub);
466 
467  dx = m_aCDCSimHit->getPosOut().X() - a;
468  dy = m_aCDCSimHit->getPosOut().Y() - b;
469  dz = m_aCDCSimHit->getPosOut().Z() - c;
470  sub = l * dx + m * dy + n * dz;
471  const double driftLFromOut = sqrt(dx * dx + dy * dy + dz * dz - sub * sub);
472 
473  const double maxDriftL = std::max(driftLFromIn, driftLFromOut);
474  const double minDriftL = m_driftLength;
475  B2DEBUG(29, "driftLFromIn= " << driftLFromIn << " driftLFromOut= " << driftLFromOut << " minDriftL= " << minDriftL << " maxDriftL= "
476  <<
477  maxDriftL << "m_driftLength= " << m_driftLength);
478 
479  iterSignalMap = signalMap.find(m_wireID);
480 
481  if (iterSignalMap == signalMap.end()) {
482  // new entry
483  // signalMap.insert(make_pair(m_wireID, SignalInfo(iHits, hitDriftTime, hitdE)));
484  signalMap.insert(make_pair(m_wireID, SignalInfo(iHits, hitDriftTime, adcCount, maxDriftL, minDriftL)));
485  B2DEBUG(29, "Creating new Signal with encoded wire number: " << m_wireID);
486  } else {
487  // ... smallest drift time has to be checked, ...
488  if (hitDriftTime < iterSignalMap->second.m_driftTime) {
489  iterSignalMap->second.m_driftTime3 = iterSignalMap->second.m_driftTime2;
490  iterSignalMap->second.m_simHitIndex3 = iterSignalMap->second.m_simHitIndex2;
491  iterSignalMap->second.m_driftTime2 = iterSignalMap->second.m_driftTime;
492  iterSignalMap->second.m_simHitIndex2 = iterSignalMap->second.m_simHitIndex;
493  iterSignalMap->second.m_driftTime = hitDriftTime;
494  iterSignalMap->second.m_simHitIndex = iHits;
495  B2DEBUG(29, "hitDriftTime of current Signal: " << hitDriftTime << ", hitDriftLength: " << hitDriftLength);
496  } else if (hitDriftTime < iterSignalMap->second.m_driftTime2) {
497  iterSignalMap->second.m_driftTime3 = iterSignalMap->second.m_driftTime2;
498  iterSignalMap->second.m_simHitIndex3 = iterSignalMap->second.m_simHitIndex2;
499  iterSignalMap->second.m_driftTime2 = hitDriftTime;
500  iterSignalMap->second.m_simHitIndex2 = iHits;
501  } else if (hitDriftTime < iterSignalMap->second.m_driftTime3) {
502  iterSignalMap->second.m_driftTime3 = hitDriftTime;
503  iterSignalMap->second.m_simHitIndex3 = iHits;
504  }
505  // ... total charge has to be updated.
506  // iterSignalMap->second.m_charge += hitdE;
507  iterSignalMap->second.m_charge += adcCount;
508 
509  // set max and min driftLs
510  if (iterSignalMap->second.m_maxDriftL < maxDriftL) iterSignalMap->second.m_maxDriftL = maxDriftL;
511  if (iterSignalMap->second.m_minDriftL > minDriftL) iterSignalMap->second.m_minDriftL = minDriftL;
512  B2DEBUG(29, "maxDriftL in struct= " << iterSignalMap->second.m_maxDriftL << "minDriftL in struct= " <<
513  iterSignalMap->second.m_minDriftL);
514  }
515 
516  } // end loop over SimHits.
517 
518  //--- Now Store the results into CDCHits and
519  // create corresponding relations between SimHits and CDCHits.
520 
521  unsigned int iCDCHits = 0;
522  RelationArray cdcSimHitsToCDCHits(m_simHits, m_cdcHits); //SimHit<->CDCHit
523  RelationArray mcParticlesToCDCHits(m_mcParticles, m_cdcHits); //MCParticle<->CDCHit
524 
525  for (iterSignalMap = signalMap.begin(); iterSignalMap != signalMap.end(); ++iterSignalMap) {
526 
527  //add time-walk (here for simplicity)
528  // unsigned short adcCount = getADCCount(iterSignalMap->second.m_charge);
529  // unsigned short adcCount = iterSignalMap->second.m_charge;
530  iterADCMap = adcMap.find(iterSignalMap->first);
531  unsigned short adcCount = iterADCMap != adcMap.end() ? iterADCMap->second : 0;
532  /*
533  unsigned short adcCount = 0;
534  if (iterADCMap != adcMap.end()) {
535  adcCount = getADCCount(iterSignalMap->first, iterADCMap->second, 1., 0.);
536  unsigned short boardID = m_cdcgp->getBoardID(iterSignalMap->first);
537  // B2DEBUG(29, "boardID= " << boardID);
538  const unsigned short adcTh = m_useDB4FEE ? m_adcThresh[boardID] : m_adcThreshold;
539  if (adcCount < adcTh) adcCount = 0;
540  }
541  */
542 
543  if (m_addTimeWalk) {
544  B2DEBUG(29, "timewalk= " << m_cdcgp->getTimeWalk(iterSignalMap->first, adcCount));
545  iterSignalMap->second.m_driftTime += m_cdcgp->getTimeWalk(iterSignalMap->first, adcCount);
546  }
547 
548  //remove negative drift time (TDC) upon request
549  if (!m_outputNegativeDriftTime &&
550  iterSignalMap->second.m_driftTime < 0.) {
551  continue;
552  }
553 
554  //N.B. No bias (+ or -0.5 count) is introduced on average in digitization by the real TDC (info. from KEK electronics division). So round off (t0 - drifttime) below.
555  unsigned short tdcCount = static_cast<unsigned short>((getPositiveT0(iterSignalMap->first) - iterSignalMap->second.m_driftTime) *
556  m_tdcBinWidthInv + 0.5);
557 
558  //calculate tot; hard-coded currently
559  double deltaDL = iterSignalMap->second.m_maxDriftL - iterSignalMap->second.m_minDriftL;
560  if (deltaDL < 0.) {
561  B2DEBUG(29, "negative deltaDL= " << deltaDL);
562  deltaDL = 0.;
563  }
564  const unsigned short boardID = m_cdcgp->getBoardID(iterSignalMap->first);
565  unsigned short tot = std::min(std::round(5.92749 * deltaDL + 2.59706), static_cast<double>(m_widthOfTimeWindow[boardID]));
566  if (m_adcThresh[boardID] > 0) {
567  tot = std::min(static_cast<int>(tot), static_cast<int>(adcCount / m_adcThresh[boardID]));
568  }
569 
570  CDCHit* firstHit = m_cdcHits.appendNew(tdcCount, adcCount, iterSignalMap->first, 0, tot);
571  // std::cout <<"firsthit?= " << firstHit->is2ndHit() << std::endl;
572  //set a relation: CDCSimHit -> CDCHit
573  cdcSimHitsToCDCHits.add(iterSignalMap->second.m_simHitIndex, iCDCHits);
574 
575  //set a relation: MCParticle -> CDCHit
576  RelationVector<MCParticle> rels = m_simHits[iterSignalMap->second.m_simHitIndex]->getRelationsFrom<MCParticle>();
577  if (rels.size() != 0) {
578  //assumption: only one MCParticle
579  const MCParticle* mcparticle = rels[0];
580  double weight = rels.weight(0);
581  mcparticle->addRelationTo(firstHit, weight);
582  }
583 
584  //Set 2nd-hit related things if it exists
585  if (m_output2ndHit && iterSignalMap->second.m_simHitIndex2 >= 0) {
586  unsigned short tdcCount2 = static_cast<unsigned short>((getPositiveT0(iterSignalMap->first) - iterSignalMap->second.m_driftTime2) *
587  m_tdcBinWidthInv + 0.5);
588  if (tdcCount2 != tdcCount) {
589  CDCHit* secondHit = m_cdcHits.appendNew(tdcCount2, adcCount, iterSignalMap->first, 0, tot);
590  secondHit->set2ndHitFlag();
591  secondHit->setOtherHitIndices(firstHit);
592  // std::cout <<"2ndhit?= " << secondHit->is2ndHit() << std::endl;
593  // std::cout <<"1st-otherhitindex= " << firstHit->getOtherHitIndex() << std::endl;
594  // std::cout <<"2nd-otherhitindex= " << secondHit->getOtherHitIndex() << std::endl;
595  // secondHit->setOtherHitIndex(firstHit->getArrayIndex());
596  // firstHit->setOtherHitIndex(secondHit->getArrayIndex());
597  // std::cout <<"1st-otherhitindex= " << firstHit->getOtherHitIndex() << std::endl;
598  // std::cout <<"2nd-otherhitindex= " << secondHit->getOtherHitIndex() << std::endl;
599 
600  //set a relation: CDCSimHit -> CDCHit
601  ++iCDCHits;
602  cdcSimHitsToCDCHits.add(iterSignalMap->second.m_simHitIndex2, iCDCHits);
603  // std::cout << "settdc2 " << firstHit->getTDCCount() << " " << secondHit->getTDCCount() << std::endl;
604 
605  //set a relation: MCParticle -> CDCHit
606  rels = m_simHits[iterSignalMap->second.m_simHitIndex2]->getRelationsFrom<MCParticle>();
607  if (rels.size() != 0) {
608  //assumption: only one MCParticle
609  const MCParticle* mcparticle = rels[0];
610  double weight = rels.weight(0);
611  mcparticle->addRelationTo(secondHit, weight);
612  }
613  } else { //Check the 3rd hit when tdcCount = tdcCount2
614  // std::cout << "tdcCount1=2" << std::endl;
615  if (iterSignalMap->second.m_simHitIndex3 >= 0) {
616  unsigned short tdcCount3 = static_cast<unsigned short>((getPositiveT0(iterSignalMap->first) - iterSignalMap->second.m_driftTime3) *
617  m_tdcBinWidthInv + 0.5);
618  // std::cout << "tdcCount3= " << tdcCount3 << " " << tdcCount << std::endl;
619  if (tdcCount3 != tdcCount) {
620  CDCHit* secondHit = m_cdcHits.appendNew(tdcCount3, adcCount, iterSignalMap->first, 0, tot);
621  secondHit->set2ndHitFlag();
622  secondHit->setOtherHitIndices(firstHit);
623  // secondHit->setOtherHitIndex(firstHit->getArrayIndex());
624  // firstHit->setOtherHitIndex(secondHit->getArrayIndex());
625  // std::cout <<"2ndhit?= " << secondHit->is2ndHit() << std::endl;
626 
627  //set a relation: CDCSimHit -> CDCHit
628  ++iCDCHits;
629  cdcSimHitsToCDCHits.add(iterSignalMap->second.m_simHitIndex3, iCDCHits);
630  // std::cout << "settdc3 " << firstHit->getTDCCount() << " " << secondHit->getTDCCount() << std::endl;
631 
632  //set a relation: MCParticle -> CDCHit
633  rels = m_simHits[iterSignalMap->second.m_simHitIndex3]->getRelationsFrom<MCParticle>();
634  if (rels.size() != 0) {
635  //assumption: only one MCParticle
636  const MCParticle* mcparticle = rels[0];
637  double weight = rels.weight(0);
638  mcparticle->addRelationTo(secondHit, weight);
639  }
640  }
641  }
642  } //end of checking tdcCount 1=2 ?
643  } //end of 2nd hit setting
644 
645  // std::cout <<"t0= " << m_cdcgp->getT0(iterSignalMap->first) << std::endl;
646  /* unsigned short tdcInCommonStop = static_cast<unsigned short>((m_tdcOffset - iterSignalMap->second.m_driftTime) * m_tdcBinWidthInv);
647  float driftTimeFromTDC = static_cast<float>(m_tdcOffset - (tdcInCommonStop + 0.5)) * m_tdcBinWidth;
648  std::cout <<"driftT bf digitization, TDC in common stop, digitized driftT = " << iterSignalMap->second.m_driftTime <<" "<< tdcInCommonStop <<" "<< driftTimeFromTDC << std::endl;
649  */
650  ++iCDCHits;
651  }
652 
653  //Add crosstalk
654  if (m_addXTalk) addXTalk();
655 
656  // Store the results with trigger time window in a separate array
657  // with corresponding relations.
658  for (iterSignalMapTrg = signalMapTrg.begin(); iterSignalMapTrg != signalMapTrg.end(); ++iterSignalMapTrg) {
659  /*
660  unsigned short adcCount = getADCCount(iterSignalMapTrg->first.first, iterSignalMapTrg->second.m_charge, 1., 0.);
661  unsigned short boardID = m_cdcgp->getBoardID(iterSignalMapTrg->first.first);
662  // B2DEBUG(29, "boardID= " << boardID);
663  const unsigned short adcTh = m_useDB4FEE ? m_adcThresh[boardID] : m_adcThreshold;
664  if (adcCount < adcTh) adcCount = 0;
665  */
666  // unsigned short adcCount = getADCCount(iterSignalMapTrg->second.m_charge);
667  unsigned short adcCount = iterSignalMapTrg->second.m_charge;
668  unsigned short tdcCount =
669  static_cast<unsigned short>((getPositiveT0(iterSignalMapTrg->first.first) -
670  iterSignalMapTrg->second.m_driftTime) * m_tdcBinWidthInv + 0.5);
671  const CDCHit* cdcHit = m_cdcHits4Trg.appendNew(tdcCount, adcCount, iterSignalMapTrg->first.first);
672 
673  // relations
674  m_simHits[iterSignalMapTrg->second.m_simHitIndex]->addRelationTo(cdcHit);
675  RelationVector<MCParticle> rels = m_simHits[iterSignalMapTrg->second.m_simHitIndex]->getRelationsFrom<MCParticle>();
676  if (rels.size() != 0) {
677  //assumption: only one MCParticle
678  const MCParticle* mcparticle = rels[0];
679  double weight = rels.weight(0);
680  mcparticle->addRelationTo(cdcHit, weight);
681  }
682  }
683 
684  /*
685  std::cout << " " << std::endl;
686  RelationIndex<MCParticle, CDCHit> mcp_to_hit(mcParticles, cdcHits);
687  if (!mcp_to_hit) B2FATAL("No MCParticle -> CDCHit relation founf!");
688  typedef RelationIndex<MCParticle, CDCHit>::Element RelationElement;
689  int ncdcHits = cdcHits.getEntries();
690  for (int j = 0; j < ncdcHits; ++j) {
691  for (const RelationElement& rel : mcp_to_hit.getElementsTo(cdcHits[j])) {
692  std::cout << j << " " << cdcHits[j]->is2ndHit() <<" "<< rel.from->getIndex() << " " << rel.weight << std::endl;
693  }
694  }
695  */
696 }
697 
698 double CDCDigitizerModule::smearDriftLength(const double driftLength, const double dDdt)
699 {
700  double mean = 0.;
701  double resolution;
702 
703  if (m_useSimpleDigitization) {
704  if (gRandom->Uniform() <= m_fraction) {
705  mean = m_mean1;
706  resolution = m_resolution1;
707  } else {
708  mean = m_mean2;
709  resolution = m_resolution2;
710  }
711  } else {
712  const unsigned short leftRight = m_posFlag;
713  double alpha = m_cdcgp->getAlpha(m_posWire, m_momentum);
714  double theta = m_cdcgp->getTheta(m_momentum);
715  resolution = m_cdcgp->getSigma(driftLength, m_wireID.getICLayer(), leftRight, alpha, theta);
716  resolution *= m_totalFudgeFactor;
717  }
718 
719  //subtract resol. due to digitization, which'll be added later in the digitization
720 
721  double diff = resolution - dDdt * m_tdcResol;
722  if (diff > 0.) {
723  resolution = sqrt(diff * (resolution + dDdt * m_tdcResol));
724  } else {
725  resolution = 0.;
726  }
727 
728 #if defined(CDC_DEBUG)
729  cout << " " << endl;
730  cout << "CDCDigitizerModule::smearDriftLength" << endl;
731  cout << "tdcResol= " << m_tdcResol << endl;
732  cout << "dDdt,resolution= " << dDdt << " " << resolution << endl;
733 #endif
734 
735  // Smear drift length
736  double newDL = gRandom->Gaus(driftLength + mean , resolution);
737  while (newDL <= 0.) newDL = gRandom->Gaus(driftLength + mean, resolution);
738  // cout << "totalFugeF in Digi= " << m_totalFudgeFactor << endl;
739  return newDL;
740 }
741 
742 
743 double CDCDigitizerModule::getdDdt(const double driftL)
744 {
745  //---------------------------------------------------------------------------------
746  // Calculates the 1'st derivative: dD/dt, where D: drift length before smearing; t: drift time
747  //---------------------------------------------------------------------------------
748 
749  double dDdt = m_driftV;
750 
751  if (!m_useSimpleDigitization) {
752  const unsigned short layer = m_wireID.getICLayer();
753  const unsigned short leftRight = m_posFlag;
754  double alpha = m_cdcgp->getAlpha(m_posWire, m_momentum);
755  double theta = m_cdcgp->getTheta(m_momentum);
756  double t = m_cdcgp->getDriftTime(driftL, layer, leftRight, alpha, theta);
757  dDdt = m_cdcgp->getDriftV(t, layer, leftRight, alpha, theta);
758 
759 #if defined(CDC_DEBUG)
760  cout << " " << endl;
761  cout << "CDCDigitizerModule::getdDdt" << endl;
762  cout << "**layer= " << layer << endl;
763  cout << "alpha= " << 180.*alpha / M_PI << std::endl;
764  if (layer == 55) {
765  int lr = 0;
766  for (int i = 0; i < 1000; ++i) {
767  t = 1.0 * i;
768  double d = m_cdcgp->getDriftLength(t, layer, lr, alpha, theta);
769  cout << t << " " << d << endl;
770  }
771 
772  cout << " " << endl;
773 
774  lr = 1;
775  for (int i = 0; i < 100; ++i) {
776  t = 5 * i;
777  double d = m_cdcgp->getDriftLength(t, layer, lr, alpha, theta);
778  cout << t << " " << d << endl;
779  }
780  exit(-1);
781  }
782 #endif
783  }
784 
785  return dDdt;
786 }
787 
788 
789 double CDCDigitizerModule::getDriftTime(const double driftLength, const bool addTof, const bool addDelay)
790 {
791  //---------------------------------------------------------------------------------
792  // Method returning electron drift time (parameters: position in cm)
793  // T(drift) = TOF + T(true drift time) + T(propagation delay in wire) - T(event),
794  // T(event) is a timing of event, which includes a time jitter due to
795  // the trigger system.
796  //---------------------------------------------------------------------------------
797 
798  double driftT = 0.;
799 
800  if (m_useSimpleDigitization) {
801  driftT = (driftLength / Unit::cm) * m_driftVInv;
802 
803 #if defined(CDC_DEBUG)
804  cout << " " << endl;
805  cout << "CDCDigitizerModule::getDriftTime" << endl;
806  cout << "driftvinv= " << m_driftVInv << endl;
807 #endif
808  } else {
809  const unsigned short layer = m_wireID.getICLayer();
810  const unsigned short leftRight = m_posFlag;
811  double alpha = m_cdcgp->getAlpha(m_posWire, m_momentum);
812  double theta = m_cdcgp->getTheta(m_momentum);
813  driftT = m_cdcgp->getDriftTime(driftLength, layer, leftRight, alpha, theta);
814  // std::cout <<"alpha,theta,driftT= " << alpha <<" "<< theta <<" "<< driftT << std::endl;
815  }
816 
817  if (addTof) {
818  driftT += m_flightTime; // in ns
819  }
820 
821  if (addDelay) {
822  //calculate signal propagation length in the wire
823  CDCGeometryPar::EWirePosition set = m_align ? CDCGeometryPar::c_Aligned : CDCGeometryPar::c_Base;
824  TVector3 backWirePos = m_cdcgp->wireBackwardPosition(m_wireID, set);
825 
826  double propLength = (m_posWire - backWirePos).Mag();
827  // if (m_cdcgp->getSenseWireZposMode() == 1) {
828  //TODO: replace the following with cached reference
829  // std::cout << m_gcp->getInstance().getSenseWireZposMode() << std::endl;
830  if (m_gcp->getSenseWireZposMode() == 1) {
831  const unsigned short layer = m_wireID.getICLayer();
832  propLength += m_cdcgp->getBwdDeltaZ(layer);
833  }
834  // B2DEBUG(29, "Propagation in wire length: " << propLength);
835 
836  if (m_useSimpleDigitization) {
837  driftT += (propLength / Unit::cm) * m_propSpeedInv;
838 
839 #if defined(CDC_DEBUG)
840  cout << "pseedinv= " << m_propSpeedInv << endl;
841 #endif
842  } else {
843  const unsigned short layer = m_wireID.getICLayer();
844  driftT += (propLength / Unit::cm) * m_cdcgp->getPropSpeedInv(layer);
845 #if defined(CDC_DEBUG)
846  cout << "layer,pseedinv= " << layer << " " << m_cdcgp->getPropSpeedInv(layer) << endl;
847 #endif
848  }
849  }
850 
851  return driftT;
852 }
853 
854 
855 //unsigned short CDCDigitizerModule::getADCCount(unsigned short layer, unsigned short cell, double edep, double dx, double costh)
856 unsigned short CDCDigitizerModule::getADCCount(const WireID& wid, double dEinGeV, double dx, double costh)
857 {
858  unsigned short adcCount = 0;
859  if (dEinGeV <= 0. || dx <= 0.) return adcCount;
860 
861  // The current value is taken from E. Nakano from some test beam results. This should be a somewhat realistic value, but doesn't need to be exact.
862  // Similar as geometry parameters are for the ideal geometry, not the real one.
863  // const double conversionEDepToADC = (100.0 / 3.2) * 1e6;
864  double conv = (100.0 / 3.2); //keV -> count
865  const unsigned short layer = wid.getICLayer();
866  const unsigned short cell = wid.getIWire();
867  double dEInkeV = dEinGeV / Unit::keV;
868  if (m_spaceChargeEffect) {
869  if (m_useDB4EDepToADC) conv = m_cdcgp->getEDepToADCConvFactor(layer, cell, dEInkeV, dx, costh);
870  } else {
871  if (m_useDB4EDepToADC) conv = m_cdcgp->getEDepToADCMainFactor(layer, cell);
872  }
873  conv *= m_runGain;
874 
875  //The ADCcount is obtained by rounding-up (measured voltage)/bin in real ADC. This is true both for pedestal and signal voltages, so the pedestal-subtracted ADCcount (simulated here) is rounded.
876  adcCount = static_cast<unsigned short>(std::round(conv * dEInkeV));
877  return adcCount;
878 }
879 
880 
881 // Set FEE parameters (from DB)
882 void CDCDigitizerModule::setFEElectronics()
883 {
884  const double& off = m_tdcThresholdOffset;
885  const double& gA = m_analogGain;
886  const double& gD = m_digitalGain;
887  const double& adcBW = m_adcBinWidth;
888  const double convF = gA / gD / adcBW;
889  const double el1TrgLatency = m_cdcgp->getMeanT0(); // ns
890  B2DEBUG(29, "L1TRGLatency= " << el1TrgLatency);
891  const double c = 32. * m_tdcBinWidth;
892 
893  if (!m_fEElectronicsFromDB) B2FATAL("No FEEElectronics dbobject!");
894  const CDCFEElectronics& fp = *((*m_fEElectronicsFromDB)[0]);
895  int mode = (fp.getBoardID() == -1) ? 1 : 0;
896  int iNBoards = static_cast<int>(nBoards);
897 
898  //set typical values for all channels first if mode=1
899  if (mode == 1) {
900  for (int bdi = 1; bdi < iNBoards; ++bdi) {
901  m_uprEdgeOfTimeWindow[bdi] = el1TrgLatency - c * (fp.getTrgDelay() + 1);
902  if (m_uprEdgeOfTimeWindow[bdi] < 0.) B2FATAL("CDCDigitizer: Upper edge of time window < 0!");
903  m_lowEdgeOfTimeWindow[bdi] = m_uprEdgeOfTimeWindow[bdi] - c * (fp.getWidthOfTimeWindow() + 1);
904  if (m_lowEdgeOfTimeWindow[bdi] > 0.) B2FATAL("CDCDigitizer: Lower edge of time window > 0!");
905  m_adcThresh[bdi] = fp.getADCThresh();
906  m_tdcThresh[bdi] = convF * (off - fp.getTDCThreshInMV());
907  m_widthOfTimeWindow[bdi] = fp.getWidthOfTimeWindow() + 1;
908  }
909  }
910 
911  //ovewrite values for specific channels if mode=1
912  //set typical values for all channels if mode=0
913  for (const auto& fpp : (*m_fEElectronicsFromDB)) {
914  int bdi = fpp.getBoardID();
915  if (mode == 0 && bdi == 0) continue; //bdi=0 is dummy (not used)
916  if (mode == 1 && bdi == -1) continue; //skip typical case
917  if (bdi < 0 || bdi >= iNBoards) B2FATAL("CDCDigitizer:: Invalid no. of FEE board!");
918  m_uprEdgeOfTimeWindow[bdi] = el1TrgLatency - c * (fpp.getTrgDelay() + 1);
919  if (m_uprEdgeOfTimeWindow[bdi] < 0.) B2FATAL("CDCDigitizer: Upper edge of time window < 0!");
920  m_lowEdgeOfTimeWindow[bdi] = m_uprEdgeOfTimeWindow[bdi] - c * (fpp.getWidthOfTimeWindow() + 1);
921  if (m_lowEdgeOfTimeWindow[bdi] > 0.) B2FATAL("CDCDigitizer: Lower edge of time window > 0!");
922  m_adcThresh[bdi] = fpp.getADCThresh();
923  m_tdcThresh[bdi] = convF * (off - fpp.getTDCThreshInMV());
924  m_widthOfTimeWindow[bdi] = fpp.getWidthOfTimeWindow() + 1;
925  }
926 
927  //debug
928  B2DEBUG(29, "mode= " << mode);
929  for (int bdi = 1; bdi < iNBoards; ++bdi) {
930  B2DEBUG(29, bdi << " " << m_lowEdgeOfTimeWindow[bdi] << " " << m_uprEdgeOfTimeWindow[bdi] << " " << m_adcThresh[bdi] << " " <<
931  m_tdcThresh[bdi]);
932  }
933 }
934 
935 // Set Run-gain (from DB)
936 void CDCDigitizerModule::setRunGain()
937 {
938  m_runGain = (*m_runGainFromDB)->getRunGain();
939  m_runGain *= m_overallGainFactor;
940 }
941 
942 void CDCDigitizerModule::addXTalk()
943 {
944  map<WireID, XTalkInfo> xTalkMap;
945  map<WireID, XTalkInfo> xTalkMap1;
946  map<WireID, XTalkInfo>::iterator iterXTalkMap1;
947 
948  // Loop over all cdc hits to create a xtalk map
949  int OriginalNoOfHits = m_cdcHits.getEntries();
950  B2DEBUG(m_debugLevel4XTalk, "\n \n" << "#CDCHits " << OriginalNoOfHits);
951  for (const auto& aHit : m_cdcHits) {
952  if (m_issue2ndHitWarning && aHit.is2ndHit()) {
953  B2WARNING("2nd TDC hit found, but not ready for it!");
954  }
955  WireID wid(aHit.getID());
956  // B2DEBUG(m_debugLevel4XTalk, "Encoded wireid of current CDCHit: " << wid);
957  short tdcCount = aHit.getTDCCount();
958  short adcCount = aHit.getADCCount();
959  short tot = aHit.getTOT();
960  short board = m_cdcgp->getBoardID(wid);
961  short channel = m_cdcgp->getChannelID(wid);
962  const vector<pair<short, asicChannel>> xTalks = (*m_xTalkFromDB)->getLibraryCrossTalk(channel, tdcCount, adcCount, tot);
963 
964  int nXTalks = xTalks.size();
965  for (int i = 0; i < nXTalks; ++i) {
966  const unsigned short tdcCount4XTalk = xTalks[i].second.TDC;
967  if (i == 0) {
968  B2DEBUG(m_debugLevel4XTalk, "\n" << " signal: " << channel << " " << tdcCount << " " << adcCount << " " << tot);
969  }
970  B2DEBUG(m_debugLevel4XTalk, "xtalk: " << xTalks[i].first << " " << tdcCount4XTalk << " " << xTalks[i].second.ADC << " " <<
971  xTalks[i].second.TOT);
972  WireID widx = m_cdcgp->getWireID(board, xTalks[i].first);
973  if (!m_cdcgp->isBadWire(widx)) { // for non-bad wire
974  if (m_includeEarlyXTalks || (xTalks[i].second.TDC <= tdcCount)) {
975  const double t0 = getPositiveT0(widx);
976  const double ULOfTDC = (t0 - m_lowEdgeOfTimeWindow[board]) * m_tdcBinWidthInv;
977  const double LLOfTDC = (t0 - m_uprEdgeOfTimeWindow[board]) * m_tdcBinWidthInv;
978  if (LLOfTDC <= tdcCount4XTalk && tdcCount4XTalk <= ULOfTDC) {
979  const unsigned short status = 0;
980  xTalkMap.insert(make_pair(widx, XTalkInfo(tdcCount4XTalk, xTalks[i].second.ADC, xTalks[i].second.TOT, status)));
981  }
982  }
983  // } else {
984  // cout<<"badwire= " << widx.getICLayer() <<" "<< widx.getIWire() << endl;
985  }
986  } //end of xtalk loop
987  } //end of cdc hit loop
988 
989  //Loop over all xtalk hits to creat a new xtalk map with only the fastest hits kept (approx.)
990  B2DEBUG(m_debugLevel4XTalk, "#xtalk hits: " << xTalkMap.size());
991  for (const auto& aHit : xTalkMap) {
992  WireID wid = aHit.first;
993 
994  iterXTalkMap1 = xTalkMap1.find(wid);
995  unsigned short tdcCount = aHit.second.m_tdc;
996  unsigned short adcCount = aHit.second.m_adc;
997  unsigned short tot = aHit.second.m_tot;
998  unsigned short status = aHit.second.m_status;
999 
1000  if (iterXTalkMap1 == xTalkMap1.end()) { // new entry
1001  xTalkMap1.insert(make_pair(wid, XTalkInfo(tdcCount, adcCount, tot, status)));
1002  // B2DEBUG(m_debugLevel4XTalk, "Creating a new xtalk hit with encoded wire no.: " << wid);
1003  } else { // not new; check if fastest
1004  if (tdcCount < iterXTalkMap1->second.m_tdc) {
1005  iterXTalkMap1->second.m_tdc = tdcCount;
1006  B2DEBUG(m_debugLevel4XTalk, "TDC-count of current xtalk: " << tdcCount);
1007  }
1008  iterXTalkMap1->second.m_adc += adcCount;
1009  iterXTalkMap1->second.m_tot += tot; // approx.
1010  }
1011  } // end of xtalk loop
1012 
1013  //add xtalk in the same way as the beam bg. overlay
1014  B2DEBUG(m_debugLevel4XTalk, "#xtalk1 hits: " << xTalkMap1.size());
1015  for (const auto& aX : xTalkMap1) {
1016  bool append = true;
1017  const unsigned short tdc4Bg = aX.second.m_tdc;
1018  const unsigned short adc4Bg = aX.second.m_adc;
1019  const unsigned short tot4Bg = aX.second.m_tot;
1020  const unsigned short status4Bg = aX.second.m_status;
1021 
1022  for (int iHit = 0; iHit < OriginalNoOfHits; ++iHit) {
1023  CDCHit& aH = *(m_cdcHits[iHit]);
1024  if (aH.getID() != aX.first.getEWire()) { //wire id unmatched
1025  continue;
1026  } else { //wire id matched
1027  append = false;
1028  const unsigned short tdc4Sg = aH.getTDCCount();
1029  const unsigned short adc4Sg = aH.getADCCount();
1030  const unsigned short tot4Sg = aH.getTOT();
1031  // B2DEBUG(m_debuglevel4XTalk, "Sg tdc,adc,tot= " << tdc4Sg << " " << adc4Sg << " " << tot4Sg);
1032  // B2DEBUG(m_debugLevel4XTalk, "Bg tdc,adc,tot= " << tdc4Bg << " " << adc4Bg << " " << tot4Bg);
1033 
1034  // If the BG hit is faster than the true hit, the TDC count is replaced, and
1035  // the relations are removed. ADC counts are summed up.
1036  if (tdc4Sg < tdc4Bg) {
1037  aH.setTDCCount(tdc4Bg);
1038  aH.setStatus(status4Bg);
1039  auto relSimHits = aH.getRelationsFrom<CDCSimHit>();
1040  for (int i = relSimHits.size() - 1; i >= 0; --i) {
1041  relSimHits.remove(i);
1042  }
1043  auto relMCParticles = aH.getRelationsFrom<MCParticle>();
1044  for (int i = relMCParticles.size() - 1; i >= 0; --i) {
1045  relMCParticles.remove(i);
1046  }
1047  }
1048 
1049  aH.setADCCount(adc4Sg + adc4Bg);
1050 
1051  //Set TOT for signal+background case. It is assumed that the start timing
1052  //of a pulse (input to ADC) is given by the TDC-count. This is an
1053  //approximation becasue analog (for ADC) and digital (for TDC) parts are
1054  //different in the front-end electronics.
1055  unsigned short s1 = tdc4Sg; //start time of 1st pulse
1056  unsigned short s2 = tdc4Bg; //start time of 2nd pulse
1057  unsigned short w1 = tot4Sg; //its width
1058  unsigned short w2 = tot4Bg; //its width
1059  if (tdc4Sg < tdc4Bg) {
1060  s1 = tdc4Bg;
1061  w1 = tot4Bg;
1062  s2 = tdc4Sg;
1063  w2 = tot4Sg;
1064  }
1065  w1 *= 32;
1066  w2 *= 32;
1067  const unsigned short e1 = s1 - w1; //end time of 1st pulse
1068  const unsigned short e2 = s2 - w2; //end time of 2nd pulse
1069  // B2DEBUG(m_debuglevel4Xtalk, "s1,e1,w1,s2,e2,w2= " << s1 << " " << e1 << " " << w1 << " " << s2 << " " << e2 << " " << w2);
1070 
1071  double pulseW = w1 + w2;
1072  if (e1 <= e2) {
1073  pulseW = w1;
1074  } else if (e1 <= s2) {
1075  pulseW = s1 - e2;
1076  }
1077 
1078  unsigned short board = m_cdcgp->getBoardID(aX.first);
1079  aH.setTOT(std::min(std::round(pulseW / 32.), static_cast<double>(m_widthOfTimeWindow[board])));
1080  B2DEBUG(m_debugLevel4XTalk, "replaced tdc,adc,tot,wid,status= " << aH.getTDCCount() << " " << aH.getADCCount() << " " << aH.getTOT()
1081  <<
1082  " " << aH.getID() << " " << aH.getStatus());
1083  break;
1084  }
1085  } //end of cdc hit loop
1086 
1087  if (append) {
1088  m_cdcHits.appendNew(tdc4Bg, adc4Bg, aX.first, status4Bg, tot4Bg);
1089  B2DEBUG(m_debugLevel4XTalk, "appended tdc,adc,tot,wid,status= " << tdc4Bg << " " << adc4Bg << " " << tot4Bg << " " << aX.first <<
1090  " " <<
1091  status4Bg);
1092  }
1093  } //end of x-talk loop
1094  B2DEBUG(m_debugLevel4XTalk, "original #hits, #hits= " << OriginalNoOfHits << " " << m_cdcHits.getEntries());
1095 }
1096 
1097 
1098 double CDCDigitizerModule::getPositiveT0(const WireID& wid)
1099 {
1100  double t0 = m_cdcgp->getT0(wid);
1101  if (t0 <= 0 && m_treatNegT0WiresAsGood) t0 = m_cdcgp->getMeanT0();
1102  // B2DEBUG(m_debugLevel, m_cdcgp->getT0(wid) <<" "<< m_cdcgp->getMeanT0() <<" "<< t0);
1103  return t0;
1104 }
Belle2::RelationVector::size
size_t size() const
Get number of relations.
Definition: RelationVector.h:98
Belle2::CDCHit::setStatus
void setStatus(unsigned short status)
Setter for CDCHit status.
Definition: CDCHit.h:117
Belle2::RelationArray
Low-level class to create/modify relations between StoreArrays.
Definition: RelationArray.h:72
Belle2::WireID
Class to identify a wire inside the CDC.
Definition: WireID.h:44
Belle2::CDCHit::setOtherHitIndices
void setOtherHitIndices(CDCHit *otherHit)
Setter for the other hit indices.
Definition: CDCHit.h:158
Belle2::CDCHit::getID
unsigned short getID() const
Getter for encoded wire number.
Definition: CDCHit.h:204
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::CDCHit
Class containing the result of the unpacker in raw data and the result of the digitizer in simulation...
Definition: CDCHit.h:51
Belle2::CDCHit::getTDCCount
short getTDCCount() const
Getter for TDC count.
Definition: CDCHit.h:230
Belle2::DBArray
Class for accessing arrays of objects in the database.
Definition: DBArray.h:36
Belle2::CDC::CDCGeometryPar::getNominalPropSpeed
double getNominalPropSpeed() const
Return the nominal propagation speed of the sense wire (default: 27.25 cm/nsec).
Definition: CDCGeometryPar.h:752
Belle2::RelationsInterface::addRelationTo
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
Definition: RelationsObject.h:144
Belle2::CDC::CDCGeometryPar::getTdcBinWidth
double getTdcBinWidth() const
Return TDC bin width (nsec).
Definition: CDCGeometryPar.h:732
Belle2::CDCDigitizerModule::SignalInfo
Structure for saving the signal information.
Definition: CDCDigitizerModule.h:241
Belle2::CDCSimHit
Example Detector.
Definition: CDCSimHit.h:33
Belle2::CDC::ClosestApproach
double ClosestApproach(const TVector3 &bwp, const TVector3 &fwp, const TVector3 &posIn, const TVector3 &posOut, TVector3 &hitPosition, TVector3 &wirePosition)
Returns a closest distance between a track and a wire.
Definition: ClosestApproach.cc:27
Belle2::CDCHit::getStatus
unsigned short getStatus() const
Getter for CDCHit status.
Definition: CDCHit.h:210
Belle2::CDCHit::getTOT
unsigned short getTOT() const
Getter for TOT.
Definition: CDCHit.h:259
Belle2::DBObjPtr
Class for accessing objects in the database.
Definition: DBObjPtr.h:31
Belle2::CDCHit::getADCCount
unsigned short getADCCount() const
Getter for integrated charge.
Definition: CDCHit.h:241
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2::CDC::CDCGeometryPar
The Class for CDC Geometry Parameters.
Definition: CDCGeometryPar.h:75
Belle2::RelationVector
Class for type safe access to objects that are referred to in relations.
Definition: DataStore.h:38
Belle2::CDCHit::setTDCCount
void setTDCCount(short tdcCount)
Setter for TDC count.
Definition: CDCHit.h:139
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::CDCHit::set2ndHitFlag
void set2ndHitFlag()
Setter for 2nd hit flag.
Definition: CDCHit.h:124
Belle2::CDCDigitizerModule
The Class for Detailed Digitization of CDC.
Definition: CDCDigitizerModule.h:60
Belle2::RelationsInterface::getRelationsFrom
RelationVector< FROM > getRelationsFrom(const std::string &name="", const std::string &namedRelation="") const
Get the relations that point from another store array to this object.
Definition: RelationsObject.h:214
Belle2::CDCHit::setTOT
void setTOT(unsigned short tot)
Setter for TOT.
Definition: CDCHit.h:171
Belle2::RelationArray::add
void add(index_type from, index_type to, weight_type weight=1.0)
Add a new element to the relation.
Definition: RelationArray.h:291
Belle2::CDC::CDCGeometryPar::getNominalDriftV
double getNominalDriftV() const
Return the nominal drift velocity of He-ethane gas (default: 4.0x10^-3 cm/nsec).
Definition: CDCGeometryPar.h:742
Belle2::CDCHit::setADCCount
void setADCCount(unsigned short adcCount)
Setter for ADC count.
Definition: CDCHit.h:146
Belle2::CDC::CDCGeometryPar::EWirePosition
EWirePosition
Wire position set.
Definition: CDCGeometryPar.h:80
Belle2::CDCDigitizerModule::XTalkInfo
Structure for saving the x-talk information.
Definition: CDCDigitizerModule.h:261
Belle2::RelationVector::weight
float weight(int index) const
Get weight with index.
Definition: RelationVector.h:120
Belle2::MCParticle
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:43
Belle2::WireID::getIWire
unsigned short getIWire() const
Getter for wire within the layer.
Definition: WireID.h:155
Belle2::WireID::getICLayer
unsigned short getICLayer() const
Getter for continuous layer numbering.
Definition: WireID.cc:26
Belle2::DBAccessorBase::addCallback
void addCallback(std::function< void(const std::string &)> callback, bool onDestruction=false)
Add a callback method.
Definition: DBAccessorBase.h:108
Belle2::CDCFEElectronics
Database object for Fron-endt electronics params.
Definition: CDCFEElectronics.h:30