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