8 #ifndef GAR_READOUTSIMULATION_IONIZATIONREADOUT 9 #define GAR_READOUTSIMULATION_IONIZATIONREADOUT 29 #include "cetlib_except/exception.h" 34 #include "nug4/ParticleNavigation/ParticleList.h" 35 #include "nurandom/RandomUtils/NuRandomService.h" 42 #include "Utilities/AssociationUtil.h" 46 #include "CoreUtils/ServiceUtil.h" 85 std::vector<edepIDE> & edepIDEs);
87 std::vector<sdp::EnergyDeposit>
const& edepCol);
89 std::vector<float> & electrons,
90 std::set<size_t> & eDepLocs,
91 std::deque<float> & eDepWeights,
92 std::vector<raw::RawDigit> & digCol,
132 fTime = gar::providerFrom<detinfo::DetectorClocksServiceGAr>();
134 fNumTicks = gar::providerFrom<detinfo::DetectorPropertiesService>()->NumberTimeSamples();
136 fGeo = gar::providerFrom<geo::GeometryGAr>();
140 produces< std::vector<raw::RawDigit> >();
141 produces< ::art::Assns<sdp::EnergyDeposit, raw::RawDigit, float> >();
150 if (fullname.empty() ||
stat(fullname.c_str(), &sb)!=0)
151 throw cet::exception(
"IonizationReadout") <<
"Input pad response function file " 153 <<
" not found in FW_SEARCH_PATH\n";
155 TFile
infile(fullname.c_str(),
"READ");
160 fHFILLPRF->SetDirectory(0);
179 MF_LOG_DEBUG(
"IonizationReadout") <<
"Debug: IonizationReadout()";
189 auto driftAlgName = driftAlgPars.
get<
std::string>(
"DriftAlgType");
192 if (driftAlgName.compare(
"Standard") == 0) {
197 <<
"Unable to determine which electron drift algorithm to use, bail";
201 auto tpcROAlgName = tpcROAlgPars.
get<
std::string>(
"TPCReadoutSimType");
203 if (tpcROAlgName.compare(
"Standard") == 0){
208 <<
"Unable to determine which TPC readout simulation algorithm to use, bail";
245 std::unique_ptr< std::vector<raw::RawDigit> > rdCol (
new std::vector<raw::RawDigit> );
246 std::unique_ptr< ::art::Assns<sdp::EnergyDeposit, raw::RawDigit, float> > erassn(new ::art::Assns<sdp::EnergyDeposit, raw::RawDigit, float>);
251 if(eDepCol->size() > 0){
253 std::vector<edepIDE> eDepIDEs;
258 if (eDepIDEs.size()>0)
262 unsigned int prevChan = eDepIDEs.front().Channel;
263 std::set<size_t> digitEDepLocs;
264 std::deque<float> digitEDepWeights;
265 std::vector<float> electrons(
fNumTicks, 0.);
268 for(
auto edide : eDepIDEs){
271 <<
"Current eDepIDE channel is " 273 <<
" previous channel is " 276 if(edide.Channel != prevChan){
279 << digitEDepLocs.size()
282 <<
" rdCol size is currently " 297 prevChan = edide.Channel;
302 size_t esize = electrons.size();
304 if (edide.TDC >= esize) {
305 electrons[esize - 1] = edide.NumElect;
307 electrons[edide.TDC] = edide.NumElect;
311 for(
auto loc : edide.edepLocs) digitEDepLocs.insert(
loc);
312 for(
auto w : edide.edepWeights) digitEDepWeights.push_front(
w);
329 <<
" raw digits from signal";
349 std::vector<edepIDE> & edepIDEs)
351 auto geo = gar::providerFrom<geo::GeometryGAr>();
354 unsigned int chan = 0;
356 std::vector<edepIDE> edepIDEaccumulator;
363 for (
size_t e = 0;
e < edepCol.size(); ++
e) {
367 fDriftAlg->DriftElectronsToReadout(edepCol[
e], driftInfo);
379 for (
size_t c = 0;
c < clusterXPos.size(); ++
c) {
381 xyz[0] = clusterXPos[
c];
382 xyz[1] = clusterYPos[
c];
383 xyz[2] = clusterZPos[
c];
389 geo->NearestChannelInfo(xyz, cwn);
396 if (chan ==
geo->GapChannelNumber())
continue;
402 TVector3
pos = cwn.at(0).pos;
403 TVector3 pproj(0,xyz[1],xyz[2]);
405 std::vector<float> chanweight;
406 size_t ncdistrib = cwn.size();
410 MF_LOG_DEBUG(
"IonizationReadout::DriftElectronsToReadout") <<
"pproj: " << pproj.Y() <<
" " << pproj.Z() <<
std::endl;
411 for (
size_t icd=0; icd<ncdistrib; ++icd) {
426 throw cet::exception(
"IonizationReadout::DriftElectronsToReadout") <<
"Ununderstood readout chamber type " 427 << cwn.at(icd).roctype <<
"\n";
429 TVector3 dproj = pproj - cwn.at(icd).pos;
431 MF_LOG_DEBUG(
"IonizationReadout::DriftElectronsToReadout") <<
" Pad loc: " << cwn.at(icd).pos.Y() <<
434 float dist_along_padrow = dproj.Dot(cwn.at(icd).padrowdir);
435 float dist_perp_padrow = (dproj - dist_along_padrow*cwn.at(icd).padrowdir).Mag();
436 MF_LOG_DEBUG(
"IonizationReadout::DriftElectronsToReadout") <<
"along, perp: " << dist_along_padrow <<
439 dist_along_padrow = TMath::Abs(dist_along_padrow);
440 if (dist_along_padrow < prfhist->GetXaxis()->GetBinUpEdge(prfhist->GetNbinsX()) &&
441 dist_perp_padrow < prfhist->GetYaxis()->GetBinUpEdge(prfhist->GetNbinsY())) {
442 chanweight.push_back(prfhist->GetBinContent(prfhist->FindBin(dist_along_padrow,dist_perp_padrow)));
444 chanweight.push_back(0);
447 sumw += chanweight.back();
451 throw cet::exception(
"IonizationReadout::DriftElectronsToReadout") <<
452 "Weight sum is zero, even when including the closest channel " <<
std::endl;
454 float rsumw = 1.0/sumw;
455 for (
size_t i=0; i<chanweight.size(); ++i) {
456 if (chanweight.at(i)>0 && clusterSize.at(
c) > 0) {
457 edepIDEaccumulator.emplace_back(clusterSize.at(
c)*chanweight.at(i)*rsumw,
460 e, chanweight.at(i));
463 "DriftElectronsToReadout");
465 if (edepIDEaccumulator.size() > 10000)
468 edepIDEs.insert(edepIDEs.end(),edepIDEaccumulator.begin(),edepIDEaccumulator.end());
469 edepIDEaccumulator.clear();
474 MF_LOG_DEBUG(
"IonizationReadout::DriftElectronsToReadout")
488 edepIDEs.insert(edepIDEs.end(),edepIDEaccumulator.begin(),edepIDEaccumulator.end());
496 std::vector<sdp::EnergyDeposit>
const& edepCol) {
501 <<
" energy deposits";
503 if (edepIDEs.size()==0)
return;
505 std::vector<edepIDE>
temp;
509 std::sort(edepIDEs.begin(), edepIDEs.end());
511 for(
auto itr : edepIDEs){
512 for(
auto edloc : itr.edepLocs) {
515 "CombineIDEsAfterSort");
519 edepIDE prev = edepIDEs.front();
527 for (
size_t e = 1;
e < edepIDEs.size(); ++
e) {
531 <<
"current edepIDE: " 538 << cur.edepLocs.size();
542 <<
"storing edepIDE sum: " 549 << sum.edepLocs.size();
552 for (
auto edloc : sum.edepLocs) {
568 <<
"summing current edepIDE";
581 <<
" energy deposits";
588 std::vector<float> & electrons,
589 std::set<size_t> & eDepLocs,
590 std::deque<float> & eDepWeights,
591 std::vector<raw::RawDigit> & digCol,
603 digCol.emplace_back(tmpdigit);
608 <<
" energy deposits to digit for channel " 613 for (
auto ed : eDepLocs) {
618 <<
"Making association: " << digCol.size() <<
" " << ptr <<
std::endl;
648 MF_LOG_DEBUG(
"IonizationReadout::CheckChannelToEnergyDepositMapping")
653 <<
" is off from the energy deposit: (" 675 #endif // GAR_READOUTSIMULATION_IONIZATIONREADOUT
std::vector< gar::geo::ChanWithPos > ChanWithNeighbors
TH2F * fIOROCPRF
pad response function for IOROC
base_engine_t & createEngine(seed_t seed)
bool fCheckChan
flag to check mapping of energy deposits to channels
std::vector< double > const & ClusterZPos() const
std::vector< double > const & ClusterYPos() const
TH2F * fHFILLPRF
pad response function for hole-filler chamber
EDProducer(fhicl::ParameterSet const &pset)
const gar::detinfo::DetectorClocks * fTime
electronics clock
std::unique_ptr< TPCReadoutSimAlg > fROSimAlg
algorithm to simulate the electronics
Description of geometry of one entire detector.
void DriftElectronsToReadout(std::vector< sdp::EnergyDeposit > const &edepCol, std::vector< edepIDE > &edepIDEs)
std::vector< double > const & ClusterXPos() const
void produce(::art::Event &evt)
double TickPeriod() const
A single tick period in nano-second, frequency is in MHz.
fhicl::ParameterSet fISCalcPars
parameter set for the IS calculator
void beginRun(::art::Run &run)
#define DEFINE_ART_MODULE(klass)
bool CreateAssnD(PRODUCER const &prod, art::Event &evt, art::Assns< T, U, D > &assn, size_t first_index, size_t second_index, typename art::Assns< T, U, D >::data_t &&data)
Creates a single one-to-one association with associated data.
virtual double G4ToElecTime(double g4_time) const =0
Given Geant4 time [ns], returns relative time [ns] w.r.t. electronics time T0.
T get(std::string const &key) const
Runs Readout simulation including propagation of electrons and photons to readout.
bool fUsePRF
switch to turn on PRF modeling, otherwise just use the arrival pad
IonizationReadout(fhicl::ParameterSet const &pset)
Standard constructor and destructor for an FMWK module.
std::string fPRFFileName
where to find the pad response function histograms
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
std::string fG4Label
label of G4 module
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
static IonizationAndScintillation * CreateInstance(CLHEP::HepRandomEngine &engine, fhicl::ParameterSet const &pset)
virtual double TPCG4Time2TDC(double g4time) const =0
Given G4 time [ns], returns corresponding TPC electronics clock count [tdc].
size_t fNumTicks
number of TDC samples
const gar::geo::GeometryCore * fGeo
geometry information
void CombineIDEs(std::vector< edepIDE > &edepIDEs, std::vector< sdp::EnergyDeposit > const &edepCol)
virtual ~IonizationReadout()
General GArSoft Utilities.
void CheckChannelToEnergyDepositMapping(unsigned int const &channel, sdp::EnergyDeposit const &edep, std::string const &id)
TH2F * fOOROCPRF
pad response function for OOROC
std::unique_ptr< ElectronDriftAlg > fDriftAlg
algorithm to drift ionization electrons
virtual const ElecClock & TPCClock() const =0
Borrow a const TPC clock with time set to Trigger time [ns].
std::vector< double > const & ClusterTime() const
TH2F * fIROCPRF
pad response function for IROC
CLHEP::HepRandomEngine & fEngine
random engine
LArSoft geometry interface.
art framework interface to geometry description
void ChannelToPosition(unsigned int const channel, float *const worldLoc) const
static ServiceHandle< RandomNumberGenerator > & rng()
std::vector< int > const & ClusterSize() const
Collection of charge vs time digitized from a single readout channel.
cet::coded_exception< error, detail::translate > exception
QTextStream & endl(QTextStream &s)
void reconfigure(fhicl::ParameterSet const &pset)
void CreateSignalDigit(unsigned int const &channel, std::vector< float > &electrons, std::set< size_t > &eDepLocs, std::deque< float > &eDepWeights, std::vector< raw::RawDigit > &digCol,::art::ValidHandle< std::vector< sdp::EnergyDeposit > > &eDepCol,::art::Assns< sdp::EnergyDeposit, raw::RawDigit, float > &erassn,::art::Event &evt)