13 #include "CLHEP/Random/RandFlat.h"
14 #include "CLHEP/Random/RandomEngine.h"
15 #include "CLHEP/Units/SystemOfUnits.h"
16 #include "GaudiKernel/MsgStream.h"
26 #include "GaudiKernel/Bootstrap.h"
39 :
AthMessaging(
"TgcDigitMaker"), m_doFourBunchDigitization(doFourBunch) {
82 return StatusCode::SUCCESS;
89 const TGCSimHit* hit,
const double globalHitTime,
92 CLHEP::HepRandomEngine* rndmEngine) {
94 constexpr
float sensor_propagation_time =
102 constexpr
float wire_pitch = 1.8 *
CLHEP::mm;
103 constexpr
float zwidth_frame = 17. *
CLHEP::mm;
108 int Id = hit->
TGCid();
135 <<
"context begin_index = " << tgcContext.
begin_index()
136 <<
" context end_index = " << tgcContext.
end_index()
137 <<
" the identifier is " << elemId);
141 std::unique_ptr<TgcDigitCollection> digits =
142 std::make_unique<TgcDigitCollection>(elemId, coll_hash);
145 float height = tgcChamber->
getRsize();
146 float hmin = sqrt(
pow(centreChamber.x(), 2) +
pow(centreChamber.y(), 2)) -
156 float distanceZ = 1.4 *
CLHEP::mm / direCos[0] * direCos[2];
157 float zLocal = localPos.z() + distanceZ;
160 float distanceY = 1.4 *
CLHEP::mm / direCos[0] * direCos[1];
164 float yLocal = ySign * (localPos.y() + distanceY);
169 double tofCorrection =
170 (sqrt(
pow(hmin + zwidth_frame, 2) +
pow(centreChamber.z(), 2)) /
174 float bunchTime = globalHitTime - tofCorrection;
176 static const float jitterInitial = 9999.;
177 float jitter = jitterInitial;
198 kWIRE, rndmEngine))) {
201 float posInWireGroup[2] = {0., 0.};
202 for (
int iPosition = 0; iPosition < 2; iPosition++) {
203 int nWireOffset = (std::abs(
stationEta) == 5 ||
211 double zPosInSensArea =
212 zLocal +
static_cast<double>(tgcChamber->
nWires(ilyr) -
217 if (zPosInSensArea < 0. ||
218 zPosInSensArea > tgcChamber->
nWires(ilyr) * wire_pitch) {
219 iWireGroup[iPosition] = 0;
220 posInWireGroup[iPosition] = 0.;
222 "executeDigi(): Wire: Hit position located at outside of a "
226 <<
" position: " << zPosInSensArea <<
" xlocal: " << zLocal
227 <<
" dir cosine: " << direCos[0] <<
"/" << direCos[1] <<
"/"
229 <<
" active region: " << height - zwidth_frame * 2.);
233 while (wire_pitch * (
static_cast<float>(wire_index)) <
235 igang <= tgcChamber->nWireGangs(ilyr)) {
236 wire_index += tgcChamber->
nWires(ilyr, igang);
239 posInWireGroup[iPosition] =
240 (zPosInSensArea / wire_pitch -
241 (
static_cast<float>(wire_index))) /
243 tgcChamber->
nWires(ilyr, igang - 1))) +
246 iWireGroup[iPosition] = ((1 == igang) ? 1 : igang - 1);
250 unsigned int jWG[2] = {
251 (iWireGroup[0] <= iWireGroup[1]) ? (
unsigned int)(0)
253 (iWireGroup[0] <= iWireGroup[1]) ? (
unsigned int)(1)
254 : (
unsigned int)(0)};
255 int iWG[2] = {iWireGroup[jWG[0]], iWireGroup[jWG[1]]};
256 float posInWG[2] = {posInWireGroup[jWG[0]], posInWireGroup[jWG[1]]};
257 if (iWG[0] != iWG[1]) {
258 ATH_MSG_DEBUG(
"executeDigi(): Multihits found in WIRE GROUPs:"
259 << iWG[0] <<
" " << iWG[1]);
263 for (
int iwg = iWG[0]; iwg <= iWG[1]; iwg++) {
264 if (1 <= iwg && iwg <= tgcChamber->nWireGangs(ilyr)) {
266 float wire_timeOffset =
272 if (iStationName > 46)
280 float ySignPhi = (
stationPhi % 2 == 1) ? -1. : +1.;
284 float wTimeDiffByRadiusOfInner =
288 bunchTime + jitter + wTimeDiffByRadiusOfInner;
289 float wASDDis{-1000.};
290 if (ASDpos !=
nullptr) {
295 wASDDis + (ySignPhi * yLocal +
298 sensor_propagation_time *
301 cable_propagation_time * wASDDis;
314 "WireGroup: digitized time "
315 << digit_time <<
" ns is outside of time window from "
316 << wire_timeOffset <<
". bunchTime: " << bunchTime
317 <<
" time jitter: " << jitter <<
" propagation time: "
318 << sensor_propagation_time *
321 cable_propagation_time * wASDDis
322 <<
" time difference by cable radius of inner station: "
323 << wTimeDiffByRadiusOfInner);
328 addDigit(newId, bctag, digits.get());
332 posInWG[0], digit_time, wire_timeOffset,
333 rndmEngine, digits.get());
337 "WireGroup: newid breakdown digitTime x/y/z direcos "
338 "height_gang bctag: "
341 <<
"WIRE/" << iwg <<
" " << digit_time <<
" "
342 << localPos.x() <<
"/" << localPos.y() <<
"/"
343 << localPos.z() <<
" " << direCos.x() <<
"/"
344 << direCos.y() <<
"/" << direCos.z() <<
" " << height
345 <<
" " << tgcChamber->
nWires(ilyr, iwg) <<
" "
350 "Wire Gang id is out of range. id, x/y/z, height: "
351 << iwg <<
" " << localPos.x() <<
"/" << localPos.y() <<
"/"
352 << localPos.z() <<
" " << height);
360 if ((ilyr != 2 || (
stationName.compare(0, 2,
"T1") !=
364 sensor, rndmEngine)) ||
373 float posInStrip[2] = {0., 0.};
375 for (
int iPosition = 0; iPosition < 2; iPosition++) {
378 float zPos = zLocal + height / 2. - zwidth_frame;
380 iStrip[iPosition] = 0;
381 posInStrip[iPosition] = 0.;
383 "Strip: Hit position located at outside of a sensitive "
384 "volume, id, position, xlocal0/1, dir cosine: "
386 <<
"/" << ilyr << zPos <<
" " << zLocal <<
" " << direCos[0]
387 <<
"/" << direCos[1] <<
"/" << direCos[2]);
388 }
else if (zPos > height - zwidth_frame * 2.) {
389 iStrip[iPosition] = tgcChamber->
nStrips(ilyr) + 1;
390 posInStrip[iPosition] = 0.;
392 "Strip: Hit position located at outside of a sensitive "
393 "volume, id, position, active region: "
395 <<
"/" << ilyr << zPos <<
" "
396 << height - zwidth_frame * 2.);
405 float phiLocal = atan2(yLocal, zLocal + height / 2. + hmin);
408 "dphi, phiLocal, yLocal, zLocall+ height/2.+hmin: "
409 << dphi <<
" " << phiLocal <<
" " << yLocal <<
" "
410 << zLocal + height / 2. + hmin);
415 istr =
static_cast<int>(floor(phiLocal / dphi + 15.75)) + 1;
416 posInStrip[iPosition] =
417 phiLocal / dphi + 15.75 -
static_cast<float>(istr - 1);
419 istr =
static_cast<int>(floor(
420 (phiLocal - dphi * 14.25) / (dphi / 2.))) +
422 posInStrip[iPosition] =
423 (phiLocal - dphi * 14.25) / (dphi / 2.) -
424 static_cast<float>(istr - 31);
427 istr =
static_cast<int>(floor(phiLocal / dphi + 16.25)) + 1;
428 posInStrip[iPosition] =
429 phiLocal / dphi + 16.25 -
static_cast<float>(istr - 1);
431 istr =
static_cast<int>(floor(
432 (phiLocal + dphi * 14.25) / (dphi / 2.))) +
434 posInStrip[iPosition] =
435 (phiLocal + dphi * 14.25) / (dphi / 2.) -
436 static_cast<float>(istr - 3);
441 posInStrip[iPosition] = 0.;
442 }
else if (32 < istr) {
444 posInStrip[iPosition] = 0.;
446 iStrip[iPosition] = istr;
450 unsigned int jStr[2] = {
451 (iStrip[0] <= iStrip[1]) ? (
unsigned int)(0) : (
unsigned int)(1),
452 (iStrip[0] <= iStrip[1]) ? (
unsigned int)(1) : (
unsigned int)(0)};
453 int iStr[2] = {iStrip[jStr[0]], iStrip[jStr[1]]};
454 float posInStr[2] = {posInStrip[jStr[0]], posInStrip[jStr[1]]};
455 if (iStr[0] != iStr[1]) {
461 float strip_timeOffset =
466 for (
int istr = iStr[0]; istr <= iStr[1]; istr++) {
467 if (1 <= istr && istr <= 32) {
469 if (jitter > jitterInitial - 0.1) {
478 float sTimeDiffByRadiusOfInner =
483 sensor_propagation_time *
484 (height / 2. + zwidth_frame + zSignEta * zLocal) +
485 sTimeDiffByRadiusOfInner;
486 float sASDDis{-1000};
487 if (ASDpos !=
nullptr) {
492 float sCableDis = sASDDis + (height / 2. + zwidth_frame +
495 sASDDis * cable_propagation_time;
506 "Strip: Digitized time is outside of time window. "
507 << sDigitTime <<
" bunchTime: " << bunchTime
508 <<
" time jitter: " << jitter <<
" propagation time: "
509 << sensor_propagation_time *
510 (height / 2. + zwidth_frame + zSignEta * zLocal)
511 <<
" time difference by cable radius of inner station: "
512 << sTimeDiffByRadiusOfInner);
517 addDigit(newId, bctag, digits.get());
519 if (istr == iStr[0]) {
521 iStr[0], posInStr[0], sDigitTime,
522 strip_timeOffset, rndmEngine,
527 "Strip: newid breakdown digitTime x/y/z direcos "
530 <<
"/" <<
stationPhi <<
"/" << ilyr <<
"/" << sensor
531 <<
"/" << istr <<
" " << sDigitTime <<
" "
532 << localPos.x() <<
"/" << localPos.y() <<
"/"
533 << localPos.z() <<
" " << direCos.x() <<
"/"
534 << direCos.y() <<
"/" << direCos.z() <<
" "
535 << height / 2. + hmin <<
" " << bctag);
539 << ilyr <<
" " << istr);
544 return digits.release();
549 const char*
const fileName =
"TGC_Digitization_timejitter.dat";
553 if (!fileWithPath.empty()) {
554 ifs.open(fileWithPath.c_str(), std::ios::in);
558 return StatusCode::FAILURE;
564 return StatusCode::FAILURE;
578 "readFileOfTimeJitter(): Timejitter, angle, Number of bins, prob. "
582 for (
int j = 0; j < 41 ; j++) {
595 return StatusCode::SUCCESS;
599 CLHEP::HepRandomEngine* rndmEngine)
const {
600 float injectionAngle =
601 atan2(fabs(direCosLocal[2]), fabs(direCosLocal[0])) /
CLHEP::degree;
603 int ithAngle =
static_cast<int>(injectionAngle / 5.);
604 float wAngle = injectionAngle / 5. -
static_cast<float>(ithAngle);
610 jthAngle = ithAngle + 1;
617 while (
prob > probRef) {
618 prob = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0);
619 jitter = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0) * 40. *
621 int ithJitter =
static_cast<int>(jitter);
631 CLHEP::HepRandomEngine* rndmEngine)
const {
632 if (CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0) <
m_efficiency[sensor])
635 << sensor <<
"(0=WIRE,1=STRIP)");
650 const double offset)
const {
651 const double calc_coll_time =
658 if (0. < calc_coll_time && calc_coll_time < window) {
676 if ((bctag >> (bc - 1)) & 0
x1) {
677 bool duplicate =
false;
678 for (
const auto digit : *digits) {
679 if (
id ==
digit->identify() &&
digit->bcTag() == bc) {
685 std::unique_ptr<TgcDigit> multihitDigit =
686 std::make_unique<TgcDigit>(
id, bc);
687 digits->push_back(multihitDigit.release());
697 for (iStationName = 0; iStationName <
N_STATIONNAME; iStationName++) {
711 const std::string
fileName =
"TGC_Digitization_energyThreshold.dat";
713 if (fileWithPath.empty()) {
714 ATH_MSG_FATAL(
"readFileOfEnergyThreshold(): Could not find file "
716 return StatusCode::FAILURE;
721 ifs.open(fileWithPath.c_str(), std::ios::in);
723 ATH_MSG_FATAL(
"readFileOfEnergyThreshold(): Could not open file "
725 return StatusCode::FAILURE;
728 double energyThreshold;
734 <<
" stationName= " << iStationName <<
" stationEta= "
737 <<
" energyThreshold(MeV)= " << energyThreshold);
753 if (gasGap < 0 || gasGap >=
N_GASGAP)
769 return StatusCode::SUCCESS;
777 SmartIF<IGeoModelSvc> geoModel{Gaudi::svcLocator()->service(
"GeoModelSvc")};
782 std::string atlasVersion = geoModel->atlasVersion();
784 SmartIF<IRDBAccessSvc> rdbAccess{Gaudi::svcLocator()->service(
"RDBAccessSvc")};
791 rdbAccess->getRecordsetPtr(
"AtlasCommon", atlasVersion,
"ATLAS");
793 if (atlasCommonRec->size() == 0)
796 std::string configVal = (*atlasCommonRec)[0]->getString(
"CONFIG");
797 if (configVal ==
"RUN1")
799 else if (configVal ==
"RUN2")
801 else if (configVal ==
"RUN3")
804 else if (configVal ==
"RUN4")
810 "Unexpected value for geometry config read from the database: "
822 for (iStationName = 0; iStationName <
N_STATIONNAME; iStationName++) {
836 return StatusCode::FAILURE;
842 fileName =
"TGC_Digitization_deadChamber.dat";
844 fileName =
"TGC_Digitization_2016deadChamber.dat";
846 fileName =
"TGC_Digitization_NOdeadChamber.dat";
849 <<
" is unexpected in TgcDigitMaker - "
850 "using NOdeadChamber configuration.");
851 return StatusCode::FAILURE;
854 if (fileWithPath.empty()) {
855 ATH_MSG_FATAL(
"readFileOfDeadChamber(): Could not find file "
857 return StatusCode::FAILURE;
862 ifs.open(fileWithPath.c_str(), std::ios::in);
864 ATH_MSG_FATAL(
"readFileOfDeadChamber(): Could not open file "
866 return StatusCode::FAILURE;
870 unsigned int nDeadChambers = 0;
879 <<
" stationName= " << iStationName <<
" stationEta= "
896 if (gasGap < 0 || gasGap >=
N_GASGAP)
910 ATH_MSG_INFO(
"readFileOfDeadChamber: the number of dead chambers = "
913 return StatusCode::SUCCESS;
920 for (iStationName = 0; iStationName <
N_STATIONNAME; iStationName++) {
929 const std::string
fileName =
"TGC_Digitization_StripPosition.dat";
931 if (fileWithPath.empty()) {
932 ATH_MSG_FATAL(
"readFileOfStripPosition(): Could not find file "
934 return StatusCode::FAILURE;
939 ifs.open(fileWithPath.c_str(), std::ios::in);
941 ATH_MSG_FATAL(
"readFileOfStripPosition(): Could not open file "
943 return StatusCode::FAILURE;
951 <<
" stationName= " << iStationName <<
" stationEta= "
953 <<
" StripPosition= " << strippos);
975 return StatusCode::SUCCESS;
991 double energyThreshold = +999999.;
1008 << sensor <<
" energyThreshold(MeV)= " << energyThreshold);
1010 return energyThreshold;
1017 const float posInChan,
const float digitTime,
const float time_offset,
1032 float prob1CrossTalk =
1034 float prob11CrossTalk =
1036 float prob20CrossTalk =
1038 float prob21CrossTalk =
1041 int nCrossTalks_neg = 0;
1042 int nCrossTalks_pos = 0;
1044 if (posInChan < prob1CrossTalk) {
1045 nCrossTalks_neg = 1;
1046 }
else if (posInChan > 1. - prob1CrossTalk) {
1047 nCrossTalks_pos = 1;
1049 double prob = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0);
1050 if (
prob < prob11CrossTalk / (1. - 2. * prob1CrossTalk)) {
1051 nCrossTalks_neg = 1;
1052 nCrossTalks_pos = 1;
1053 }
else if (
prob < (prob20CrossTalk + prob11CrossTalk) /
1054 (1. - 2. * prob1CrossTalk)) {
1055 if (posInChan < 0.5) {
1056 nCrossTalks_neg = 2;
1059 nCrossTalks_pos = 2;
1063 (prob20CrossTalk + prob11CrossTalk + 2. * prob21CrossTalk) /
1064 (1. - 2. * prob1CrossTalk)) {
1065 if (posInChan < 0.5) {
1066 nCrossTalks_neg = 2;
1067 nCrossTalks_pos = 1;
1070 nCrossTalks_neg = 1;
1071 nCrossTalks_pos = 2;
1077 if (nCrossTalks_neg == 0 && nCrossTalks_pos == 0)
1081 float dt = digitTime;
1090 for (
int jChan =
channel - nCrossTalks_neg;
1091 jChan <=
channel + nCrossTalks_pos; jChan++) {
1092 if (jChan ==
channel || jChan < 1 || jChan > maxChannelNumber)
1103 bool v_isDeadChamber =
true;
1129 <<
" isDeadChamber= " << v_isDeadChamber);
1131 return v_isDeadChamber;
1135 int iStationName = 0;
1153 return iStationName;
1181 if (iStationName != 47 && iStationName != 48)
1200 const int channel,
const float position)
const {
1203 int phiId = (iStationName >= 47) ?
stationPhi : 0x1f;
1206 unsigned int asdNo =
static_cast<unsigned int>(
channel - 1) /
1209 float asd_position = 0.;
1211 auto it = map.find(chamberId);
1213 if (
it != map.end()) {
1218 <<
", phi=" << phiId);
1221 float distance = fabs(position - asd_position);
1230 (station_num << 3) + static_cast<uint16_t>(std::abs(
station_eta));
1231 return ((sensor == TgcSensor::kSTRIP)
1233 : readCdo->
wireOffset.find(chamberId)->second);
1238 const TgcSensor sensor,
const unsigned int index_prob) {
1239 if (readCdo ==
nullptr)
1241 return ((sensor == TgcSensor::kSTRIP)