File indexing completed on 2025-12-17 09:22:13
0001 #include "PHG4TpcPadPlaneReadout.h"
0002
0003 #include <fun4all/Fun4AllReturnCodes.h>
0004 #include <g4detectors/PHG4CellDefs.h> // for genkey, keytype
0005 #include <g4detectors/PHG4TpcGeom.h>
0006 #include <g4detectors/PHG4TpcGeomContainer.h>
0007
0008 #include <g4main/PHG4Hit.h> // for PHG4Hit
0009 #include <g4main/PHG4HitContainer.h>
0010
0011 #include <phool/PHRandomSeed.h>
0012 #include <phool/getClass.h>
0013
0014 #include <cdbobjects/CDBTTree.h>
0015 #include <ffamodules/CDBInterface.h>
0016
0017
0018 #include <trackbase/TpcDefs.h>
0019 #include <trackbase/TrkrDefs.h> // for hitkey, hitse...
0020 #include <trackbase/TrkrHit.h> // for TrkrHit
0021 #include <trackbase/TrkrHitSet.h>
0022 #include <trackbase/TrkrHitSetContainer.h>
0023 #include <trackbase/TrkrHitv2.h> // for TrkrHit
0024
0025 #include <g4tracking/TrkrTruthTrack.h>
0026 #include <g4tracking/TrkrTruthTrackContainer.h>
0027 #include <g4tracking/TrkrTruthTrackContainerv1.h>
0028 #include <g4tracking/TrkrTruthTrackv1.h>
0029
0030 #include <phool/phool.h> // for PHWHERE
0031
0032 #include <TF1.h>
0033 #include <TFile.h>
0034 #include <TH2.h>
0035 #include <TSystem.h>
0036
0037 #include <gsl/gsl_randist.h>
0038 #include <gsl/gsl_rng.h> // for gsl_rng_alloc
0039
0040 #include <cmath>
0041 #include <cstdlib> // for getenv
0042 #include <format>
0043 #include <iostream>
0044 #include <map> // for _Rb_tree_cons...
0045 #include <utility> // for pair
0046
0047 class PHCompositeNode;
0048 class TrkrHitTruthAssoc;
0049
0050 namespace
0051 {
0052
0053 template <class T>
0054 constexpr T square(const T &x)
0055 {
0056 return x * x;
0057 }
0058
0059 template <class T>
0060 inline T get_r(const T &x, const T &y)
0061 {
0062 return std::sqrt(square(x) + square(y));
0063 }
0064
0065
0066 template <class T>
0067 inline T gaus(const T &x, const T &sigma)
0068 {
0069 return std::exp(-square(x / sigma) / 2) / (sigma * std::sqrt(2 * M_PI));
0070 }
0071
0072 constexpr unsigned int print_layer = 18;
0073
0074 }
0075
0076 PHG4TpcPadPlaneReadout::PHG4TpcPadPlaneReadout(const std::string &name)
0077 : PHG4TpcPadPlane(name)
0078 , RandomGenerator(gsl_rng_alloc(gsl_rng_mt19937))
0079 {
0080 InitializeParameters();
0081
0082 ReadGain();
0083
0084 gsl_rng_set(RandomGenerator, PHRandomSeed());
0085
0086 return;
0087 }
0088
0089 PHG4TpcPadPlaneReadout::~PHG4TpcPadPlaneReadout()
0090 {
0091 gsl_rng_free(RandomGenerator);
0092 for (auto *his : h_gain)
0093 {
0094 delete his;
0095 }
0096 }
0097
0098
0099 int PHG4TpcPadPlaneReadout::InitRun(PHCompositeNode *topNode)
0100 {
0101
0102 const auto reply = PHG4TpcPadPlane::InitRun(topNode);
0103 if (reply != Fun4AllReturnCodes::EVENT_OK)
0104 {
0105 return reply;
0106 }
0107 const std::string seggeonodename = "TPCGEOMCONTAINER";
0108 GeomContainer = findNode::getClass<PHG4TpcGeomContainer>(topNode, seggeonodename);
0109 assert(GeomContainer);
0110
0111 PHG4TpcGeom *layergeom = GeomContainer->GetLayerCellGeom(20);
0112 double tpc_adc_clock = layergeom->get_adc_clock();
0113 double extended_readout_time = layergeom->get_extended_readout_time();
0114 double maxdriftlength = layergeom->get_max_driftlength();
0115 double drift_velocity_sim = layergeom->get_drift_velocity_sim();
0116 const double TBinWidth = tpc_adc_clock;
0117 const double MaxT = extended_readout_time + 2.0 * maxdriftlength / drift_velocity_sim;
0118 const double MinT = 0;
0119 NTBins = (int) ((MaxT - MinT) / TBinWidth) + 1;
0120
0121 if (m_use_module_gain_weights)
0122 {
0123 int side;
0124 int region;
0125 int sector;
0126 double weight;
0127 std::ifstream weights_file(m_tpc_module_gain_weights_file);
0128 if (!weights_file.is_open())
0129 {
0130 std::cout << ".In PHG4TpcPadPlaneReadout: Option to use module gain weights enabled, but weights file not found. Aborting." << std::endl;
0131 return Fun4AllReturnCodes::ABORTEVENT;
0132 }
0133
0134 for (int iside = 0; iside < 2; ++iside)
0135 {
0136 for (int isec = 0; isec < 12; ++isec)
0137 {
0138 for (int ir = 0; ir < 3; ++ir)
0139 {
0140 weights_file >> side >> region >> sector >> weight;
0141 m_module_gain_weight[side][region][sector] = weight;
0142 std::cout << " iside " << iside << " side " << side << " ir " << ir
0143 << " region " << region << " isec " << isec
0144 << " sector " << sector << " weight " << weight << std::endl;
0145 }
0146 }
0147 }
0148 }
0149
0150 if (m_useLangau)
0151 {
0152 int side;
0153 int region;
0154 int sector;
0155 double par0;
0156 double par1;
0157 double par2;
0158 double par3;
0159 std::ifstream pars_file(m_tpc_langau_pars_file);
0160 if (!pars_file.is_open())
0161 {
0162 std::cout << ".In PHG4TpcPadPlaneReadout: Option to use Langau parameters enabled, but parameter file not found. Aborting." << std::endl;
0163 return Fun4AllReturnCodes::ABORTEVENT;
0164 }
0165
0166 for (int iside = 0; iside < 2; ++iside)
0167 {
0168 for (int isec = 0; isec < 12; ++isec)
0169 {
0170 for (int ir = 0; ir < 3; ++ir)
0171 {
0172 pars_file >> side >> region >> sector >> par0 >> par1 >> par2 >> par3;
0173 flangau[side][region][sector] = new TF1(std::format("flangau_{}_{}_{}", side, region, sector).c_str(), [](double *x, double *par)
0174 {
0175 Double_t invsq2pi = 0.3989422804014;
0176 Double_t mpshift = -0.22278298;
0177 Double_t np = 100.0;
0178 Double_t sc = 5.0;
0179 Double_t xx;
0180 Double_t mpc;
0181 Double_t fland;
0182 Double_t sum = 0.0;
0183 Double_t xlow;
0184 Double_t xupp;
0185 Double_t step;
0186 Double_t i;
0187 mpc = par[1] - mpshift * par[0];
0188 xlow = x[0] - sc * par[3];
0189 xupp = x[0] + sc * par[3];
0190 step = (xupp-xlow) / np;
0191 for(i=1.0; i<=np/2; i++)
0192 {
0193 xx = xlow + (i-.5) * step;
0194 fland = TMath::Landau(xx,mpc,par[0]) / par[0];
0195 sum += fland * TMath::Gaus(x[0],xx,par[3]);
0196
0197 xx = xupp - (i-.5) * step;
0198 fland = TMath::Landau(xx,mpc,par[0]) / par[0];
0199 sum += fland * TMath::Gaus(x[0],xx,par[3]);
0200 }
0201
0202 return (par[2] * step * sum * invsq2pi / par[3]); }, 0, 5000, 4);
0203
0204 flangau[side][region][sector]->SetParameters(par0, par1, par2, par3);
0205
0206
0207
0208 }
0209 }
0210 }
0211 }
0212 if (m_maskDeadChannels)
0213 {
0214 makeChannelMask(m_deadChannelMap, m_deadChannelMapName, "TotalDeadChannels");
0215 }
0216 if (m_maskHotChannels)
0217 {
0218 makeChannelMask(m_hotChannelMap, m_hotChannelMapName, "TotalHotChannels");
0219 }
0220
0221 return Fun4AllReturnCodes::EVENT_OK;
0222 }
0223
0224
0225 double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification()
0226 {
0227
0228
0229
0230
0231
0232
0233
0234
0235 double nelec = gsl_ran_exponential(RandomGenerator, averageGEMGain);
0236 if (m_usePolya)
0237 {
0238 double y;
0239 double xmax = 5000;
0240 double ymax = 0.376;
0241 while (true)
0242 {
0243 nelec = gsl_ran_flat(RandomGenerator, 0, xmax);
0244 y = gsl_rng_uniform(RandomGenerator) * ymax;
0245 if (y <= pow((1 + polyaTheta) * (nelec / averageGEMGain), polyaTheta) * exp(-(1 + polyaTheta) * (nelec / averageGEMGain)))
0246 {
0247 break;
0248 }
0249 }
0250 }
0251
0252
0253 return nelec;
0254 }
0255
0256
0257 double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification(double weight)
0258 {
0259
0260
0261
0262
0263
0264
0265
0266
0267 double q_bar = averageGEMGain * weight;
0268 double nelec = gsl_ran_exponential(RandomGenerator, q_bar);
0269 if (m_usePolya)
0270 {
0271 double y;
0272 double xmax = 5000;
0273 double ymax = 0.376;
0274 while (true)
0275 {
0276 nelec = gsl_ran_flat(RandomGenerator, 0, xmax);
0277 y = gsl_rng_uniform(RandomGenerator) * ymax;
0278 if (y <= pow((1 + polyaTheta) * (nelec / q_bar), polyaTheta) * exp(-(1 + polyaTheta) * (nelec / q_bar)))
0279 {
0280 break;
0281 }
0282 }
0283 }
0284
0285
0286 return nelec;
0287 }
0288
0289
0290 double PHG4TpcPadPlaneReadout::getSingleEGEMAmplification(TF1 *f)
0291 {
0292 double nelec = f->GetRandom(0, 5000);
0293
0294
0295 return nelec;
0296 }
0297
0298 void PHG4TpcPadPlaneReadout::MapToPadPlane(
0299 TpcClusterBuilder &tpc_truth_clusterer,
0300 TrkrHitSetContainer *single_hitsetcontainer,
0301 TrkrHitSetContainer *hitsetcontainer,
0302 TrkrHitTruthAssoc * ,
0303 const double x_gem, const double y_gem, const double t_gem, const unsigned int side,
0304 PHG4HitContainer::ConstIterator hiter, TNtuple * , TNtuple * )
0305 {
0306
0307
0308
0309
0310 double phi = atan2(y_gem, x_gem);
0311 if (phi > +M_PI)
0312 {
0313 phi -= 2 * M_PI;
0314 }
0315 if (phi < -M_PI)
0316 {
0317 phi += 2 * M_PI;
0318 }
0319
0320 double rad_gem = get_r(x_gem, y_gem);
0321
0322
0323 for (int iregion = 0; iregion < 3; ++iregion)
0324 {
0325 double daR = 0;
0326 if (iregion == 0 || iregion == 2)
0327 {
0328 daR = 1.0;
0329 }
0330 else
0331 {
0332 daR = MinRadius[iregion] - MaxRadius[iregion - 1];
0333 }
0334 if (rad_gem <= MinRadius[iregion] && rad_gem >= MinRadius[iregion] - daR)
0335 {
0336 if (rad_gem <= MinRadius[iregion] - daR / 2)
0337 {
0338 rad_gem = MinRadius[iregion] - (1.1 * daR);
0339 }
0340 else
0341 {
0342 rad_gem = MinRadius[iregion] + 0.1 * daR;
0343 }
0344 }
0345 }
0346
0347 unsigned int layernum = 0;
0348
0349
0350
0351
0352 PHG4TpcGeomContainer::ConstRange layerrange = GeomContainer->get_begin_end();
0353 for (PHG4TpcGeomContainer::ConstIterator layeriter = layerrange.first;
0354 layeriter != layerrange.second;
0355 ++layeriter)
0356 {
0357 double rad_low = layeriter->second->get_radius() - layeriter->second->get_thickness() / 2.0;
0358 double rad_high = layeriter->second->get_radius() + layeriter->second->get_thickness() / 2.0;
0359
0360 if (rad_gem > rad_low && rad_gem < rad_high)
0361 {
0362
0363 LayerGeom = layeriter->second;
0364
0365 layernum = LayerGeom->get_layer();
0366
0367
0368 if (Verbosity() > 1000)
0369 {
0370 std::cout << " g4hit id " << hiter->first << " rad_gem " << rad_gem << " rad_low " << rad_low << " rad_high " << rad_high
0371 << " layer " << hiter->second->get_layer() << " want to change to " << layernum << std::endl;
0372 }
0373 hiter->second->set_layer(layernum);
0374 }
0375 }
0376
0377 if (layernum == 0)
0378 {
0379 return;
0380 }
0381
0382
0383 const auto phibins = LayerGeom->get_phibins();
0384
0385
0386 const auto tbins = LayerGeom->get_zbins();
0387
0388 sector_min_Phi = LayerGeom->get_sector_min_phi();
0389 sector_max_Phi = LayerGeom->get_sector_max_phi();
0390 phi_bin_width = LayerGeom->get_phistep();
0391
0392 phi = check_phi(side, phi, rad_gem);
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404 double nelec = getSingleEGEMAmplification();
0405
0406 double phi_gain = phi;
0407 if (phi < 0)
0408 {
0409 phi_gain += 2 * M_PI;
0410 }
0411 double gain_weight = 1.0;
0412 if (m_flagToUseGain == 1)
0413 {
0414 gain_weight = h_gain[side]->GetBinContent(h_gain[side]->FindBin(rad_gem * 10, phi_gain));
0415 nelec = nelec * gain_weight;
0416 }
0417
0418 if (m_use_module_gain_weights)
0419 {
0420 double phistep = 30.0;
0421 int sector = 0;
0422
0423 if ((phi_gain * 180.0 / M_PI) >= 15 && (phi_gain * 180.0 / M_PI) < 345)
0424 {
0425 sector = 1 + (int) ((phi_gain * 180.0 / M_PI - 15) / phistep);
0426 }
0427 else
0428 {
0429 sector = 0;
0430 }
0431
0432 int this_region = -1;
0433 for (int iregion = 0; iregion < 3; ++iregion)
0434 {
0435 if (rad_gem < MaxRadius[iregion] && rad_gem > MinRadius[iregion])
0436 {
0437 this_region = iregion;
0438 }
0439 }
0440 if (this_region > -1)
0441 {
0442 gain_weight = m_module_gain_weight[side][this_region][sector];
0443 }
0444
0445
0446 nelec = getSingleEGEMAmplification(gain_weight);
0447
0448
0449
0450 }
0451
0452 if (m_useLangau)
0453 {
0454 double phistep = 30.0;
0455 int sector = 0;
0456
0457 if ((phi_gain * 180.0 / M_PI) >= 15 && (phi_gain * 180.0 / M_PI) < 345)
0458 {
0459 sector = 1 + (int) ((phi_gain * 180.0 / M_PI - 15) / phistep);
0460 }
0461 else
0462 {
0463 sector = 0;
0464 }
0465
0466 int this_region = -1;
0467 for (int iregion = 0; iregion < 3; ++iregion)
0468 {
0469 if (rad_gem < MaxRadius[iregion] && rad_gem > MinRadius[iregion])
0470 {
0471 this_region = iregion;
0472 }
0473 }
0474 if (this_region > -1)
0475 {
0476 nelec = getSingleEGEMAmplification(flangau[side][this_region][sector]);
0477 }
0478 else
0479 {
0480 nelec = getSingleEGEMAmplification();
0481 }
0482 }
0483
0484
0485
0486
0487
0488
0489
0490 if (Verbosity() > 200)
0491 {
0492 std::cout << " populate phi bins for "
0493 << " layernum " << layernum
0494 << " phi " << phi
0495 << " sigmaT " << sigmaT
0496
0497 << std::endl;
0498 }
0499
0500 std::vector<int> pad_phibin;
0501 std::vector<double> pad_phibin_share;
0502
0503 populate_zigzag_phibins(side, layernum, phi, sigmaT, pad_phibin, pad_phibin_share);
0504
0505
0506
0507
0508
0509
0510
0511 double norm1 = 0.0;
0512 for (unsigned int ipad = 0; ipad < pad_phibin.size(); ++ipad)
0513 {
0514 double pad_share = pad_phibin_share[ipad];
0515 norm1 += pad_share;
0516 }
0517 for (unsigned int iphi = 0; iphi < pad_phibin.size(); ++iphi)
0518 {
0519 pad_phibin_share[iphi] /= norm1;
0520 }
0521
0522
0523
0524 if (Verbosity() > 100 && layernum == print_layer)
0525 {
0526 std::cout << " populate t bins for layernum " << layernum
0527 << " with t_gem " << t_gem << " SAMPA peaking time " << Ts << std::endl;
0528 }
0529
0530 std::vector<int> adc_tbin;
0531 std::vector<double> adc_tbin_share;
0532 sampaTimeDistribution(t_gem, adc_tbin, adc_tbin_share);
0533
0534
0535
0536
0537
0538
0539
0540
0541 double tnorm = 0.0;
0542 for (unsigned int it = 0; it < adc_tbin.size(); ++it)
0543 {
0544 double bin_share = adc_tbin_share[it];
0545 tnorm += bin_share;
0546 }
0547 for (unsigned int it = 0; it < adc_tbin.size(); ++it)
0548 {
0549 adc_tbin_share[it] /= tnorm;
0550 }
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566 double phi_integral = 0.0;
0567 double t_integral = 0.0;
0568 double weight = 0.0;
0569
0570 for (unsigned int ipad = 0; ipad < pad_phibin.size(); ++ipad)
0571 {
0572 int pad_num = pad_phibin[ipad];
0573 double pad_share = pad_phibin_share[ipad];
0574
0575 for (unsigned int it = 0; it < adc_tbin.size(); ++it)
0576 {
0577 int tbin_num = adc_tbin[it];
0578 double adc_bin_share = adc_tbin_share[it];
0579
0580
0581 float neffelectrons = nelec * (pad_share) * (adc_bin_share);
0582 if (neffelectrons < neffelectrons_threshold)
0583 {
0584 continue;
0585 }
0586
0587 if (tbin_num >= tbins)
0588 {
0589 std::cout << " Error making key: adc_tbin " << tbin_num << " ntbins " << tbins << std::endl;
0590 }
0591 if (pad_num >= phibins)
0592 {
0593 std::cout << " Error making key: pad_phibin " << pad_num << " nphibins " << phibins << std::endl;
0594 }
0595
0596
0597
0598
0599 double tcenter = LayerGeom->get_zcenter(tbin_num);
0600 double phicenter = LayerGeom->get_phicenter(pad_num, side);
0601 phi_integral += phicenter * neffelectrons;
0602 t_integral += tcenter * neffelectrons;
0603 weight += neffelectrons;
0604 if (Verbosity() > 1 && layernum == print_layer)
0605 {
0606 std::cout << " tbin_num " << tbin_num << " tcenter " << tcenter << " pad_num " << pad_num << " phicenter " << phicenter
0607 << " neffelectrons " << neffelectrons << " neffelectrons_threshold " << neffelectrons_threshold << std::endl;
0608 }
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619 unsigned int pads_per_sector = phibins / 12;
0620 unsigned int sector = pad_num / pads_per_sector;
0621 TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layernum, sector, side);
0622
0623 TrkrHitSetContainer::Iterator hitsetit = hitsetcontainer->findOrAddHitSet(hitsetkey);
0624 TrkrHitSetContainer::Iterator single_hitsetit = single_hitsetcontainer->findOrAddHitSet(hitsetkey);
0625 TrkrDefs::hitkey hitkey;
0626
0627 if (m_maskDeadChannels)
0628 {
0629 hitkey = TpcDefs::genHitKey((unsigned int) pad_num, 0);
0630 if (m_deadChannelMap.contains(hitsetkey) &&
0631 std::find(m_deadChannelMap[hitsetkey].begin(), m_deadChannelMap[hitsetkey].end(), hitkey) != m_deadChannelMap[hitsetkey].end())
0632 {
0633 continue;
0634 }
0635 }
0636 if (m_maskHotChannels)
0637 {
0638 hitkey = TpcDefs::genHitKey((unsigned int) pad_num, 0);
0639 if (m_hotChannelMap.contains(hitsetkey) &&
0640 std::find(m_hotChannelMap[hitsetkey].begin(), m_hotChannelMap[hitsetkey].end(), hitkey) != m_hotChannelMap[hitsetkey].end())
0641 {
0642 continue;
0643 }
0644 }
0645
0646 hitkey = TpcDefs::genHitKey((unsigned int) pad_num, (unsigned int) tbin_num);
0647
0648
0649 TrkrHit *hit = nullptr;
0650 hit = hitsetit->second->getHit(hitkey);
0651 if (!hit)
0652 {
0653
0654 hit = new TrkrHitv2();
0655 hitsetit->second->addHitSpecificKey(hitkey, hit);
0656 }
0657
0658 hit->addEnergy(neffelectrons);
0659
0660 tpc_truth_clusterer.addhitset(hitsetkey, hitkey, neffelectrons);
0661
0662
0663
0664 TrkrHit *single_hit = nullptr;
0665 single_hit = single_hitsetit->second->getHit(hitkey);
0666 if (!single_hit)
0667 {
0668
0669 single_hit = new TrkrHitv2();
0670 single_hitsetit->second->addHitSpecificKey(hitkey, single_hit);
0671 }
0672
0673 single_hit->addEnergy(neffelectrons);
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683 }
0684 }
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695
0696
0697 if (Verbosity() > 100)
0698 {
0699 if (layernum == print_layer)
0700 {
0701 std::cout << " hit " << m_NHits << " quick centroid for this electron " << std::endl;
0702 std::cout << " phi centroid = " << phi_integral / weight << " phi in " << phi << " phi diff " << phi_integral / weight - phi << std::endl;
0703 std::cout << " t centroid = " << t_integral / weight << " t in " << t_gem << " t diff " << t_integral / weight - t_gem << std::endl;
0704
0705
0706
0707
0708
0709
0710
0711
0712 }
0713 }
0714
0715 m_NHits++;
0716
0717 }
0718 double PHG4TpcPadPlaneReadout::check_phi(const unsigned int side, const double phi, const double radius)
0719 {
0720 double new_phi = phi;
0721 int p_region = -1;
0722 for (int iregion = 0; iregion < 3; ++iregion)
0723 {
0724 if (radius < MaxRadius[iregion] && radius > MinRadius[iregion])
0725 {
0726 p_region = iregion;
0727 }
0728 }
0729
0730 if (p_region >= 0)
0731 {
0732 for (int s = 0; s < 12; s++)
0733 {
0734 double daPhi = 0;
0735 if (s == 0)
0736 {
0737 daPhi = fabs(sector_min_Phi[side][11] + 2 * M_PI - sector_max_Phi[side][s]);
0738 }
0739 else
0740 {
0741 daPhi = fabs(sector_min_Phi[side][s - 1] - sector_max_Phi[side][s]);
0742 }
0743 double min_phi = sector_max_Phi[side][s];
0744 double max_phi = sector_max_Phi[side][s] + daPhi;
0745 if (new_phi <= max_phi && new_phi >= min_phi)
0746 {
0747 if (fabs(max_phi - new_phi) > fabs(new_phi - min_phi))
0748 {
0749 new_phi = min_phi - phi_bin_width / 5;
0750 }
0751 else
0752 {
0753 new_phi = max_phi + phi_bin_width / 5;
0754 }
0755 }
0756 }
0757 if (new_phi < sector_min_Phi[side][11] && new_phi >= -M_PI)
0758 {
0759 new_phi += 2 * M_PI;
0760 }
0761 }
0762
0763 return new_phi;
0764 }
0765
0766 void PHG4TpcPadPlaneReadout::populate_zigzag_phibins(const unsigned int side, const unsigned int layernum, const double phi, const double cloud_sig_rp, std::vector<int> &phibin_pad, std::vector<double> &phibin_pad_share)
0767 {
0768 const double radius = LayerGeom->get_radius();
0769 const double phistepsize = LayerGeom->get_phistep();
0770 const auto phibins = LayerGeom->get_phibins();
0771
0772
0773 double rphi = phi * radius;
0774 if (Verbosity() > 100)
0775 {
0776 if (LayerGeom->get_layer() == print_layer)
0777 {
0778 std::cout << " populate_zigzag_phibins for layer " << layernum << " with radius " << radius << " phi " << phi
0779 << " rphi " << rphi << " phistepsize " << phistepsize << std::endl;
0780 std::cout << " fcharge created: radius " << radius << " rphi " << rphi << " cloud_sig_rp " << cloud_sig_rp << std::endl;
0781 }
0782 }
0783
0784
0785 const double philim_low_calc = phi - (_nsigmas * cloud_sig_rp / radius) - phistepsize;
0786 const double philim_high_calc = phi + (_nsigmas * cloud_sig_rp / radius) + phistepsize;
0787
0788
0789 const double philim_low = check_phi(side, philim_low_calc, radius);
0790 const double philim_high = check_phi(side, philim_high_calc, radius);
0791
0792 int phibin_low = LayerGeom->get_phibin(philim_high, side);
0793 int phibin_high = LayerGeom->get_phibin(philim_low, side);
0794 int npads = phibin_high - phibin_low;
0795
0796 if (Verbosity() > 1000)
0797 {
0798 if (layernum == print_layer)
0799 {
0800 std::cout << " zigzags: phi " << phi << " philim_low " << philim_low << " phibin_low " << phibin_low
0801 << " philim_high " << philim_high << " phibin_high " << phibin_high << " npads " << npads << std::endl;
0802 }
0803 }
0804
0805 if (npads < 0 || npads > 9)
0806 {
0807 npads = 9;
0808 }
0809
0810
0811 const double pad_rphi = 2.0 * LayerGeom->get_phistep() * radius;
0812
0813
0814 using PadParameterSet = std::array<double, 2>;
0815 std::array<PadParameterSet, 10> pad_parameters{};
0816 std::array<int, 10> pad_keep{};
0817
0818
0819 std::array<double, 10> overlap = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
0820 double pads_phi[10] = {0., 0., 0., 0., 0., 0., 0., 0., 0., 0.};
0821 double sum_of_pads_phi = 0.;
0822 double sum_of_pads_absphi = 0.;
0823 for (int ipad = 0; ipad <= npads; ipad++)
0824 {
0825 int pad_now = phibin_low + ipad;
0826 if (pad_now >= phibins)
0827 {
0828 pad_now -= phibins;
0829 }
0830 pads_phi[ipad] = LayerGeom->get_phicenter(pad_now, side);
0831 sum_of_pads_phi += pads_phi[ipad];
0832 sum_of_pads_absphi += fabs(pads_phi[ipad]);
0833 }
0834
0835 for (int ipad = 0; ipad <= npads; ipad++)
0836 {
0837 int pad_now = phibin_low + ipad;
0838
0839
0840 if (pad_now >= phibins)
0841 {
0842 pad_now -= phibins;
0843 }
0844
0845 pad_keep[ipad] = pad_now;
0846 double phi_now = pads_phi[ipad];
0847 const double rphi_pad_now = phi_now * radius;
0848 pad_parameters[ipad] = {{pad_rphi / 2.0, rphi_pad_now}};
0849
0850 if (Verbosity() > 1000)
0851 {
0852 if (layernum == print_layer)
0853 {
0854 std::cout << " zigzags: make fpad for ipad " << ipad << " pad_now " << pad_now << " pad_rphi/2 " << pad_rphi / 2.0
0855 << " rphi_pad_now " << rphi_pad_now << std::endl;
0856 }
0857 }
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867 const double pitch = pad_rphi / 2.0;
0868 double x_loc_tmp = rphi_pad_now - rphi;
0869 const double sigma = cloud_sig_rp;
0870
0871
0872 if (fabs(sum_of_pads_phi) != sum_of_pads_absphi)
0873 {
0874 if (phi < -M_PI / 2 && phi_now > 0)
0875 {
0876 x_loc_tmp = (phi_now - 2 * M_PI) * radius - rphi;
0877 }
0878 if (phi > M_PI / 2 && phi_now < 0)
0879 {
0880 x_loc_tmp = (phi_now + 2 * M_PI) * radius - rphi;
0881 }
0882 if (phi < 0 && phi_now > 0)
0883 {
0884 x_loc_tmp = (phi_now + fabs(phi)) * radius;
0885 }
0886 if (phi > 0 && phi_now < 0)
0887 {
0888 x_loc_tmp = (2 * M_PI - phi_now + phi) * radius;
0889 }
0890 }
0891
0892 const double x_loc = x_loc_tmp;
0893
0894
0895
0896
0897
0898 overlap[ipad] =
0899 (pitch - x_loc) * (std::erf(x_loc / (M_SQRT2 * sigma)) - std::erf((x_loc - pitch) / (M_SQRT2 * sigma))) / (pitch * 2) + (pitch + x_loc) * (std::erf((x_loc + pitch) / (M_SQRT2 * sigma)) - std::erf(x_loc / (M_SQRT2 * sigma))) / (pitch * 2) + (gaus(x_loc - pitch, sigma) - gaus(x_loc, sigma)) * square(sigma) / pitch + (gaus(x_loc + pitch, sigma) - gaus(x_loc, sigma)) * square(sigma) / pitch;
0900 }
0901
0902
0903 for (int ipad = 0; ipad <= npads; ipad++)
0904 {
0905 phibin_pad.push_back(pad_keep[ipad]);
0906 phibin_pad_share.push_back(overlap[ipad]);
0907 }
0908
0909 return;
0910 }
0911
0912 void PHG4TpcPadPlaneReadout::UseGain(const int flagToUseGain)
0913 {
0914 m_flagToUseGain = flagToUseGain;
0915 if (m_flagToUseGain == 1 && Verbosity() > 0)
0916 {
0917 std::cout << "PHG4TpcPadPlaneReadout: UseGain: TRUE " << std::endl;
0918 }
0919 }
0920
0921 void PHG4TpcPadPlaneReadout::ReadGain()
0922 {
0923
0924 if (m_flagToUseGain == 1)
0925 {
0926 char *calibrationsroot = getenv("CALIBRATIONROOT");
0927 if (calibrationsroot != nullptr)
0928 {
0929 std::string gain_maps_filename = std::string(calibrationsroot) + std::string("/TPC/GainMaps/TPCGainMaps.root");
0930 TFile *fileGain = TFile::Open(gain_maps_filename.c_str(), "READ");
0931 h_gain[0] = (TH2 *) fileGain->Get("RadPhiPlot0")->Clone();
0932 h_gain[1] = (TH2 *) fileGain->Get("RadPhiPlot1")->Clone();
0933 h_gain[0]->SetDirectory(nullptr);
0934 h_gain[1]->SetDirectory(nullptr);
0935 fileGain->Close();
0936 }
0937 }
0938 }
0939 void PHG4TpcPadPlaneReadout::SetDefaultParameters()
0940 {
0941 set_default_double_param("tpc_minradius_inner", 31.105);
0942 set_default_double_param("tpc_minradius_mid", 41.153);
0943 set_default_double_param("tpc_minradius_outer", 58.367);
0944
0945 set_default_double_param("tpc_maxradius_inner", 40.249);
0946 set_default_double_param("tpc_maxradius_mid", 57.475);
0947 set_default_double_param("tpc_maxradius_outer", 75.911);
0948
0949 set_default_double_param("neffelectrons_threshold", 1.0);
0950 set_default_double_param("gem_cloud_sigma", 0.04);
0951 set_default_double_param("sampa_shaping_lead", 32.0);
0952 set_default_double_param("sampa_shaping_tail", 48.0);
0953
0954 set_default_double_param("tpc_sector_phi_inner", 0.5024);
0955 set_default_double_param("tpc_sector_phi_mid", 0.5087);
0956 set_default_double_param("tpc_sector_phi_outer", 0.5097);
0957
0958 set_default_int_param("ntpc_phibins_inner", 1128);
0959 set_default_int_param("ntpc_phibins_mid", 1536);
0960 set_default_int_param("ntpc_phibins_outer", 2304);
0961
0962
0963
0964
0965
0966
0967 set_default_double_param("gem_amplification", 1400);
0968 set_default_double_param("polya_theta", 0.8);
0969 return;
0970 }
0971
0972 void PHG4TpcPadPlaneReadout::UpdateInternalParameters()
0973 {
0974 neffelectrons_threshold = get_double_param("neffelectrons_threshold");
0975
0976 MinRadius =
0977 {{get_double_param("tpc_minradius_inner"),
0978 get_double_param("tpc_minradius_mid"),
0979 get_double_param("tpc_minradius_outer")}};
0980
0981 MaxRadius =
0982 {{get_double_param("tpc_maxradius_inner"),
0983 get_double_param("tpc_maxradius_mid"),
0984 get_double_param("tpc_maxradius_outer")}};
0985
0986 sigmaT = get_double_param("gem_cloud_sigma");
0987 sigmaL = {{get_double_param("sampa_shaping_lead"),
0988 get_double_param("sampa_shaping_tail")}};
0989
0990
0991 averageGEMGain = get_double_param("gem_amplification");
0992 polyaTheta = get_double_param("polya_theta");
0993 }
0994
0995 void PHG4TpcPadPlaneReadout::makeChannelMask(hitMaskTpc &aMask, const std::string &dbName, const std::string &totalChannelsToMask)
0996 {
0997 CDBTTree *cdbttree;
0998 if (m_maskFromFile)
0999 {
1000 cdbttree = new CDBTTree(dbName);
1001 }
1002 else
1003 {
1004 std::string database = CDBInterface::instance()->getUrl(dbName);
1005 cdbttree = new CDBTTree(database);
1006 }
1007
1008 std::cout << "Masking TPC Channel Map: " << dbName << std::endl;
1009
1010 int NChan = -1;
1011 NChan = cdbttree->GetSingleIntValue(totalChannelsToMask);
1012
1013 for (int i = 0; i < NChan; i++)
1014 {
1015 int Layer = cdbttree->GetIntValue(i, "layer");
1016 int Sector = cdbttree->GetIntValue(i, "sector");
1017 int Side = cdbttree->GetIntValue(i, "side");
1018 int Pad = cdbttree->GetIntValue(i, "pad");
1019 if (Verbosity() > VERBOSITY_A_LOT)
1020 {
1021 std::cout << dbName << ": Will mask layer: " << Layer << ", sector: " << Sector << ", side: " << Side << ", Pad: " << Pad << std::endl;
1022 }
1023
1024 TrkrDefs::hitsetkey DeadChannelHitKey = TpcDefs::genHitSetKey(Layer, Sector, Side);
1025 TrkrDefs::hitkey DeadHitKey = TpcDefs::genHitKey((unsigned int) Pad, 0);
1026 aMask[DeadChannelHitKey].push_back(DeadHitKey);
1027 }
1028
1029 delete cdbttree;
1030 }
1031
1032 void PHG4TpcPadPlaneReadout::sampaTimeDistribution(double tzero, std::vector<int> &adc_tbin, std::vector<double> &adc_tbin_share)
1033 {
1034
1035
1036
1037 int nclocks = 8;
1038
1039 double tstepsize = LayerGeom->get_zstep();
1040 int tbinzero = LayerGeom->get_zbin(tzero);
1041
1042
1043 double tfirst_end = LayerGeom->get_zcenter(tbinzero) + tstepsize/2.0;
1044 double vfirst_end = sampaShapingResponseFunction(tzero, tfirst_end);
1045 double first_integral = (vfirst_end / 2.0) * (tfirst_end - tzero);
1046
1047 adc_tbin.push_back(tbinzero);
1048 adc_tbin_share.push_back(first_integral);
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058 for(int iclock = 1; iclock < nclocks; ++iclock)
1059 {
1060 int tbin = tbinzero + iclock;
1061 if (tbin < 0 || tbin > LayerGeom->get_zbins())
1062 {
1063 if (Verbosity() > 0)
1064 {
1065 std::cout << " t bin " << tbin << " is outside range of " << LayerGeom->get_zbins() << " so skip it" << std::endl;
1066 }
1067 continue;
1068 }
1069
1070
1071 double tcenter = LayerGeom->get_zcenter(tbin);
1072 double tlow = tcenter - tstepsize/2.0;
1073
1074
1075 int nsamples = 6;
1076 double sample_step = tstepsize / (double) nsamples;
1077 double sintegral = 0;
1078 for(int isample = 0; isample < nsamples; ++isample)
1079 {
1080 double tnow = tlow + (double) isample * sample_step + sample_step / 2.0;
1081 double vnow = sampaShapingResponseFunction(tzero, tnow);
1082 sintegral += vnow * sample_step;
1083
1084
1085
1086
1087
1088
1089
1090
1091 }
1092
1093
1094 adc_tbin.push_back(tbin);
1095 adc_tbin_share.push_back(sintegral);
1096 }
1097 }
1098
1099 double PHG4TpcPadPlaneReadout::sampaShapingResponseFunction(double tzero, double t) const
1100 {
1101 double v = exp(-4*(t-tzero)/Ts) * pow( (t-tzero)/Ts, 4.0);
1102
1103 return v;
1104 }