Belle II Software  release-08-01-10
CDCDigitizerModule.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <cdc/modules/cdcDigitizer/CDCDigitizerModule.h>
10 #include <cdc/modules/cdcDigitizer/EDepInGas.h>
11 #include <cdc/utilities/ClosestApproach.h>
12 
13 #include <framework/datastore/RelationArray.h>
14 //#include <framework/datastore/RelationIndex.h>
15 #include <framework/gearbox/Unit.h>
16 #include <framework/logging/Logger.h>
17 
18 #include <TRandom.h>
19 #include <map>
20 #include <utility>
21 
22 using namespace std;
23 using namespace Belle2;
24 using namespace CDC;
25 
26 // register module
27 REG_MODULE(CDCDigitizer);
28 CDCDigitizerModule::CDCDigitizerModule() : Module(),
29  m_cdcgp(), m_gcp(), m_aCDCSimHit(), m_posFlag(0),
30  m_driftLength(0.0), m_flightTime(0.0), m_globalTime(0.0),
31  m_tdcBinWidth(1.0), m_tdcBinWidthInv(1.0),
32  m_tdcResol(0.9825), m_driftV(4.0e-3),
33  m_driftVInv(250.0), m_propSpeedInv(27.25), m_align(true)
34 {
35  // Set description
36  setDescription("Creates CDCHits from CDCSimHits.");
38 
39  // Add parameters
40  // I/O
41  addParam("InputCDCSimHitsName", m_inputCDCSimHitsName, "Name of input array. Should consist of CDCSimHits.", string(""));
42  addParam("OutputCDCHitsName", m_outputCDCHitsName, "Name of output array. Will consist of CDCHits.", string(""));
43  addParam("OutputCDCHitsName4Trg", m_outputCDCHitsName4Trg,
44  "Name of output array for trigger. Can contain several hits per wire, "
45  "if they correspond to different time windows of 32ns.",
46  string("CDCHits4Trg"));
47 
48  //Relations
49  addParam("MCParticlesToCDCSimHitsName", m_MCParticlesToSimHitsName,
50  "Name of relation between MCParticles and CDCSimHits used", string(""));
51  addParam("CDCSimHistToCDCHitsName", m_SimHitsTOCDCHitsName,
52  "Name of relation between the CDCSimHits and the CDCHits used", string(""));
53  addParam("OptionalFirstMCParticlesToHitsName", m_OptionalFirstMCParticlesToHitsName,
54  "Optional name of relation between the first MCParticles and CDCHits used", string("FirstMatchedParticles"));
55  addParam("OptionalAllMCParticlesToHitsName", m_OptionalAllMCParticlesToHitsName,
56  "Optional name of relation between all MCParticles and CDCHits used", string("AllMatchedParticles"));
57 
58 
59  //Parameters for Digitization
60  addParam("UseSimpleDigitization", m_useSimpleDigitization,
61  "If true, a simple x-t with a constant velocity is used for the drift-length to -time conversion", false);
62 
63  //float Gauss Parameters
64  addParam("Fraction", m_fraction, "Fraction of first Gaussian used to smear drift length in cm", 1.0);
65  addParam("Mean1", m_mean1, "Mean value of first Gaussian used to smear drift length in cm", 0.0000);
66  addParam("Resolution1", m_resolution1, "Resolution of first Gaussian used to smear drift length in cm", 0.0130);
67  addParam("Mean2", m_mean2, "Mean value of second Gaussian used to smear drift length in cm", 0.0000);
68  addParam("Resolution2", m_resolution2, "Resolution of second Gaussian used to smear drift length in cm", 0.0000);
69 
70  //Switch to control smearing
71  addParam("DoSmearing", m_doSmearing,
72  "If false, drift length will not be smeared.", true);
73 
74  addParam("TrigTimeJitter", m_trigTimeJitter,
75  "Magnitude (w) of trigger timing jitter (ns). The trigger timing is randuminzed uniformly in a time window of [-w/2, +w/2].",
76  0.);
77  //Switches to control time information handling
78  addParam("AddTimeWalk", m_addTimeWalk, "A switch for time-walk (pulse-heght dep. delay); true: on; false: off", true);
79  addParam("AddInWirePropagationDelay", m_addInWirePropagationDelay,
80  "A switch used to control adding propagation delay in the wire into the final drift time or not; this is for signal hits.", true);
81  addParam("AddInWirePropagationDelay4Bg", m_addInWirePropagationDelay4Bg,
82  "The same switch but for beam bg. hits.", true);
83  addParam("AddTimeOfFlight", m_addTimeOfFlight,
84  "A switch used to control adding time of flight into the final drift time or not; this is for signal hits.", true);
85  addParam("AddTimeOfFlight4Bg", m_addTimeOfFlight4Bg,
86  "The same switch but for beam bg. hits.", true);
87  addParam("OutputNegativeDriftTime", m_outputNegativeDriftTime, "Output hits with negative drift time", true);
88  addParam("Output2ndHit", m_output2ndHit,
89  "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.",
90  false);
91  //Switch to control sense wire sag
92  addParam("CorrectForWireSag", m_correctForWireSag,
93  "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.",
94  true);
95  //Switch for negative-t0 wires
96  addParam("TreatNegT0WiresAsGood", m_treatNegT0WiresAsGood, "Treat wires with negative t0 (calibrated) as good wire4s.", true);
97 
98  //Threshold
99  addParam("TDCThreshold4Outer", m_tdcThreshold4Outer,
100  "TDC threshold (dE in eV) for Layers#8-56. The value corresponds to He-C2H6 gas", 250.);
101  addParam("TDCThreshold4Inner", m_tdcThreshold4Inner,
102  "Same as TDCThreshold4Outer but for Layers#0-7,", 150.);
103  addParam("EDepInGasMode", m_eDepInGasMode,
104  "Mode for extracting energy deposit in gas from energy deposit in gas+wire; =0: scaling using electron density; 1: scaling using most probab. energy deposit; 2: similar to 2 but slightly different; 3: extraction based on probability; 4: regeneration following probability",
105  0);
106 
107  //ADC Threshold
108  addParam("ADCThreshold", m_adcThreshold,
109  "Threshold for ADC-count (in unit of count). ADC-count < threshold is treated as count=0.", 2);
110  addParam("tMin", m_tMin, "Lower edge of time window in ns; valid only for UseDB4FEE=false", -100.);
111  addParam("tMaxOuter", m_tMaxOuter, "Upper edge of time window in ns for the normal-cell layers; valid only for UseDB4FEE=false",
112  500.);
113  addParam("tMaxInner", m_tMaxInner, "Upper edge of time window in ns for the small-cell layers; valid only for UseDB4FEE=false",
114  300.);
115  // The following doesn't make any sense. The only reasonable steerable would be a switch to decide if the jitter shall be
116  // activated. Then there has to be event by event jitter.
117  /* addParam("EventTime", m_eventTime,
118  "It is a timing of event, which includes a time jitter due to the trigger system, set in ns", float(0.0));*/
119 
120  //Switch for database
121  addParam("UseDB4FEE", m_useDB4FEE, "Fetch and use FEE params. from database or not", true);
122  addParam("UseDB4EDepToADC", m_useDB4EDepToADC, "Uuse edep-to-ADC conversion params. from database or not", true);
123  addParam("UseDB4RunGain", m_useDB4RunGain, "Fetch and use run gain from database or not", true);
124  addParam("OverallGainFactor", m_overallGainFactor, "Overall gain factor for adjustment", 1.0);
125 
126  //Switch for synchronization
127  addParam("Synchronization", m_synchronization, "Synchronize timing with other sub-detectors", m_synchronization);
128  addParam("Randomization", m_randomization, "Randomize timing with other sub-detectors; valid only for Synchronization=false",
130  addParam("OffsetForGetTriggerBin", m_offsetForTriggerBin, "Input to getCDCTriggerBin(offset), either of 0,1,2 or 3",
132  addParam("TrgTimingOffsetInCount", m_trgTimingOffsetInCount,
133  "L1 trigger timing offset in count, [0,7] in a trigger bin. The defaut value is from exp14, while the value from exp12 is 2. This run dependence may be taken into account later if needed",
135  addParam("ShiftOfTimeWindowIn32Count", m_shiftOfTimeWindowIn32Count,
136  "Shift of time window in 32count for synchronization (L1 timing=0)", m_shiftOfTimeWindowIn32Count);
137 
138  //Some FEE params.
139  addParam("TDCThresholdOffset", m_tdcThresholdOffset, "Offset for TDC (digital) threshold (mV)", 3828.);
140  addParam("AnalogGain", m_analogGain, "Analog gain (V/pC)", 1.09);
141  addParam("DigitalGain", m_digitalGain, "Digital gain (V/pC)", 7.);
142  addParam("ADCBinWidth", m_adcBinWidth, "ADC bin width (mV)", 2.);
143 
144  addParam("AddFudgeFactorForSigma", m_addFudgeFactorForSigma,
145  "Additional fudge factor for space resol. (common to all cells)", 1.);
146  addParam("SpaceChargeEffect", m_spaceChargeEffect, "Switch for space charge effect", true);
147  addParam("DegOfSPEOnThreshold", m_degOfSPEOnThreshold,
148  "Degree of space charge effect on timing threshold; specify the range [0,1]; =1: full effect on threshold; =0: no effect",
150 
151  addParam("AddXTalk", m_addXTalk, "A switch for crosstalk; true: on; false: off", true);
152  addParam("Issue2ndHitWarning", m_issue2ndHitWarning, "=true: issue a warning when a 2nd TDC hit is found.", true);
153  addParam("IncludeEarlyXTalks", m_includeEarlyXTalks, "=true: include earlier x-talks as well than the signal hit in question.",
154  true);
155  addParam("DebugLevel", m_debugLevel, "Debug level; 20-29 are usable.", 20);
156  addParam("DebugLevel4XTalk", m_debugLevel4XTalk, "Debug level for crosstalk; 20-29 are usable.", 21);
157 
158  //Gain smearing
159  addParam("GasGainSmearing", m_gasGainSmearing, "Switch for gas gain smearing for ADC simulation; true: on; false: off",
161  addParam("EffWForGasGainSmearing", m_effWForGasGainSmearing,
162  "Effective energy (keV) needed for one electron production for gas gain smearing; average for alpha- and beta-sources.",
164  addParam("ThetaOfPolyaFunction", m_thetaOfPolya, "Theta of Polya function for gas gain smearing", m_thetaOfPolya);
165  addParam("ExtraADCSmearing", m_extraADCSmearing, "Switch for extra ADC smearing; true: on; false: off", m_extraADCSmearing);
166  // addParam("SigmaForExtraADCSmearing", m_sigmaForExtraADCSmearing, "Gaussian sigma for extra ADC smearing; specify range [0,1]", m_sigmaForExtraADCSmearing);
167 
168  // Switch for optional relations
169  addParam("MatchAllMCParticles", m_matchAllMCParticles, "Switch to store all MCRelations that produced a SimHit", false);
170  addParam("MatchFirstMCParticles", m_matchFirstMCParticles,
171  "Switch to store all MCRelations for the first three SimHits instead of only the first", false);
172 
173 #if defined(CDC_DEBUG)
174  cout << " " << endl;
175  cout << "CDCDigitizer constructor" << endl;
176 #endif
177 }
178 
180 {
181  m_simHits.isRequired(m_inputCDCSimHitsName);
182  m_simClockState.isOptional();
183 
184  // Register the arrays in the DataStore, that are to be added in this module.
185  m_cdcHits.registerInDataStore(m_outputCDCHitsName);
186  m_simHits.registerRelationTo(m_cdcHits);
190 
191  // Arrays for trigger.
192  m_cdcHits4Trg.registerInDataStore(m_outputCDCHitsName4Trg);
193  m_simHits.registerRelationTo(m_cdcHits4Trg);
195 
197  CDCGeometryPar& cdcgp = *m_cdcgp;
198  m_tdcBinWidth = cdcgp.getTdcBinWidth();
200  m_tdcResol = m_tdcBinWidth / sqrt(12.);
201  m_driftV = cdcgp.getNominalDriftV();
202  m_driftVInv = 1. / m_driftV;
203  m_propSpeedInv = 1. / cdcgp.getNominalPropSpeed();
207  B2DEBUG(m_debugLevel, "totalFugeF in Digi= " << m_totalFudgeFactor);
208  /*
209  m_fraction = 1.0;
210  m_resolution1 = cdcgp.getNominalSpaceResol();
211  m_resolution2 = 0.;
212  m_mean1 = 0.;
213  m_mean2 = 0.;
214  */
215 
216  if (m_useDB4FEE) {
218  if ((*m_fEElectronicsFromDB).isValid()) {
219  (*m_fEElectronicsFromDB).addCallback(this, &CDCDigitizerModule::setFEElectronics);
221  } else {
222  B2FATAL("CDCDigitizer:: CDCFEElectronics not valid !");
223  }
224  }
225 
226  /*
227  if (m_useDB4EDepToADC) {
228  m_eDepToADCConversionsFromDB = new DBObjPtr<CDCEDepToADCConversions>;
229  if ((*m_eDepToADCConversionsFromDB).isValid()) {
230  (*m_eDepToADCConversionsFromDB).addCallback(this, &CDCDigitizerModule::setEDepToADCConversions);
231  setEDepToADCConversions();
232  } else {
233  B2FATAL("CDCDigitizer:: CDCEDepToADCConversions not valid !");
234  }
235  }
236  */
237 
238  if (m_useDB4RunGain) {
240  if ((*m_runGainFromDB).isValid()) {
241  (*m_runGainFromDB).addCallback(this, &CDCDigitizerModule::setSemiTotalGain);
242  } else {
243  B2FATAL("CDCDedxRunGain invalid!");
244  }
245 
247  if ((*m_gain0FromDB).isValid()) {
248  (*m_gain0FromDB).addCallback(this, &CDCDigitizerModule::setSemiTotalGain);
249  } else {
250  B2FATAL("CDCDedxScaleFactor invalid!");
251  }
252 
254  if ((*m_wireGainFromDB).isValid()) {
255  (*m_wireGainFromDB).addCallback(this, &CDCDigitizerModule::setSemiTotalGain);
257  } else {
258  B2FATAL("CDCDedxWireGain invalid!");
259  }
260  }
261 
262  if (m_addXTalk) {
264  if ((*m_xTalkFromDB).isValid()) {
265  } else {
266  B2FATAL("CDCCrossTalkLibrary invalid!");
267  }
268  }
269 
271  if ((*m_corrToThresholdFromDB).isValid()) {
272  } else {
273  B2FATAL("CDCCorrToThresholds invalid!");
274  }
275 
276 #if defined(CDC_DEBUG)
277  cout << " " << endl;
278  cout << "CDCDigitizer initialize" << endl;
279  // cout << "m_tdcOffset= " << m_tdcOffset << endl;
280  cout << "m_tdcBinWidth= " << m_tdcBinWidth << endl;
281  cout << "m_tdcResol= " << m_tdcResol << endl;
282  cout << "m_driftV= " << m_driftV << endl;
283  cout << "m_driftVInv= " << m_driftVInv << endl;
284  cout << "m_propSpeedInv= " << m_propSpeedInv << endl;
285  /*
286  cout << "m_fraction= " << m_fraction << endl;
287  cout << "m_resolution1= " << m_resolution1 << endl;
288  cout << "m_resolution2= " << m_resolution2 << endl;
289  cout << "m_mean1= " << m_mean1 << endl;
290  cout << "m_mean2= " << m_mean2 << endl;
291  */
292 #endif
293 
294  if (m_useDB4EDepToADC) {
295  ushort firstLayerOffset = m_cdcgp->getOffsetOfFirstLayer();
296  if (m_cdcgp->getEDepToADCMainFactor(firstLayerOffset, 0) == 0.) {
297  B2FATAL("CDCEDepToADCConversion payloads are unavailable!");
298  }
299  }
300 
301  // Set timing sim. mode
302  if (m_useDB4FEE) {
303  if (m_synchronization) { // syncronization
304  m_tSimMode = 0;
305  } else {
306  if (m_randomization) { // radomization
307  m_tSimMode = 1;
308  } else {
309  m_tSimMode = 2; // old sim.
310  }
311  }
312  } else {
313  m_tSimMode = 3; // old sim. w/o relying on fee db
314  }
315  B2DEBUG(m_debugLevel, "timing sim. mode= " << m_tSimMode);
316  if (m_tSimMode < 0 || m_tSimMode > 3) B2FATAL("invalid timing sim. mode= " << m_tSimMode);
317 }
318 
320 {
321  // Get SimHit array, MCParticle array, and relation between the two.
322  RelationArray mcParticlesToCDCSimHits(m_mcParticles, m_simHits); //RelationArray created by CDC SensitiveDetector
323 
324 
325  //--- Start Digitization --------------------------------------------------------------------------------------------
326  // Merge the hits in the same cell and save them into CDC signal map.
327 
328  // Define signal map
329  map<WireID, SignalInfo> signalMap;
330  map<WireID, SignalInfo>::iterator iterSignalMap;
331  // Define adc map
332  map<WireID, unsigned short> adcMap;
333  map<WireID, unsigned short>::iterator iterADCMap;
334  // map<WireID, double> adcMap;
335  // map<WireID, double>::iterator iterADCMap;
336 
337  // signal map for trigger
338  map<pair<WireID, unsigned>, SignalInfo> signalMapTrg;
339  map<pair<WireID, unsigned>, SignalInfo>::iterator iterSignalMapTrg;
340 
341  // signal map for all MCParticles: Wire <-> MCArrayIndex
342  map<WireID, std::set<int>> particleMap;
343  map<WireID, std::set<int>>::iterator iterParticleMap;
344 
345 
346  // Set time window per event
347  if (m_tSimMode == 0 || m_tSimMode == 1) {
348  int trigBin = 0;
349  if (m_simClockState.isValid()) {
350  trigBin = m_simClockState->getCDCTriggerBin(m_offsetForTriggerBin);
351  } else {
352  if (m_tSimMode == 0) {
353  B2DEBUG(m_debugLevel, "SimClockState unavailable so switched the mode from synchro to random.");
354  m_tSimMode = 1;
355  }
356  trigBin = gRandom->Integer(4);
357  }
358  if (trigBin < 0 || trigBin > 3) B2ERROR("Invalid trigger bin; must be an integer [0,3]!");
359  unsigned short offs = 8 * trigBin + m_trgTimingOffsetInCount;
360  B2DEBUG(m_debugLevel, "tSimMode,trigBin,offs= " << m_tSimMode << " " << trigBin << " " << offs);
361 
362  //TODO: simplify the following 7 lines and setFEElectronics()
363  for (unsigned short bd = 1; bd < c_nBoards; ++bd) {
364  const short tMaxInCount = 32 * (m_shiftOfTimeWindowIn32Count - m_trgDelayInCount[bd]) - offs;
365  const short tMinInCount = tMaxInCount - 32 * m_widthOfTimeWindowInCount[bd];
366  B2DEBUG(m_debugLevel, bd << " " << tMinInCount << " " << tMaxInCount);
367  m_uprEdgeOfTimeWindow[bd] = m_tdcBinWidth * tMaxInCount;
368  m_lowEdgeOfTimeWindow[bd] = m_tdcBinWidth * tMinInCount;
369  }
370  }
371 
372  // Set trigger timing jitter for this event
373  double trigTiming = m_trigTimeJitter == 0. ? 0. : m_trigTimeJitter * (gRandom->Uniform() - 0.5);
374  // std::cout << "trigTiming= " << trigTiming << std::endl;
375  // Loop over all hits
376  int nHits = m_simHits.getEntries();
377  B2DEBUG(m_debugLevel, "Number of CDCSimHits in the current event: " << nHits);
378  for (int iHits = 0; iHits < nHits; ++iHits) {
379  // Get a hit
380  m_aCDCSimHit = m_simHits[iHits];
381 
382  // Hit geom. info
385  B2FATAL("SimHit with wireID " << m_wireID << " is in CDC SuperLayer: " << m_wireID.getISuperLayer() << " which should not happen.");
386  }
387  // B2DEBUG(29, "Encoded wire number of current CDCSimHit: " << m_wireID);
388 
391  // B2DEBUG(29, "m_boardID= " << m_boardID);
398 
399  //include alignment effects
400  //basically align flag should be always on since on/off is controlled by the input alignment.xml file itself.
401  m_align = true;
402 
403  B2Vector3D bwpAlign = m_cdcgp->wireBackwardPosition(m_wireID, CDCGeometryPar::c_Aligned);
404  B2Vector3D fwpAlign = m_cdcgp->wireForwardPosition(m_wireID, CDCGeometryPar::c_Aligned);
405 
408 
409  //skip correction for wire-position alignment if unnecessary
410  if ((bwpAlign - bwp).Mag() == 0. && (fwpAlign - fwp).Mag() == 0.) m_align = false;
411  // std::cout << "a m_align= " << m_align << std::endl;
412 
413  if (m_align || m_correctForWireSag) {
414 
415  bwp = bwpAlign;
416  fwp = fwpAlign;
417 
418  if (m_correctForWireSag) {
419  double zpos = m_posWire.Z();
420  double bckYSag = bwp.Y();
421  double forYSag = fwp.Y();
422 
423  // CDCGeometryPar::EWirePosition set = m_align ?
424  // CDCGeometryPar::c_Aligned : CDCGeometryPar::c_Base;
425  CDCGeometryPar::EWirePosition set = CDCGeometryPar::c_Aligned;
426  const int layerID = m_wireID.getICLayer();
427  const int wireID = m_wireID.getIWire();
428  m_cdcgp->getWireSagEffect(set, layerID, wireID, zpos, bckYSag, forYSag);
429  bwp.SetY(bckYSag);
430  fwp.SetY(forYSag);
431  }
432 
433  const B2Vector3D L = 5. * m_momentum.Unit(); //(cm) tentative
434  B2Vector3D posIn = m_posTrack - L;
435  B2Vector3D posOut = m_posTrack + L;
436  B2Vector3D posTrack = m_posTrack;
437  B2Vector3D posWire = m_posWire;
438 
439  // m_driftLength = m_cdcgp->ClosestApproach(bwp, fwp, posIn, posOut, posTrack, posWire);
440  m_driftLength = ClosestApproach(bwp, fwp, posIn, posOut, posTrack, posWire);
441  // std::cout << "base-dl, sag-dl, diff= " << m_aCDCSimHit->getDriftLength() <<" "<< m_driftLength <<" "<< m_driftLength - m_aCDCSimHit->getDriftLength() << std::endl;
442  m_posTrack = posTrack;
443  m_posWire = posWire;
444 
445  double deltaTime = 0.; //tentative (probably ok...)
446  // double deltaTime = (posTrack - m_posTrack).Mag() / speed;
447  m_flightTime += deltaTime;
448  m_globalTime += deltaTime;
450  }
451 
452  // Calculate measurement time.
453  // Smear drift length
454  double hitDriftLength = m_driftLength;
455  double dDdt = getdDdt(hitDriftLength);
456  if (m_doSmearing) {
457  hitDriftLength = smearDriftLength(hitDriftLength, dDdt);
458  }
459 
460  //set flags
461  bool addTof = m_addTimeOfFlight4Bg;
462  bool addDelay = m_addInWirePropagationDelay4Bg;
463  if (m_aCDCSimHit->getBackgroundTag() == 0) {
464  addTof = m_addTimeOfFlight;
465  addDelay = m_addInWirePropagationDelay;
466  }
467  double hitDriftTime = getDriftTime(hitDriftLength, addTof, addDelay);
468 
469  //add randamized event time for a beam bg. hit
470  if (m_aCDCSimHit->getBackgroundTag() != 0) {
471  hitDriftTime += m_globalTime - m_flightTime;
472  }
473 
474  //add trigger timing jitter
475  hitDriftTime += trigTiming;
476 
477  //apply time window cut
478  double tMin = m_tMin;
479  double tMax = m_tMaxOuter;
480  if (m_wireID.getISuperLayer() == 0) tMax = m_tMaxInner;
481  if (m_tSimMode <= 2) {
484  }
485  if (hitDriftTime < tMin || hitDriftTime > tMax) continue;
486 
487  //Sum ADC count
488  const double stepLength = m_aCDCSimHit->getStepLength() * Unit::cm;
489  const double costh = m_momentum.Z() / m_momentum.Mag();
490  double hitdE = m_aCDCSimHit->getEnergyDep();
491  if (m_cdcgp->getMaterialDefinitionMode() != 2) { // for non wire-by-wire mode
492  static EDepInGas& edpg = EDepInGas::getInstance();
493  hitdE = edpg.getEDepInGas(m_eDepInGasMode, m_aCDCSimHit->getPDGCode(), m_momentum.Mag(), stepLength, hitdE);
494  }
495 
496  double convFactorForThreshold = 1;
497  //TODO: modify the following function so that it can output timing signal in Volt in future
498  unsigned short adcCount = 0;
499  makeSignalsAfterShapers(m_wireID, hitdE, stepLength, costh, adcCount, convFactorForThreshold);
500  const unsigned short adcTh = m_useDB4FEE ? m_adcThresh[m_boardID] : m_adcThreshold;
501  // B2DEBUG(29, "adcTh,adcCount,convFactorForThreshold= " << adcTh <<" "<< adcCount <<" "<< convFactorForThreshold);
502  if (adcCount < adcTh) adcCount = 0;
503  iterADCMap = adcMap.find(m_wireID);
504  if (iterADCMap == adcMap.end()) {
505  adcMap.insert(make_pair(m_wireID, adcCount));
506  // adcMap.insert(make_pair(m_wireID, hitdE));
507  } else {
508  iterADCMap->second += adcCount;
509  // iterADCMap->second += hitdE;
510  }
511 
512  //Apply energy threshold
513  // If hitdE < dEThreshold, the hit is ignored
514  double dEThreshold = 0.;
516  dEThreshold = m_tdcThresh[m_boardID] / convFactorForThreshold * Unit::keV;
517  } else {
519  dEThreshold *= Unit::eV;
520  }
521  dEThreshold *= (*m_corrToThresholdFromDB)->getParam(m_wireID.getICLayer());
522  B2DEBUG(m_debugLevel, "hitdE,dEThreshold,driftLength " << hitdE << " " << dEThreshold << " " << hitDriftLength);
523 
524  if (hitdE < dEThreshold) {
525  B2DEBUG(m_debugLevel, "Below Ethreshold: " << hitdE << " " << dEThreshold);
526  continue;
527  }
528 
529  // add one hit per trigger time window to the trigger signal map
530  unsigned short trigWindow = floor((hitDriftTime - tMin) * m_tdcBinWidthInv / 32);
531  iterSignalMapTrg = signalMapTrg.find(make_pair(m_wireID, trigWindow));
532  if (iterSignalMapTrg == signalMapTrg.end()) {
533  // signalMapTrg.insert(make_pair(make_pair(m_wireID, trigWindow),
534  // SignalInfo(iHits, hitDriftTime, hitdE)));
535  signalMapTrg.insert(make_pair(make_pair(m_wireID, trigWindow),
536  SignalInfo(iHits, hitDriftTime, adcCount)));
537  } else {
538  if (hitDriftTime < iterSignalMapTrg->second.m_driftTime) {
539  iterSignalMapTrg->second.m_driftTime = hitDriftTime;
540  iterSignalMapTrg->second.m_simHitIndex = iHits;
541  }
542  // iterSignalMapTrg->second.m_charge += hitdE;
543  iterSignalMapTrg->second.m_charge += adcCount;
544  }
545 
546  // Reject totally-dead wire; to be replaced by isDeadWire() in future
547  // N.B. The following lines for badwire must be after the above lines for trigger becuse badwires are different between trigger and tracking.
548  // Badwires for trigger are taken into account separately in the tsim module
549  if (m_cdcgp->isBadWire(m_wireID)) {
550  // std::cout<<"badwire= " << m_wireID.getICLayer() <<" "<< m_wireID.getIWire() << std::endl;
551  continue;
552  }
553  // Reject partly-dead wire as well
554  double eff = 1.;
555  if (m_cdcgp->isDeadWire(m_wireID, eff)) {
556  // std::cout << "wid,eff= " << m_wireID << " " << eff << std::endl;
557  if (eff < gRandom->Uniform()) continue;
558  }
559 
560  // 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).
561  const double a = bwpAlign.X();
562  const double b = bwpAlign.Y();
563  const double c = bwpAlign.Z();
564  const B2Vector3D fmbAlign = fwpAlign - bwpAlign;
565  const double lmn = 1. / fmbAlign.Mag();
566  const double l = fmbAlign.X() * lmn;
567  const double m = fmbAlign.Y() * lmn;
568  const double n = fmbAlign.Z() * lmn;
569 
570  double dx = m_aCDCSimHit->getPosIn().X() - a;
571  double dy = m_aCDCSimHit->getPosIn().Y() - b;
572  double dz = m_aCDCSimHit->getPosIn().Z() - c;
573  double sub = l * dx + m * dy + n * dz;
574  const double driftLFromIn = sqrt(dx * dx + dy * dy + dz * dz - sub * sub);
575 
576  dx = m_aCDCSimHit->getPosOut().X() - a;
577  dy = m_aCDCSimHit->getPosOut().Y() - b;
578  dz = m_aCDCSimHit->getPosOut().Z() - c;
579  sub = l * dx + m * dy + n * dz;
580  const double driftLFromOut = sqrt(dx * dx + dy * dy + dz * dz - sub * sub);
581 
582  const double maxDriftL = std::max(driftLFromIn, driftLFromOut);
583  const double minDriftL = m_driftLength;
584  B2DEBUG(m_debugLevel, "driftLFromIn= " << driftLFromIn << " driftLFromOut= " << driftLFromOut << " minDriftL= " << minDriftL <<
585  " maxDriftL= "
586  <<
587  maxDriftL << "m_driftLength= " << m_driftLength);
588 
589  iterSignalMap = signalMap.find(m_wireID);
590 
591  if (m_matchAllMCParticles) {
592  iterParticleMap = particleMap.find(m_wireID);
594 
595  int mcIndex = -1;
596  if (rels.size() != 0) {
597  if (rels.weight(0) > 0) {
598  const MCParticle* mcparticle = rels[0];
599  mcIndex = int(mcparticle->getIndex());
600  }
601  }
602 
603  if (mcIndex >= 0) {
604  if (iterParticleMap == particleMap.end()) {
605  std::set<int> vecmc = {mcIndex};
606  particleMap.insert(make_pair(m_wireID, vecmc));
607  } else {
608  iterParticleMap->second.insert(mcIndex);
609  }
610  }
611  }
612 
613  if (iterSignalMap == signalMap.end()) {
614  // new entry
615  // signalMap.insert(make_pair(m_wireID, SignalInfo(iHits, hitDriftTime, hitdE)));
616  signalMap.insert(make_pair(m_wireID, SignalInfo(iHits, hitDriftTime, adcCount, maxDriftL, minDriftL)));
617  B2DEBUG(m_debugLevel, "Creating new Signal with encoded wire number: " << m_wireID);
618  } else {
619  // ... smallest drift time has to be checked, ...
620  if (hitDriftTime < iterSignalMap->second.m_driftTime) {
621  iterSignalMap->second.m_driftTime3 = iterSignalMap->second.m_driftTime2;
622  iterSignalMap->second.m_simHitIndex3 = iterSignalMap->second.m_simHitIndex2;
623  iterSignalMap->second.m_driftTime2 = iterSignalMap->second.m_driftTime;
624  iterSignalMap->second.m_simHitIndex2 = iterSignalMap->second.m_simHitIndex;
625  iterSignalMap->second.m_driftTime = hitDriftTime;
626  iterSignalMap->second.m_simHitIndex = iHits;
627  B2DEBUG(m_debugLevel, "hitDriftTime of current Signal: " << hitDriftTime << ", hitDriftLength: " << hitDriftLength);
628  } else if (hitDriftTime < iterSignalMap->second.m_driftTime2) {
629  iterSignalMap->second.m_driftTime3 = iterSignalMap->second.m_driftTime2;
630  iterSignalMap->second.m_simHitIndex3 = iterSignalMap->second.m_simHitIndex2;
631  iterSignalMap->second.m_driftTime2 = hitDriftTime;
632  iterSignalMap->second.m_simHitIndex2 = iHits;
633  } else if (hitDriftTime < iterSignalMap->second.m_driftTime3) {
634  iterSignalMap->second.m_driftTime3 = hitDriftTime;
635  iterSignalMap->second.m_simHitIndex3 = iHits;
636  }
637  // ... total charge has to be updated.
638  // iterSignalMap->second.m_charge += hitdE;
639  iterSignalMap->second.m_charge += adcCount;
640 
641  // set max and min driftLs
642  if (iterSignalMap->second.m_maxDriftL < maxDriftL) iterSignalMap->second.m_maxDriftL = maxDriftL;
643  if (iterSignalMap->second.m_minDriftL > minDriftL) iterSignalMap->second.m_minDriftL = minDriftL;
644  B2DEBUG(m_debugLevel, "maxDriftL in struct= " << iterSignalMap->second.m_maxDriftL << "minDriftL in struct= " <<
645  iterSignalMap->second.m_minDriftL);
646  }
647 
648  } // end loop over SimHits.
649 
650  //--- Now Store the results into CDCHits and
651  // create corresponding relations between SimHits and CDCHits.
652 
653  unsigned int iCDCHits = 0;
654  RelationArray cdcSimHitsToCDCHits(m_simHits, m_cdcHits); //SimHit<->CDCHit
655  RelationArray mcParticlesToCDCHits(m_mcParticles, m_cdcHits); //MCParticle<->CDCHit
656 
657  for (iterSignalMap = signalMap.begin(); iterSignalMap != signalMap.end(); ++iterSignalMap) {
658 
659  //add time-walk (here for simplicity)
660  // unsigned short adcCount = getADCCount(iterSignalMap->second.m_charge);
661  // unsigned short adcCount = iterSignalMap->second.m_charge;
662  iterADCMap = adcMap.find(iterSignalMap->first);
663  unsigned short adcCount = iterADCMap != adcMap.end() ? iterADCMap->second : 0;
664  /*
665  unsigned short adcCount = 0;
666  if (iterADCMap != adcMap.end()) {
667  adcCount = getADCCount(iterSignalMap->first, iterADCMap->second, 1., 0.);
668  unsigned short boardID = m_cdcgp->getBoardID(iterSignalMap->first);
669  // B2DEBUG(29, "boardID= " << boardID);
670  const unsigned short adcTh = m_useDB4FEE ? m_adcThresh[boardID] : m_adcThreshold;
671  if (adcCount < adcTh) adcCount = 0;
672  }
673  */
674 
675  if (m_addTimeWalk) {
676  B2DEBUG(m_debugLevel, "timewalk= " << m_cdcgp->getTimeWalk(iterSignalMap->first, adcCount));
677  iterSignalMap->second.m_driftTime += m_cdcgp->getTimeWalk(iterSignalMap->first, adcCount);
678  }
679 
680  //remove negative drift time (TDC) upon request
682  iterSignalMap->second.m_driftTime < 0.) {
683  continue;
684  }
685 
686  //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.
687  unsigned short tdcCount = static_cast<unsigned short>((getPositiveT0(iterSignalMap->first) - iterSignalMap->second.m_driftTime) *
688  m_tdcBinWidthInv + 0.5);
689 
690  //calculate tot; hard-coded currently
691  double deltaDL = iterSignalMap->second.m_maxDriftL - iterSignalMap->second.m_minDriftL;
692  if (deltaDL < 0.) {
693  B2DEBUG(m_debugLevel, "negative deltaDL= " << deltaDL);
694  deltaDL = 0.;
695  }
696  const unsigned short boardID = m_cdcgp->getBoardID(iterSignalMap->first);
697  unsigned short tot = std::min(std::round(5.92749 * deltaDL + 2.59706), static_cast<double>(m_widthOfTimeWindowInCount[boardID]));
698  if (m_adcThresh[boardID] > 0) {
699  tot = std::min(static_cast<int>(tot), static_cast<int>(adcCount / m_adcThresh[boardID]));
700  }
701 
702  CDCHit* firstHit = m_cdcHits.appendNew(tdcCount, adcCount, iterSignalMap->first, 0, tot);
703  // std::cout <<"firsthit?= " << firstHit->is2ndHit() << std::endl;
704  //set a relation: CDCSimHit -> CDCHit
705  cdcSimHitsToCDCHits.add(iterSignalMap->second.m_simHitIndex, iCDCHits);
706 
707  //set a relation: MCParticle -> CDCHit
708  RelationVector<MCParticle> rels = m_simHits[iterSignalMap->second.m_simHitIndex]->getRelationsFrom<MCParticle>();
709  if (rels.size() != 0) {
710  //assumption: only one MCParticle
711  const MCParticle* mcparticle = rels[0];
712  double weight = rels.weight(0);
713  mcparticle->addRelationTo(firstHit, weight);
714  }
715 
716  // Set relations to all particles that created a SimHit
717  if (m_matchAllMCParticles) {
718  iterParticleMap = particleMap.find(iterSignalMap->first);
719  if (iterParticleMap != particleMap.end()) {
720  std::set<int> vv = iterParticleMap->second;
721  for (std::set<int>::iterator it = vv.begin(); it != vv.end(); ++it) {
722  // set all relations
723  int idx = *it;
724  MCParticle* part = m_mcParticles[idx - 1];
725  part->addRelationTo(firstHit, 1.0, m_OptionalAllMCParticlesToHitsName);
726  }
727  }
728  }
729 
730  //set all relations to first hit if requested but dont create additional hits!
731  // relation 1
732  if (m_matchFirstMCParticles > 0) {
733  if (iterSignalMap->second.m_simHitIndex >= 0) {
734  RelationVector<MCParticle> rels1 = m_simHits[iterSignalMap->second.m_simHitIndex]->getRelationsFrom<MCParticle>();
735  if (rels1.size() != 0) {
736  //assumption: only one MCParticle
737  const MCParticle* mcparticle = rels1[0];
738  double weight = rels1.weight(0);
739  mcparticle->addRelationTo(firstHit, weight, m_OptionalFirstMCParticlesToHitsName);
740  }
741  }
742 
743  // relation 2
744  if (iterSignalMap->second.m_simHitIndex2 >= 0) {
745  RelationVector<MCParticle> rels2 = m_simHits[iterSignalMap->second.m_simHitIndex2]->getRelationsFrom<MCParticle>();
746  if (rels2.size() != 0) {
747  //assumption: only one MCParticle
748  const MCParticle* mcparticle = rels2[0];
749  double weight = rels2.weight(0);
750  mcparticle->addRelationTo(firstHit, weight, m_OptionalFirstMCParticlesToHitsName);
751  }
752  }
753 
754  // relation 3
755  if (iterSignalMap->second.m_simHitIndex3 >= 0) {
756  RelationVector<MCParticle> rels3 = m_simHits[iterSignalMap->second.m_simHitIndex3]->getRelationsFrom<MCParticle>();
757  if (rels3.size() != 0) {
758  //assumption: only one MCParticle
759  const MCParticle* mcparticle = rels3[0];
760  double weight = rels3.weight(0);
761  mcparticle->addRelationTo(firstHit, weight, m_OptionalFirstMCParticlesToHitsName);
762  }
763  }
764 
765 
766  }
767 
768  //Set 2nd-hit related things if it exists
769  if (m_output2ndHit && iterSignalMap->second.m_simHitIndex2 >= 0) {
770  unsigned short tdcCount2 = static_cast<unsigned short>((getPositiveT0(iterSignalMap->first) - iterSignalMap->second.m_driftTime2) *
771  m_tdcBinWidthInv + 0.5);
772  if (tdcCount2 != tdcCount) {
773  CDCHit* secondHit = m_cdcHits.appendNew(tdcCount2, adcCount, iterSignalMap->first, 0, tot);
774  secondHit->set2ndHitFlag();
775  secondHit->setOtherHitIndices(firstHit);
776  // std::cout <<"2ndhit?= " << secondHit->is2ndHit() << std::endl;
777  // std::cout <<"1st-otherhitindex= " << firstHit->getOtherHitIndex() << std::endl;
778  // std::cout <<"2nd-otherhitindex= " << secondHit->getOtherHitIndex() << std::endl;
779  // secondHit->setOtherHitIndex(firstHit->getArrayIndex());
780  // firstHit->setOtherHitIndex(secondHit->getArrayIndex());
781  // std::cout <<"1st-otherhitindex= " << firstHit->getOtherHitIndex() << std::endl;
782  // std::cout <<"2nd-otherhitindex= " << secondHit->getOtherHitIndex() << std::endl;
783 
784  //set a relation: CDCSimHit -> CDCHit
785  ++iCDCHits;
786  cdcSimHitsToCDCHits.add(iterSignalMap->second.m_simHitIndex2, iCDCHits);
787  // std::cout << "settdc2 " << firstHit->getTDCCount() << " " << secondHit->getTDCCount() << std::endl;
788 
789  //set a relation: MCParticle -> CDCHit
790  rels = m_simHits[iterSignalMap->second.m_simHitIndex2]->getRelationsFrom<MCParticle>();
791  if (rels.size() != 0) {
792  //assumption: only one MCParticle
793  const MCParticle* mcparticle = rels[0];
794  double weight = rels.weight(0);
795  mcparticle->addRelationTo(secondHit, weight);
796  }
797  } else { //Check the 3rd hit when tdcCount = tdcCount2
798  // std::cout << "tdcCount1=2" << std::endl;
799  if (iterSignalMap->second.m_simHitIndex3 >= 0) {
800  unsigned short tdcCount3 = static_cast<unsigned short>((getPositiveT0(iterSignalMap->first) - iterSignalMap->second.m_driftTime3) *
801  m_tdcBinWidthInv + 0.5);
802  // std::cout << "tdcCount3= " << tdcCount3 << " " << tdcCount << std::endl;
803  if (tdcCount3 != tdcCount) {
804  CDCHit* secondHit = m_cdcHits.appendNew(tdcCount3, adcCount, iterSignalMap->first, 0, tot);
805  secondHit->set2ndHitFlag();
806  secondHit->setOtherHitIndices(firstHit);
807  // secondHit->setOtherHitIndex(firstHit->getArrayIndex());
808  // firstHit->setOtherHitIndex(secondHit->getArrayIndex());
809  // std::cout <<"2ndhit?= " << secondHit->is2ndHit() << std::endl;
810 
811  //set a relation: CDCSimHit -> CDCHit
812  ++iCDCHits;
813  cdcSimHitsToCDCHits.add(iterSignalMap->second.m_simHitIndex3, iCDCHits);
814  // std::cout << "settdc3 " << firstHit->getTDCCount() << " " << secondHit->getTDCCount() << std::endl;
815 
816  //set a relation: MCParticle -> CDCHit
817  rels = m_simHits[iterSignalMap->second.m_simHitIndex3]->getRelationsFrom<MCParticle>();
818  if (rels.size() != 0) {
819  //assumption: only one MCParticle
820  const MCParticle* mcparticle = rels[0];
821  double weight = rels.weight(0);
822  mcparticle->addRelationTo(secondHit, weight);
823  }
824  }
825  }
826  } //end of checking tdcCount 1=2 ?
827  } //end of 2nd hit setting
828 
829  // std::cout <<"t0= " << m_cdcgp->getT0(iterSignalMap->first) << std::endl;
830  /* unsigned short tdcInCommonStop = static_cast<unsigned short>((m_tdcOffset - iterSignalMap->second.m_driftTime) * m_tdcBinWidthInv);
831  float driftTimeFromTDC = static_cast<float>(m_tdcOffset - (tdcInCommonStop + 0.5)) * m_tdcBinWidth;
832  std::cout <<"driftT bf digitization, TDC in common stop, digitized driftT = " << iterSignalMap->second.m_driftTime <<" "<< tdcInCommonStop <<" "<< driftTimeFromTDC << std::endl;
833  */
834  ++iCDCHits;
835  }
836 
837  //Add crosstalk
838  if (m_addXTalk) addXTalk();
839 
840  // Store the results with trigger time window in a separate array
841  // with corresponding relations.
842  for (iterSignalMapTrg = signalMapTrg.begin(); iterSignalMapTrg != signalMapTrg.end(); ++iterSignalMapTrg) {
843  /*
844  unsigned short adcCount = getADCCount(iterSignalMapTrg->first.first, iterSignalMapTrg->second.m_charge, 1., 0.);
845  unsigned short boardID = m_cdcgp->getBoardID(iterSignalMapTrg->first.first);
846  // B2DEBUG(29, "boardID= " << boardID);
847  const unsigned short adcTh = m_useDB4FEE ? m_adcThresh[boardID] : m_adcThreshold;
848  if (adcCount < adcTh) adcCount = 0;
849  */
850  // unsigned short adcCount = getADCCount(iterSignalMapTrg->second.m_charge);
851  unsigned short adcCount = iterSignalMapTrg->second.m_charge;
852  unsigned short tdcCount =
853  static_cast<unsigned short>((getPositiveT0(iterSignalMapTrg->first.first) -
854  iterSignalMapTrg->second.m_driftTime) * m_tdcBinWidthInv + 0.5);
855  const CDCHit* cdcHit = m_cdcHits4Trg.appendNew(tdcCount, adcCount, iterSignalMapTrg->first.first);
856 
857  // relations
858  m_simHits[iterSignalMapTrg->second.m_simHitIndex]->addRelationTo(cdcHit);
859  RelationVector<MCParticle> rels = m_simHits[iterSignalMapTrg->second.m_simHitIndex]->getRelationsFrom<MCParticle>();
860  if (rels.size() != 0) {
861  //assumption: only one MCParticle
862  const MCParticle* mcparticle = rels[0];
863  double weight = rels.weight(0);
864  mcparticle->addRelationTo(cdcHit, weight);
865  }
866  }
867 
868  /*
869  std::cout << " " << std::endl;
870  RelationIndex<MCParticle, CDCHit> mcp_to_hit(mcParticles, cdcHits);
871  if (!mcp_to_hit) B2FATAL("No MCParticle -> CDCHit relation founf!");
872  typedef RelationIndex<MCParticle, CDCHit>::Element RelationElement;
873  int ncdcHits = cdcHits.getEntries();
874  for (int j = 0; j < ncdcHits; ++j) {
875  for (const RelationElement& rel : mcp_to_hit.getElementsTo(cdcHits[j])) {
876  std::cout << j << " " << cdcHits[j]->is2ndHit() <<" "<< rel.from->getIndex() << " " << rel.weight << std::endl;
877  }
878  }
879  */
880 }
881 
882 double CDCDigitizerModule::smearDriftLength(const double driftLength, const double dDdt)
883 {
884  double mean = 0.;
885  double resolution;
886 
888  if (gRandom->Uniform() <= m_fraction) {
889  mean = m_mean1;
890  resolution = m_resolution1;
891  } else {
892  mean = m_mean2;
893  resolution = m_resolution2;
894  }
895  } else {
896  const unsigned short leftRight = m_posFlag;
897  double alpha = m_cdcgp->getAlpha(m_posWire, m_momentum);
898  double theta = m_cdcgp->getTheta(m_momentum);
899  resolution = m_cdcgp->getSigma(driftLength, m_wireID.getICLayer(), leftRight, alpha, theta);
900  resolution *= m_totalFudgeFactor;
901  }
902 
903  //subtract resol. due to digitization, which'll be added later in the digitization
904 
905  double diff = resolution - dDdt * m_tdcResol;
906  if (diff > 0.) {
907  resolution = sqrt(diff * (resolution + dDdt * m_tdcResol));
908  } else {
909  resolution = 0.;
910  }
911 
912 #if defined(CDC_DEBUG)
913  cout << " " << endl;
914  cout << "CDCDigitizerModule::smearDriftLength" << endl;
915  cout << "tdcResol= " << m_tdcResol << endl;
916  cout << "dDdt,resolution= " << dDdt << " " << resolution << endl;
917 #endif
918 
919  // Smear drift length
920  double newDL = gRandom->Gaus(driftLength + mean, resolution);
921  while (newDL <= 0.) newDL = gRandom->Gaus(driftLength + mean, resolution);
922  // cout << "totalFugeF in Digi= " << m_totalFudgeFactor << endl;
923  return newDL;
924 }
925 
926 
927 double CDCDigitizerModule::getdDdt(const double driftL)
928 {
929  //---------------------------------------------------------------------------------
930  // Calculates the 1'st derivative: dD/dt, where D: drift length before smearing; t: drift time
931  //---------------------------------------------------------------------------------
932 
933  double dDdt = m_driftV;
934 
936  const unsigned short layer = m_wireID.getICLayer();
937  const unsigned short leftRight = m_posFlag;
938  double alpha = m_cdcgp->getAlpha(m_posWire, m_momentum);
939  double theta = m_cdcgp->getTheta(m_momentum);
940  double t = m_cdcgp->getDriftTime(driftL, layer, leftRight, alpha, theta);
941  dDdt = m_cdcgp->getDriftV(t, layer, leftRight, alpha, theta);
942 
943 #if defined(CDC_DEBUG)
944  cout << " " << endl;
945  cout << "CDCDigitizerModule::getdDdt" << endl;
946  cout << "**layer= " << layer << endl;
947  cout << "alpha= " << 180.*alpha / M_PI << std::endl;
948  if (layer == 55) {
949  int lr = 0;
950  for (int i = 0; i < 1000; ++i) {
951  t = 1.0 * i;
952  double d = m_cdcgp->getDriftLength(t, layer, lr, alpha, theta);
953  cout << t << " " << d << endl;
954  }
955 
956  cout << " " << endl;
957 
958  lr = 1;
959  for (int i = 0; i < 100; ++i) {
960  t = 5 * i;
961  double d = m_cdcgp->getDriftLength(t, layer, lr, alpha, theta);
962  cout << t << " " << d << endl;
963  }
964  exit(-1);
965  }
966 #endif
967  }
968 
969  return dDdt;
970 }
971 
972 
973 double CDCDigitizerModule::getDriftTime(const double driftLength, const bool addTof, const bool addDelay)
974 {
975  //---------------------------------------------------------------------------------
976  // Method returning electron drift time (parameters: position in cm)
977  // T(drift) = TOF + T(true drift time) + T(propagation delay in wire) - T(event),
978  // T(event) is a timing of event, which includes a time jitter due to
979  // the trigger system.
980  //---------------------------------------------------------------------------------
981 
982  double driftT = 0.;
983 
985  driftT = (driftLength / Unit::cm) * m_driftVInv;
986 
987 #if defined(CDC_DEBUG)
988  cout << " " << endl;
989  cout << "CDCDigitizerModule::getDriftTime" << endl;
990  cout << "driftvinv= " << m_driftVInv << endl;
991 #endif
992  } else {
993  const unsigned short layer = m_wireID.getICLayer();
994  const unsigned short leftRight = m_posFlag;
995  double alpha = m_cdcgp->getAlpha(m_posWire, m_momentum);
996  double theta = m_cdcgp->getTheta(m_momentum);
997  driftT = m_cdcgp->getDriftTime(driftLength, layer, leftRight, alpha, theta);
998  // std::cout <<"alpha,theta,driftT= " << alpha <<" "<< theta <<" "<< driftT << std::endl;
999  }
1000 
1001  if (addTof) {
1002  driftT += m_flightTime; // in ns
1003  }
1004 
1005  if (addDelay) {
1006  //calculate signal propagation length in the wire
1007  CDCGeometryPar::EWirePosition set = m_align ? CDCGeometryPar::c_Aligned : CDCGeometryPar::c_Base;
1008  B2Vector3D backWirePos = m_cdcgp->wireBackwardPosition(m_wireID, set);
1009 
1010  double propLength = (m_posWire - backWirePos).Mag();
1011  // if (m_cdcgp->getSenseWireZposMode() == 1) {
1012  //TODO: replace the following with cached reference
1013  // std::cout << m_gcp->getInstance().getSenseWireZposMode() << std::endl;
1014  if (m_gcp->getSenseWireZposMode() == 1) {
1015  const unsigned short layer = m_wireID.getICLayer();
1016  propLength += m_cdcgp->getBwdDeltaZ(layer);
1017  }
1018  // B2DEBUG(29, "Propagation in wire length: " << propLength);
1019 
1021  driftT += (propLength / Unit::cm) * m_propSpeedInv;
1022 
1023 #if defined(CDC_DEBUG)
1024  cout << "pseedinv= " << m_propSpeedInv << endl;
1025 #endif
1026  } else {
1027  const unsigned short layer = m_wireID.getICLayer();
1028  driftT += (propLength / Unit::cm) * m_cdcgp->getPropSpeedInv(layer);
1029 #if defined(CDC_DEBUG)
1030  cout << "layer,pseedinv= " << layer << " " << m_cdcgp->getPropSpeedInv(layer) << endl;
1031 #endif
1032  }
1033  }
1034 
1035  return driftT;
1036 }
1037 
1038 
1039 void CDCDigitizerModule::makeSignalsAfterShapers(const WireID& wid, double dEinGeV, double dx, double costh,
1040  unsigned short& adcCount, double& convFactorForThreshold)
1041 {
1042  static double conv00 = (100.0 / 3.2); //keV -> coun (original from some test beam results)
1043  convFactorForThreshold = conv00;
1044  adcCount = 0;
1045  if (dEinGeV <= 0. || dx <= 0.) return;
1046 
1047  const unsigned short layer = wid.getICLayer();
1048  const unsigned short cell = wid.getIWire();
1049  double dEInkeV = dEinGeV / Unit::keV;
1050 
1051  double conv = conv00;
1052  if (m_spaceChargeEffect) {
1053  if (m_useDB4EDepToADC) {
1054  conv = m_cdcgp->getEDepToADCConvFactor(layer, cell, dEInkeV, dx, costh);
1055  double conv0 = m_cdcgp->getEDepToADCMainFactor(layer, cell, costh);
1056  convFactorForThreshold = (conv0 + m_degOfSPEOnThreshold * (conv - conv0));
1057  }
1058  } else {
1059  if (m_useDB4EDepToADC) conv = m_cdcgp->getEDepToADCMainFactor(layer, cell, costh);
1060  convFactorForThreshold = conv;
1061  }
1062 
1063  if (convFactorForThreshold > 0.) {
1064  convFactorForThreshold *= getSemiTotalGain(layer, cell);
1065  } else {
1066  convFactorForThreshold = conv00;
1067  }
1068 
1069  if (m_gasGainSmearing) {
1070  const int nElectrons = std::round(dEInkeV / m_effWForGasGainSmearing);
1071  double relGain = 0;
1072  if (20 <= nElectrons) {
1073  relGain = std::max(0., gRandom->Gaus(1., sqrt(1. / (nElectrons * (1. + m_thetaOfPolya)))));
1074  } else if (1 <= nElectrons) {
1075  for (int i = 1; i <= nElectrons; ++i) {
1076  relGain += Polya();
1077  }
1078  relGain /= nElectrons;
1079  } else {
1080  relGain = 1;
1081  }
1082  conv *= relGain;
1083  }
1084 
1085  if (m_extraADCSmearing) {
1086  conv *= max(0., gRandom->Gaus(1., m_cdcgp->getEDepToADCSigma(layer, cell)));
1087  }
1088 
1089  conv *= getSemiTotalGain(layer, cell);
1090 
1091  //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.
1092  adcCount = static_cast<unsigned short>(std::round(conv * dEInkeV));
1093  return;
1094 }
1095 
1096 
1097 double CDCDigitizerModule::Polya(double xmax)
1098 {
1099  double x = 0;
1100  double y = 1;
1101  double fx = 0;
1102  double urndm[2];
1103  static double ymax = pow(m_thetaOfPolya, m_thetaOfPolya) * exp(-m_thetaOfPolya);
1104  while (y > fx) {
1105  gRandom->RndmArray(2, urndm);
1106  x = xmax * urndm[0];
1107  double a = (1 + m_thetaOfPolya) * x;
1108  fx = pow(a, m_thetaOfPolya) * exp(-a);
1109  y = ymax * urndm[1];
1110  }
1111  return x;
1112 }
1113 
1114 
1115 // Set FEE parameters (from DB)
1117 {
1118  const double& off = m_tdcThresholdOffset;
1119  const double& gA = m_analogGain;
1120  const double& gD = m_digitalGain;
1121  const double& adcBW = m_adcBinWidth;
1122  const double convF = gA / gD / adcBW;
1123  const double el1TrgLatency = m_cdcgp->getMeanT0(); // ns
1124  B2DEBUG(m_debugLevel, "L1TRGLatency= " << el1TrgLatency);
1125  const double c = 32. * m_tdcBinWidth;
1126 
1127  if (!m_fEElectronicsFromDB) B2FATAL("No FEEElectronics dbobject!");
1128  const CDCFEElectronics& fp = *((*m_fEElectronicsFromDB)[0]);
1129  int mode = (fp.getBoardID() == -1) ? 1 : 0;
1130  int iNBoards = static_cast<int>(c_nBoards);
1131 
1132  //set typical values for all channels first if mode=1
1133  if (mode == 1) {
1134  for (int bdi = 1; bdi < iNBoards; ++bdi) {
1135  m_uprEdgeOfTimeWindow[bdi] = el1TrgLatency - c * (fp.getTrgDelay() + 1);
1136  if (m_uprEdgeOfTimeWindow[bdi] < 0.) B2FATAL("CDCDigitizer: Upper edge of time window < 0!");
1137  m_lowEdgeOfTimeWindow[bdi] = m_uprEdgeOfTimeWindow[bdi] - c * (fp.getWidthOfTimeWindow() + 1);
1138  if (m_lowEdgeOfTimeWindow[bdi] > 0.) B2FATAL("CDCDigitizer: Lower edge of time window > 0!");
1139  m_adcThresh[bdi] = fp.getADCThresh();
1140  m_tdcThresh[bdi] = convF * (off - fp.getTDCThreshInMV());
1141  m_widthOfTimeWindowInCount[bdi] = fp.getWidthOfTimeWindow() + 1;
1142  m_trgDelayInCount [bdi] = fp.getTrgDelay();
1143  }
1144  }
1145 
1146  //ovewrite values for specific channels if mode=1
1147  //set typical values for all channels if mode=0
1148  for (const auto& fpp : (*m_fEElectronicsFromDB)) {
1149  int bdi = fpp.getBoardID();
1150  if (mode == 0 && bdi == 0) continue; //bdi=0 is dummy (not used)
1151  if (mode == 1 && bdi == -1) continue; //skip typical case
1152  if (bdi < 0 || bdi >= iNBoards) B2FATAL("CDCDigitizer:: Invalid no. of FEE board!");
1153  m_uprEdgeOfTimeWindow[bdi] = el1TrgLatency - c * (fpp.getTrgDelay() + 1);
1154  if (m_uprEdgeOfTimeWindow[bdi] < 0.) B2FATAL("CDCDigitizer: Upper edge of time window < 0!");
1155  m_lowEdgeOfTimeWindow[bdi] = m_uprEdgeOfTimeWindow[bdi] - c * (fpp.getWidthOfTimeWindow() + 1);
1156  if (m_lowEdgeOfTimeWindow[bdi] > 0.) B2FATAL("CDCDigitizer: Lower edge of time window > 0!");
1157  m_adcThresh[bdi] = fpp.getADCThresh();
1158  m_tdcThresh[bdi] = convF * (off - fpp.getTDCThreshInMV());
1159  m_widthOfTimeWindowInCount[bdi] = fpp.getWidthOfTimeWindow() + 1;
1160  m_trgDelayInCount [bdi] = fpp.getTrgDelay();
1161  }
1162 
1163  //debug
1164  B2DEBUG(m_debugLevel, "mode= " << mode);
1165  for (int bdi = 1; bdi < iNBoards; ++bdi) {
1166  B2DEBUG(m_debugLevel, bdi << " " << m_lowEdgeOfTimeWindow[bdi] << " " << m_uprEdgeOfTimeWindow[bdi] << " " << m_adcThresh[bdi] <<
1167  " " <<
1168  m_tdcThresh[bdi]);
1169  }
1170 }
1171 
1172 // Set Run-gain (from DB)
1174 {
1175  B2DEBUG(m_debugLevel, " ");
1176 
1177  //read individual wire gains
1178  const int nLyrs = c_maxNSenseLayers;
1179  B2DEBUG(m_debugLevel, "nLyrs= " << nLyrs);
1180  int nGoodL[nLyrs] = {};
1181  float wgL[nLyrs] = {};
1182  int nGoodSL[c_nSuperLayers] = {};
1183  float wgSL[c_nSuperLayers] = {};
1184  int nGoodAll = 0;
1185  float wgAll = 0;
1186  int iw = -1;
1187  for (int lyr = 0; lyr < nLyrs; ++lyr) {
1188  int nWs = m_cdcgp->nWiresInLayer(lyr);
1189  for (int w = 0; w < nWs; ++w) {
1190  ++iw;
1191  float wg = (*m_wireGainFromDB)->getWireGain(iw);
1192  m_semiTotalGain[lyr][w] = wg;
1193  if (wg > 0) {
1194  ++nGoodL[lyr];
1195  wgL[lyr] += wg;
1196  WireID wid(lyr, w);
1197  ++nGoodSL[wid.getISuperLayer()];
1198  wgSL[wid.getISuperLayer()] += wg;
1199  ++nGoodAll;
1200  wgAll += wg;
1201  }
1202  }
1203  }
1204 
1205  //calculate mean gain per layer
1206  for (int lyr = 0; lyr < nLyrs; ++lyr) {
1207  if (nGoodL[lyr] > 0) wgL[lyr] /= nGoodL[lyr];
1208  B2DEBUG(m_debugLevel, "lyr,ngood,gain= " << lyr << " " << nGoodL[lyr] << " " << wgL[lyr]);
1209  }
1210  //calculate mean gain per superlayer
1211  for (unsigned int sl = 0; sl < c_nSuperLayers; ++sl) {
1212  if (nGoodSL[sl] > 0) wgSL[sl] /= nGoodSL[sl];
1213  B2DEBUG(m_debugLevel, "slyr,ngood,gain= " << sl << " " << nGoodSL[sl] << " " << wgSL[sl]);
1214  }
1215 
1216 
1217  //calculate mean gain over all wires
1218  if (nGoodAll > 0) {
1219  wgAll /= nGoodAll;
1220  } else {
1221  B2FATAL("No good wires !");
1222  }
1223  B2DEBUG(m_debugLevel, "ngoodAll,gain= " << nGoodAll << " " << wgAll);
1224 
1225  //set gain also for bad/dead wires (bad/dead in terms of dE/dx pid)
1226  for (int lyr = 0; lyr < nLyrs; ++lyr) {
1227  int nWs = m_cdcgp->nWiresInLayer(lyr);
1228  for (int w = 0; w < nWs; ++w) {
1229  if (m_semiTotalGain[lyr][w] <= 0) {
1230  if (wgL[lyr] > 0) {
1231  m_semiTotalGain[lyr][w] = wgL[lyr];
1232  } else {
1233  WireID wid(lyr, w);
1234  m_semiTotalGain[lyr][w] = wgSL[wid.getISuperLayer()];
1235  }
1236  }
1237  }
1238  }
1239 
1240  //check if all gains > 0
1241  for (int lyr = 0; lyr < nLyrs; ++lyr) {
1242  int nWs = m_cdcgp->nWiresInLayer(lyr);
1243  for (int w = 0; w < nWs; ++w) {
1244  if (m_semiTotalGain[lyr][w] <= 0) {
1245  B2WARNING("Gain for lyr and wire " << lyr << " " << w << "not > 0. Strange! Replace it with " << wgAll << ".");
1246  m_semiTotalGain[lyr][w] = wgAll;
1247  }
1248  }
1249  }
1250 
1251 //multiply common factor for all wires
1252  m_runGain = (*m_runGainFromDB)->getRunGain();
1253  double cgain = (*m_gain0FromDB)->getScaleFactor();
1254  B2DEBUG(m_debugLevel, "runGain, sf= " << m_runGain << " " << cgain);
1255  cgain *= m_runGain * m_overallGainFactor;
1256  for (int lyr = 0; lyr < nLyrs; ++lyr) {
1257  int nWs = m_cdcgp->nWiresInLayer(lyr);
1258  for (int w = 0; w < nWs; ++w) {
1259  m_semiTotalGain[lyr][w] *= cgain;
1260  B2DEBUG(m_debugLevel, "lyr,wire,gain= " << lyr << " " << w << " " << m_semiTotalGain[lyr][w]);
1261  }
1262  }
1263 }
1264 
1265 
1267 {
1268  map<WireID, XTalkInfo> xTalkMap;
1269  map<WireID, XTalkInfo> xTalkMap1;
1270  map<WireID, XTalkInfo>::iterator iterXTalkMap1;
1271 
1272  // Loop over all cdc hits to create a xtalk map
1273  int OriginalNoOfHits = m_cdcHits.getEntries();
1274  B2DEBUG(m_debugLevel4XTalk, "\n \n" << "#CDCHits " << OriginalNoOfHits);
1275  for (const auto& aHit : m_cdcHits) {
1276  if (m_issue2ndHitWarning && aHit.is2ndHit()) {
1277  B2WARNING("2nd TDC hit found, but not ready for it!");
1278  }
1279  WireID wid(aHit.getID());
1280  // B2DEBUG(m_debugLevel4XTalk, "Encoded wireid of current CDCHit: " << wid);
1281  short tdcCount = aHit.getTDCCount();
1282  short adcCount = aHit.getADCCount();
1283  short tot = aHit.getTOT();
1284  short board = m_cdcgp->getBoardID(wid);
1285  short channel = m_cdcgp->getChannelID(wid);
1286  const vector<pair<short, asicChannel>> xTalks = (*m_xTalkFromDB)->getLibraryCrossTalk(channel, tdcCount, adcCount, tot);
1287 
1288  int nXTalks = xTalks.size();
1289  for (int i = 0; i < nXTalks; ++i) {
1290  const unsigned short tdcCount4XTalk = xTalks[i].second.TDC;
1291  if (i == 0) {
1292  B2DEBUG(m_debugLevel4XTalk, "\n" << " signal: " << channel << " " << tdcCount << " " << adcCount << " " << tot);
1293  }
1294  B2DEBUG(m_debugLevel4XTalk, "xtalk: " << xTalks[i].first << " " << tdcCount4XTalk << " " << xTalks[i].second.ADC << " " <<
1295  xTalks[i].second.TOT);
1296  WireID widx = m_cdcgp->getWireID(board, xTalks[i].first);
1297  if (!m_cdcgp->isBadWire(widx)) { // for non-bad wire
1298  if (m_includeEarlyXTalks || (xTalks[i].second.TDC <= tdcCount)) {
1299  const double t0 = getPositiveT0(widx);
1300  const double ULOfTDC = (t0 - m_lowEdgeOfTimeWindow[board]) * m_tdcBinWidthInv;
1301  const double LLOfTDC = (t0 - m_uprEdgeOfTimeWindow[board]) * m_tdcBinWidthInv;
1302  if (LLOfTDC <= tdcCount4XTalk && tdcCount4XTalk <= ULOfTDC) {
1303  const unsigned short status = 0;
1304  xTalkMap.insert(make_pair(widx, XTalkInfo(tdcCount4XTalk, xTalks[i].second.ADC, xTalks[i].second.TOT, status)));
1305  }
1306  }
1307  // } else {
1308  // cout<<"badwire= " << widx.getICLayer() <<" "<< widx.getIWire() << endl;
1309  }
1310  } //end of xtalk loop
1311  } //end of cdc hit loop
1312 
1313  //Loop over all xtalk hits to creat a new xtalk map with only the fastest hits kept (approx.)
1314  B2DEBUG(m_debugLevel4XTalk, "#xtalk hits: " << xTalkMap.size());
1315  for (const auto& aHit : xTalkMap) {
1316  WireID wid = aHit.first;
1317 
1318  iterXTalkMap1 = xTalkMap1.find(wid);
1319  unsigned short tdcCount = aHit.second.m_tdc;
1320  unsigned short adcCount = aHit.second.m_adc;
1321  unsigned short tot = aHit.second.m_tot;
1322  unsigned short status = aHit.second.m_status;
1323 
1324  if (iterXTalkMap1 == xTalkMap1.end()) { // new entry
1325  xTalkMap1.insert(make_pair(wid, XTalkInfo(tdcCount, adcCount, tot, status)));
1326  // B2DEBUG(m_debugLevel4XTalk, "Creating a new xtalk hit with encoded wire no.: " << wid);
1327  } else { // not new; check if fastest
1328  if (tdcCount < iterXTalkMap1->second.m_tdc) {
1329  iterXTalkMap1->second.m_tdc = tdcCount;
1330  B2DEBUG(m_debugLevel4XTalk, "TDC-count of current xtalk: " << tdcCount);
1331  }
1332  iterXTalkMap1->second.m_adc += adcCount;
1333  iterXTalkMap1->second.m_tot += tot; // approx.
1334  }
1335  } // end of xtalk loop
1336 
1337  //add xtalk in the same way as the beam bg. overlay
1338  B2DEBUG(m_debugLevel4XTalk, "#xtalk1 hits: " << xTalkMap1.size());
1339  for (const auto& aX : xTalkMap1) {
1340  bool append = true;
1341  const unsigned short tdc4Bg = aX.second.m_tdc;
1342  const unsigned short adc4Bg = aX.second.m_adc;
1343  const unsigned short tot4Bg = aX.second.m_tot;
1344  const unsigned short status4Bg = aX.second.m_status;
1345 
1346  for (int iHit = 0; iHit < OriginalNoOfHits; ++iHit) {
1347  CDCHit& aH = *(m_cdcHits[iHit]);
1348  if (aH.getID() != aX.first.getEWire()) { //wire id unmatched
1349  continue;
1350  } else { //wire id matched
1351  append = false;
1352  const unsigned short tdc4Sg = aH.getTDCCount();
1353  const unsigned short adc4Sg = aH.getADCCount();
1354  const unsigned short tot4Sg = aH.getTOT();
1355  // B2DEBUG(m_debuglevel4XTalk, "Sg tdc,adc,tot= " << tdc4Sg << " " << adc4Sg << " " << tot4Sg);
1356  // B2DEBUG(m_debugLevel4XTalk, "Bg tdc,adc,tot= " << tdc4Bg << " " << adc4Bg << " " << tot4Bg);
1357 
1358  // If the BG hit is faster than the true hit, the TDC count is replaced, and
1359  // the relations are removed. ADC counts are summed up.
1360  if (tdc4Sg < tdc4Bg) {
1361  aH.setTDCCount(tdc4Bg);
1362  aH.setStatus(status4Bg);
1363  auto relSimHits = aH.getRelationsFrom<CDCSimHit>();
1364  for (int i = relSimHits.size() - 1; i >= 0; --i) {
1365  relSimHits.remove(i);
1366  }
1367  auto relMCParticles = aH.getRelationsFrom<MCParticle>();
1368  for (int i = relMCParticles.size() - 1; i >= 0; --i) {
1369  relMCParticles.remove(i);
1370  }
1371  }
1372 
1373  aH.setADCCount(adc4Sg + adc4Bg);
1374 
1375  //Set TOT for signal+background case. It is assumed that the start timing
1376  //of a pulse (input to ADC) is given by the TDC-count. This is an
1377  //approximation becasue analog (for ADC) and digital (for TDC) parts are
1378  //different in the front-end electronics.
1379  unsigned short s1 = tdc4Sg; //start time of 1st pulse
1380  unsigned short s2 = tdc4Bg; //start time of 2nd pulse
1381  unsigned short w1 = tot4Sg; //its width
1382  unsigned short w2 = tot4Bg; //its width
1383  if (tdc4Sg < tdc4Bg) {
1384  s1 = tdc4Bg;
1385  w1 = tot4Bg;
1386  s2 = tdc4Sg;
1387  w2 = tot4Sg;
1388  }
1389  w1 *= 32;
1390  w2 *= 32;
1391  const unsigned short e1 = s1 - w1; //end time of 1st pulse
1392  const unsigned short e2 = s2 - w2; //end time of 2nd pulse
1393  // B2DEBUG(m_debuglevel4Xtalk, "s1,e1,w1,s2,e2,w2= " << s1 << " " << e1 << " " << w1 << " " << s2 << " " << e2 << " " << w2);
1394 
1395  double pulseW = w1 + w2;
1396  if (e1 <= e2) {
1397  pulseW = w1;
1398  } else if (e1 <= s2) {
1399  pulseW = s1 - e2;
1400  }
1401 
1402  unsigned short board = m_cdcgp->getBoardID(aX.first);
1403  aH.setTOT(std::min(std::round(pulseW / 32.), static_cast<double>(m_widthOfTimeWindowInCount[board])));
1404  B2DEBUG(m_debugLevel4XTalk, "replaced tdc,adc,tot,wid,status= " << aH.getTDCCount() << " " << aH.getADCCount() << " " << aH.getTOT()
1405  <<
1406  " " << aH.getID() << " " << aH.getStatus());
1407  break;
1408  }
1409  } //end of cdc hit loop
1410 
1411  if (append) {
1412  m_cdcHits.appendNew(tdc4Bg, adc4Bg, aX.first, status4Bg, tot4Bg);
1413  B2DEBUG(m_debugLevel4XTalk, "appended tdc,adc,tot,wid,status= " << tdc4Bg << " " << adc4Bg << " " << tot4Bg << " " << aX.first <<
1414  " " <<
1415  status4Bg);
1416  }
1417  } //end of x-talk loop
1418  B2DEBUG(m_debugLevel4XTalk, "original #hits, #hits= " << OriginalNoOfHits << " " << m_cdcHits.getEntries());
1419 }
1420 
1421 
1423 {
1424  double t0 = m_cdcgp->getT0(wid);
1425  if (t0 <= 0 && m_treatNegT0WiresAsGood) t0 = m_cdcgp->getMeanT0();
1426  // B2DEBUG(m_debugLevel, m_cdcgp->getT0(wid) <<" "<< m_cdcgp->getMeanT0() <<" "<< t0);
1427  return t0;
1428 }
DataType Z() const
access variable Z (= .at(2) without boundary check)
Definition: B2Vector3.h:435
DataType X() const
access variable X (= .at(0) without boundary check)
Definition: B2Vector3.h:431
DataType Y() const
access variable Y (= .at(1) without boundary check)
Definition: B2Vector3.h:433
DataType Mag() const
The magnitude (rho in spherical coordinate system).
Definition: B2Vector3.h:159
B2Vector3< DataType > Unit() const
Unit vector parallel to this.
Definition: B2Vector3.h:269
void SetY(DataType y)
set Y/2nd-coordinate
Definition: B2Vector3.h:459
double m_tdcThreshold4Inner
TDC threshold for inner layers in unit of eV.
double m_driftV
Nominal drift velocity (in cm/ns)
double Polya(double xmax=10)
Generate randum number according to Polya distribution.
unsigned short m_boardID
FEE board ID.
int m_eDepInGasMode
Mode for extracting dE(gas) from dE(gas+wire)
double m_tMaxInner
Upper edge of time window in ns for the inner layers.
double getdDdt(double driftLength)
The method to get dD/dt.
bool m_outputNegativeDriftTime
A switch to output negative drift time to CDCHit.
unsigned short m_widthOfTimeWindowInCount[c_nBoards]
Width of time window.
bool m_extraADCSmearing
Swtich for extra ADC smearing.
bool m_includeEarlyXTalks
Flag to switch on/off xtalks earlier than the hit.
void makeSignalsAfterShapers(const WireID &wid, double edep, double dx, double costh, unsigned short &adcCount, double &convFactorForThreshold)
Function to make signals after shapers.
int m_trgTimingOffsetInCount
Trigger timing offset in unit of count.
bool m_addInWirePropagationDelay4Bg
A switch used to control adding propagation delay into the total drift time or not for beam bg.
double getSemiTotalGain(int clayer, int cell) const
Return semi-total gain of the specified wire.
bool m_useDB4RunGain
Fetch run gain from DB.
DBObjPtr< CDCCrossTalkLibrary > * m_xTalkFromDB
Pointer to cross-talk from DB.
double m_analogGain
analog gain (V/pC)
double m_tdcBinWidthInv
m_tdcBinWidth^-1 (in ns^-1)
float m_uprEdgeOfTimeWindow[c_nBoards]
Upper edge of time-window.
double m_tMin
Lower edge of time window in ns.
bool m_output2ndHit
A switch to output 2nd hit.
int m_adcThreshold
Threshold for ADC in unit of count.
double m_resolution2
Resolution of the second Gassian used to smear drift length.
bool m_addTimeOfFlight
A switch used to control adding time of flight into the total drift time or not.
double m_trigTimeJitter
Magnitude of trigger timing jitter (ns).
void initialize() override
Initialize variables, print info, and start CPU clock.
double smearDriftLength(double driftLength, double dDdt)
Method used to smear the drift length.
std::string m_MCParticlesToSimHitsName
Relation for origin of incoming SimHits.
double m_digitalGain
digital gain (V/pC)
double m_totalFudgeFactor
total fudge factor for space resol.
std::string m_OptionalAllMCParticlesToHitsName
Relation name for optional matching of all MCParticles.
bool m_addInWirePropagationDelay
A switch used to control adding propagation delay into the total drift time or not.
bool m_align
A switch to control alignment.
void event() override
Actual digitization of all hits in the CDC.
unsigned short m_trgDelayInCount[c_nBoards]
Trigger delay in frontend electronics in count.
double m_globalTime
global time of this hit
bool m_doSmearing
A switch to control drift length smearing.
std::string m_inputCDCSimHitsName
Input array name.
DBObjPtr< CDCDedxWireGain > * m_wireGainFromDB
Pointer to wire gain from DB.
B2Vector3D m_posWire
wire position of this hit
bool m_addTimeOfFlight4Bg
A switch used to control adding time of flight into the total drift time or not for beam bg.
bool m_addXTalk
Flag to switch on/off crosstalk.
bool m_addTimeWalk
A switch used to control adding time-walk delay into the total drift time or not.
bool m_treatNegT0WiresAsGood
A switch for negative-t0 wires.
double m_addFudgeFactorForSigma
additional fudge factor for space resol.
bool m_matchAllMCParticles
A switch to match all particles to a hit, regardless wether they produced a hit or not.
bool m_useDB4EDepToADC
Fetch edep-to-ADC conversion params.
std::string m_SimHitsTOCDCHitsName
Relation for outgoing CDCHits.
int m_offsetForTriggerBin
Input to getCDCTriggerBin(offset)
void setSemiTotalGain()
Set semi-total gain (from DB)
double m_driftLength
drift length of this hit
double m_tdcResol
TDC resolution (in ns)
int m_tSimMode
Timing simulation mode.
bool m_useDB4FEE
Fetch FEE params from DB.
double m_adcBinWidth
ADC bin width (mV)
double m_thetaOfPolya
theta of Polya function for gas gain smearing
bool m_matchFirstMCParticles
A switch to match first three MCParticles, not just the one with smallest drift time.
bool m_spaceChargeEffect
Space charge effect.
double m_driftVInv
m_driftV^-1 (in ns/cm)
StoreArray< CDCSimHit > m_simHits
CDCSimHit array.
DBObjPtr< CDCCorrToThresholds > * m_corrToThresholdFromDB
Pointer to threshold correction from DB.
std::string m_OptionalFirstMCParticlesToHitsName
Relation name for optional matching of up to first three MCParticles.
StoreArray< CDCHit > m_cdcHits4Trg
CDCHit4trg array.
float m_semiTotalGain[c_maxNSenseLayers][c_maxNDriftCells]
total gain per wire
DBObjPtr< CDCDedxRunGain > * m_runGainFromDB
Pointer to run gain from DB.
double m_degOfSPEOnThreshold
Degree of space charge effect on timing threshold.
bool m_randomization
Flag to switch on/off timing randmization.
CDCSimHit * m_aCDCSimHit
Pointer to CDCSimHit.
WireID m_wireID
WireID of this hit.
DBObjPtr< CDCDedxScaleFactor > * m_gain0FromDB
Pointer to overall gain factor from DB.
double m_effWForGasGainSmearing
Effective energy (keV) for one electron prod.
bool m_issue2ndHitWarning
Flag to switch on/off a warning on the 2nd TDC hit.
double getPositiveT0(const WireID &)
Modify t0 for negative-t0 case.
double m_tdcThreshold4Outer
TDC threshold for outer layers in unit of eV.
double m_tdcThresholdOffset
Offset for TDC(digital) threshold (mV)
double m_fraction
Fraction of the first Gaussian used to smear drift length.
int m_debugLevel4XTalk
Debug level for crosstalk.
int m_shiftOfTimeWindowIn32Count
Shift of time window for synchronization in 32count.
unsigned short m_posFlag
left or right flag of this hit
std::string m_outputCDCHitsName4Trg
Output array name for trigger.
StoreArray< CDCHit > m_cdcHits
CDCHit array.
double m_mean1
Mean value of the first Gassian used to smear drift length.
bool m_synchronization
Flag to switch on/off timing synchronization.
float m_lowEdgeOfTimeWindow[c_nBoards]
Lower edge of time-window.
double getDriftTime(double driftLength, bool addTof, bool addDelay)
The method to get drift time based on drift length.
std::string m_outputCDCHitsName
Output array name.
float m_tdcThresh[c_nBoards]
Threshold for timing-signal.
B2Vector3D m_momentum
3-momentum of this hit
StoreArray< MCParticle > m_mcParticles
Set edep-to-ADC conversion params.
bool m_gasGainSmearing
Swtich for gas gain smearing.
double m_tMaxOuter
Upper edge of time window in ns for the outer layers.
DBArray< CDCFEElectronics > * m_fEElectronicsFromDB
Pointer to FE electronics params.
double m_resolution1
Resolution of the first Gassian used to smear drift length.
B2Vector3D m_posTrack
track position of this hit
bool m_useSimpleDigitization
Use float Gaussian Smearing instead of proper digitization.
CDC::CDCGeometryPar * m_cdcgp
Cached Pointer to CDCGeometryPar.
double m_overallGainFactor
Overall gain factor.
void setFEElectronics()
Set FEE parameters (from DB)
double m_mean2
Mean value of the second Gassian used to smear drift length.
double m_tdcBinWidth
Width of a TDC bin (in ns)
CDC::CDCGeoControlPar * m_gcp
Cached pointer to CDCGeoControlPar.
bool m_correctForWireSag
A switch to control wire sag.
StoreObjPtr< SimClockState > m_simClockState
generated hardware clock state
double m_flightTime
flight time of this hit
float m_adcThresh[c_nBoards]
Threshold for FADC.
Database object for Fron-endt electronics params.
Class containing the result of the unpacker in raw data and the result of the digitizer in simulation...
Definition: CDCHit.h:40
void setTDCCount(short tdcCount)
Setter for TDC count.
Definition: CDCHit.h:128
void set2ndHitFlag()
Setter for 2nd hit flag.
Definition: CDCHit.h:113
short getTDCCount() const
Getter for TDC count.
Definition: CDCHit.h:219
void setTOT(unsigned short tot)
Setter for TOT.
Definition: CDCHit.h:160
unsigned short getID() const
Getter for encoded wire number.
Definition: CDCHit.h:193
unsigned short getStatus() const
Getter for CDCHit status.
Definition: CDCHit.h:199
void setADCCount(unsigned short adcCount)
Setter for ADC count.
Definition: CDCHit.h:135
unsigned short getADCCount() const
Getter for integrated charge.
Definition: CDCHit.h:230
unsigned short getTOT() const
Getter for TOT.
Definition: CDCHit.h:248
void setOtherHitIndices(CDCHit *otherHit)
Setter for the other hit indices.
Definition: CDCHit.h:147
void setStatus(unsigned short status)
Setter for CDCHit status.
Definition: CDCHit.h:106
Example Detector.
Definition: CDCSimHit.h:21
int getPDGCode() const
The method to get PDG code.
Definition: CDCSimHit.h:178
double getStepLength() const
The method to get step length.
Definition: CDCSimHit.h:190
double getFlightTime() const
The method to get flight time.
Definition: CDCSimHit.h:184
B2Vector3D getPosWire() const
The method to get position on wire.
Definition: CDCSimHit.h:199
float getGlobalTime() const override
The method to get global time.
Definition: CDCSimHit.h:248
WireID getWireID() const
Getter for WireID object.
Definition: CDCSimHit.h:172
double getEnergyDep() const
The method to get deposited energy.
Definition: CDCSimHit.h:187
B2Vector3D getPosTrack() const
The method to get position on the track.
Definition: CDCSimHit.h:217
double getDriftLength() const
The method to get drift length.
Definition: CDCSimHit.h:181
B2Vector3D getMomentum() const
The method to get momentum.
Definition: CDCSimHit.h:193
B2Vector3D getPosIn() const
The method to get position of pre-step.
Definition: CDCSimHit.h:205
B2Vector3D getPosOut() const
The method to get position of post-step.
Definition: CDCSimHit.h:211
int getLeftRightPassageRaw() const
The method to get new left/right info. for digitization.
Definition: CDCSimHit.h:229
int getSenseWireZposMode() const
Get sense wire z position mode.
static CDCGeoControlPar & getInstance()
Static method to get a reference to the CDCGeoControlPar instance.
The Class for CDC Geometry Parameters.
double getTimeWalk(const WireID &wID, unsigned short adcCount) const
Returns time-walk.
double getNominalPropSpeed() const
Return the nominal propagation speed of the sense wire (default: 27.25 cm/nsec).
double getTheta(const B2Vector3D &momentum) const
Returns track incident angle (theta in rad.).
unsigned short getBoardID(const WireID &wID) const
Returns frontend board id. corresponding to the wire id.
EWirePosition
Wire position set.
void getWireSagEffect(EWirePosition set, unsigned layerID, unsigned cellID, double zw, double &ywb_sag, double &ywf_sag) const
Compute effects of the sense wire sag.
double getAlpha(const B2Vector3D &posOnWire, const B2Vector3D &momentum) const
Returns track incident angle in rphi plane (alpha in rad.).
ushort getOffsetOfFirstLayer() const
Get the offset of the first layer.
const B2Vector3D wireForwardPosition(uint layerId, int cellId, EWirePosition set=c_Base) const
Returns the forward position of the input sense wire.
bool isDeadWire(const WireID &wid, double &eff)
Inquire if the wire is dead.
const WireID getWireID(unsigned short bd, unsigned short ch) const
Returns wire id. corresponding to the board-and-cannel ids.
double getDriftV(double dt, unsigned short layer, unsigned short lr, double alpha=0., double theta=0.5 *M_PI) const
Get the realistic drift velocity.
const B2Vector3D wireBackwardPosition(uint layerId, int cellId, EWirePosition set=c_Base) const
Returns the backward position of the input sense wire.
double getTdcBinWidth() const
Return TDC bin width (nsec).
float getT0(const WireID &wireID) const
Returns t0 parameter of the specified sense wire.
double getSigma(double dist, unsigned short layer, unsigned short lr, double alpha=0., double theta=0.5 *M_PI) const
Return the basic resolution of drift length (cm).
double getFudgeFactorForSigma(unsigned short target) const
Return the fuge factor for space resol.
unsigned nWiresInLayer(int layerId) const
Returns wire numbers in a layer.
double getBwdDeltaZ(unsigned short layerID) const
Return backward 'deltaZ'.
double getEDepToADCSigma(unsigned short layer, unsigned short cell)
Return sigma for extra smearing of edep to ADC conversion.
double getNominalDriftV() const
Return the nominal drift velocity of He-ethane gas (default: 4.0x10^-3 cm/nsec).
double getMeanT0() const
Returns the mean t0 over all wires.
double getPropSpeedInv(const unsigned int layerID) const
Get the inversel of propagation speed in the sense wire.
double getEDepToADCConvFactor(unsigned short layer, unsigned short cell, double edep, double dx, double costh)
Return edep-to-ADC conversion factor.
double getDriftTime(double dist, unsigned short layer, unsigned short lr, double alpha, double theta) const
Return the drift time to the sense wire.
double getDriftLength(double dt, unsigned short layer, unsigned short lr, double alpha=0., double theta=0.5 *M_PI, bool calculateMinTime=true, double minTime=0.) const
Return the drift dength to the sense wire.
bool isBadWire(const WireID &wid)
Inquire if the wire is totally-dead.
int getMaterialDefinitionMode() const
Return mode for material definition.
static CDCGeometryPar & Instance(const CDCGeometry *=nullptr)
Static method to get a reference to the CDCGeometryPar instance.
ushort getOffsetOfFirstSuperLayer() const
Get the offset of the first super layer.
unsigned short getChannelID(const WireID &wID) const
Returns frontend channel id. corresponding to the wire id.
unsigned short getNewLeftRightRaw(const B2Vector3D &posOnWire, const B2Vector3D &posOnTrack, const B2Vector3D &momentum) const
Returns new left/right_raw.
double getEDepToADCMainFactor(unsigned short layer, unsigned short cell, double costh=0)
Return edep-to-ADC conversion main factor (in count/keV)
The Class for Energy deposit in the gas.
Definition: EDepInGas.h:20
static EDepInGas & getInstance()
Static method to get a reference to the EDepInGas instance.
Definition: EDepInGas.cc:23
double getEDepInGas(int mode, int pdg, double p, double dx, double e3) const
Return the energy deosite in the gas.
Definition: EDepInGas.cc:137
void addCallback(std::function< void(const std::string &)> callback, bool onDestruction=false)
Add a callback method.
Class for accessing arrays of objects in the database.
Definition: DBArray.h:26
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
@ c_WriteOut
Object/array should be saved by output modules.
Definition: DataStore.h:70
@ c_Event
Different object in each event, all objects/arrays are invalidated after event() function has been ca...
Definition: DataStore.h:59
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
int getIndex() const
Get 1-based index of the particle in the corresponding MCParticle list.
Definition: MCParticle.h:230
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
Low-level class to create/modify relations between StoreArrays.
Definition: RelationArray.h:62
void add(index_type from, index_type to, weight_type weight=1.0)
Add a new element to the relation.
Class for type safe access to objects that are referred to in relations.
size_t size() const
Get number of relations.
float weight(int index) const
Get weight with index.
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).
RelationVector< FROM > getRelationsFrom(const std::string &name="", const std::string &namedRelation="") const
Get the relations that point from another store array to this object.
virtual unsigned short getBackgroundTag() const
Get background tag.
Definition: SimHitBase.h:46
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
static const double keV
[kiloelectronvolt]
Definition: Unit.h:113
static const double eV
[electronvolt]
Definition: Unit.h:112
static const double cm
Standard units with the value = 1.
Definition: Unit.h:47
Class to identify a wire inside the CDC.
Definition: WireID.h:34
unsigned short getICLayer() const
Getter for continuous layer numbering.
Definition: WireID.cc:24
unsigned short getIWire() const
Getter for wire within the layer.
Definition: WireID.h:145
unsigned short getISuperLayer() const
Getter for Super-Layer.
Definition: WireID.h:130
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
double ClosestApproach(const B2Vector3D &bwp, const B2Vector3D &fwp, const B2Vector3D &posIn, const B2Vector3D &posOut, B2Vector3D &hitPosition, B2Vector3D &wirePosition)
Returns a closest distance between a track and a wire.
Abstract base class for different kinds of events.
Structure for saving the signal information.
Structure for saving the x-talk information.