71 #include "art/Framework/Core/EDProducer.h"
72 #include "art/Framework/Core/ModuleMacros.h"
73 #include "art/Framework/Principal/Event.h"
74 #include "art/Framework/Principal/Handle.h"
75 #include "art/Framework/Services/Registry/ServiceHandle.h"
76 #include "fhiclcpp/ParameterSet.h"
77 #include "messagefacility/MessageLogger/MessageLogger.h"
78 #include "nurandom/RandomUtils/NuRandomService.h"
81 #include "CLHEP/Random/RandGauss.h"
87 #include <unordered_map>
135 typedef std::unordered_map<raw::ChannelID_t, ChannelBookKeeping>
ChannelMap_t;
162 : art::EDProducer{pset}
163 , fSimModuleLabel{pset.get<art::InputTag>(
"SimulationLabel")}
167 , fRandGauss{art::ServiceHandle<rndm::NuRandomService>{}->createEngine(*
this, pset,
"Seed")}
170 produces<std::vector<sim::SimChannel>>();
181 art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob();
184 for (
int i = 0; i < 3; ++i) {
196 art::ServiceHandle<sim::LArG4Parameters const> paramHandle;
202 MF_LOG_DEBUG(
"SimDriftElectrons")
204 <<
"\n Temperature (K): " <<
detProp.Temperature()
226 typedef art::Handle<std::vector<sim::SimEnergyDeposit>> energyDepositHandle_t;
227 energyDepositHandle_t energyDepositHandle;
236 std::unique_ptr<std::vector<sim::SimChannel>> channels(
new std::vector<sim::SimChannel>);
238 std::unique_ptr<std::vector<sim::SimDriftedElectronCluster>>
239 SimDriftedElectronClusterCollection(
new std::vector<sim::SimDriftedElectronCluster>);
249 auto const clockData =
250 art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(event);
251 auto const& tpcClock = clockData.TPCClock();
254 art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(event, clockData);
258 auto const& energyDeposits = *energyDepositHandle;
259 auto energyDepositsSize = energyDeposits.size();
262 for (
size_t edIndex = 0; edIndex < energyDepositsSize; ++edIndex) {
263 auto const& energyDeposit = energyDeposits[edIndex];
268 auto const mp = energyDeposit.MidPoint();
269 double const xyz[3] = {mp.X(), mp.Y(), mp.Z()};
274 unsigned int cryostat = 0;
276 fGeometry->PositionToCryostat(xyz, cryostat);
278 catch (cet::exception&
e) {
279 mf::LogWarning(
"SimDriftElectrons") <<
"step "
280 <<
"cannot be found in a cryostat\n"
285 unsigned int tpc = 0;
287 fGeometry->PositionToTPC(xyz, tpc, cryostat);
289 catch (cet::exception& e) {
290 mf::LogWarning(
"SimDriftElectrons") <<
"step "
291 <<
"cannot be found in a TPC\n"
313 int transversecoordinate1 = 0;
314 int transversecoordinate2 = 0;
315 if (driftcoordinate == 0) {
316 transversecoordinate1 = 1;
317 transversecoordinate2 = 2;
319 else if (driftcoordinate == 1) {
320 transversecoordinate1 = 0;
321 transversecoordinate2 = 2;
323 else if (driftcoordinate == 2) {
324 transversecoordinate1 = 0;
325 transversecoordinate2 = 1;
328 if (transversecoordinate1 == transversecoordinate2)
338 if (driftsign == 1 && tpcGeo.
PlaneLocation(0)[driftcoordinate] < xyz[driftcoordinate])
340 if (driftsign == -1 && tpcGeo.
PlaneLocation(0)[driftcoordinate] > xyz[driftcoordinate])
345 double DriftDistance =
351 double posOffsetxyz[3] = {0.0, 0.0, 0.0};
353 auto const* SCE = lar::providerFrom<spacecharge::SpaceChargeService>();
354 if (SCE->EnableSimSpatialSCE() ==
true) {
355 posOffsets = SCE->GetPosOffsets(mp);
359 posOffsetxyz[0] = posOffsets.X();
360 posOffsetxyz[1] = posOffsets.Y();
361 posOffsetxyz[2] = posOffsets.Z();
364 double avegagetransversePos1 = 0.;
365 double avegagetransversePos2 = 0.;
367 DriftDistance += -1. * posOffsetxyz[driftcoordinate];
368 avegagetransversePos1 = xyz[transversecoordinate1] + posOffsetxyz[transversecoordinate1];
369 avegagetransversePos2 = xyz[transversecoordinate2] + posOffsetxyz[transversecoordinate2];
375 if (DriftDistance < 0.) DriftDistance = 0.;
381 driftcoordinate == 0) {
383 TDrift = ((DriftDistance - tpcGeo.
PlanePitch(0, 1)) * fRecipDriftVel[0] +
387 const int nIonizedElectrons = energyDeposit.NumElectrons();
389 const double energy = energyDeposit.Energy();
393 if (nIonizedElectrons <= 0) {
394 MF_LOG_DEBUG(
"SimDriftElectrons")
396 <<
"No electrons drifted to readout, " << energy <<
" MeV lost.";
401 const double nElectrons = nIonizedElectrons * lifetimecorrection;
404 double SqrtT = std::sqrt(TDrift);
410 int nClus = (int)std::ceil(nElectrons / electronclsize);
413 if (electronclsize < 1.0) { electronclsize = 1.0; }
414 nClus = (int)std::ceil(nElectrons / electronclsize);
426 fnElDiff.resize(nClus, electronclsize);
430 fnElDiff.back() = nElectrons - (nClus - 1) * electronclsize;
432 for (
size_t xx = 0; xx <
fnElDiff.size(); ++xx) {
445 if (TDiffSig > 0.0) {
456 for (
size_t p = 0;
p < tpcGeo.
Nplanes(); ++
p) {
461 for (
int k = 0;
k < nClus; ++
k) {
464 double TDiff = TDrift +
fLongDiff[
k] * fRecipDriftVel[0];
469 for (
size_t ip = 0; ip <
p; ++ip) {
472 fRecipDriftVel[(tpcGeo.
Nplanes() == 2 && driftcoordinate == 0) ? ip + 2 : ip + 1];
488 auto const simTime = energyDeposit.Time();
489 unsigned int tdc = tpcClock.Ticks(clockData.G4ToElecTime(TDiff + simTime));
493 auto search = channelDataMap.find(channel);
497 size_t channelIndex = 0;
501 if (search == channelDataMap.end()) {
504 ChannelBookKeeping bookKeeping;
508 bookKeeping.channelIndex = channels->size();
509 channels->emplace_back(channel);
510 channelIndex = bookKeeping.channelIndex;
514 bookKeeping.stepList.push_back(edIndex);
517 channelDataMap[channel] = bookKeeping;
523 auto& bookKeeping = search->second;
524 channelIndex = bookKeeping.channelIndex;
527 auto& stepList = bookKeeping.stepList;
528 if (!std::binary_search(stepList.begin(), stepList.end(), edIndex)) {
530 stepList.push_back(edIndex);
542 SimDriftedElectronClusterCollection->emplace_back(
548 fDriftClusterPos[2]},
550 LDiffSig, TDiffSig, TDiffSig},
552 energyDeposit.TrackID());
554 catch (cet::exception& e) {
555 mf::LogDebug(
"SimDriftElectrons")
556 <<
"unable to drift electrons from point (" << xyz[0] <<
"," << xyz[1] <<
","
557 << xyz[2] <<
") with exception " <<
e;
564 event.put(std::move(channels));
Store parameters for running LArG4.
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
std::vector< double > fTransDiff2
double PlanePitch(unsigned int p1=0, unsigned int p2=1) const
Utilities related to art service access.
double fElectronClusterSize
Energy deposited on a readout channel by simulated tracks.
contains objects relating to SimDriftedElectronCluster
bool out_of_bounds(geo::Vector_t const &offset)
unsigned int Nplanes() const
Number of planes in this tpc.
Geometry information for a single TPC.
std::vector< size_t > stepList
CLHEP::RandGauss fRandGauss
art::ServiceHandle< geo::Geometry const > fGeometry
Handle to the Geometry service.
std::vector< size_t > fNTPCs
double fLongitudinalDiffusion
createEngine fStoreDriftedElectronClusters
Utility function for testing if Space Charge offsets are out of bounds.
void produce(art::Event &evt) override
std::vector< double > fnEnDiff
std::vector< ChannelMap_t > fChannelMaps
double fTransverseDiffusion
art::InputTag fSimModuleLabel
double fLifetimeCorr_const
std::vector< double > fLongDiff
double fDriftClusterPos[3]
std::vector< double > fTransDiff1
short int DetectDriftDirection() const
Returns the expected drift direction based on geometry.
contains information for a single step in the detector simulation
std::vector< double > fnElDiff
object containing MC truth information necessary for making RawDigits and doing back tracking ...
void AddIonizationElectrons(TrackID_t trackID, TDC_t tdc, double numberElectrons, double const *xyz, double energy, TrackID_t origTrackID=util::kBogusI)
Add ionization electrons and energy to this channel.
std::unordered_map< raw::ChannelID_t, ChannelBookKeeping > ChannelMap_t
unsigned int ChannelID_t
Type representing the ID of a readout channel.
bool fStoreDriftedElectronClusters
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
int fMinNumberOfElCluster
const double * PlaneLocation(unsigned int p) const
art framework interface to geometry description
SimDriftElectrons(fhicl::ParameterSet const &pset)