17 #include "Geant4/G4Step.hh"
18 #include "Geant4/G4StepPoint.hh"
19 #include "Geant4/G4ThreeVector.hh"
20 #include "Geant4/G4VPhysicalVolume.hh"
23 #include "cetlib_except/exception.h"
24 #include "messagefacility/MessageLogger/MessageLogger.h"
42 #include "CLHEP/Random/RandGauss.h"
56 unsigned int cryostat, tpc;
57 if (std::sscanf(name.c_str(),
"%*19s%1u%*4s%u", &cryostat, &tpc) == 2)
88 MF_LOG_DEBUG(
"LArVoxelReadout") << GetName() <<
"covers C=" <<
fCstat <<
" T=" <<
fTPC;
97 MF_LOG_DEBUG(
"LArVoxelReadout") << GetName() <<
" autodetects TPC";
106 "You must use set the clock data pointer at the beginning "
107 "of each module's event-level call. This might be done through the "
108 "LArVoxelReadoutGeometry::Sentry class.");
110 "You must use set the detector-properties data pointer at the beginning "
111 "of each module's event-level call. This might be done through the "
112 "LArVoxelReadoutGeometry::Sentry class.");
115 for (
int i = 0; i < 3; ++i)
126 MF_LOG_DEBUG(
"LArVoxelReadout")
141 MF_LOG_DEBUG(
"LArVoxelReadout") <<
"Total number of steps was " <<
fNSteps << std::endl;
157 for (
auto& channelsMap : cryoData)
166 throw cet::exception(
"LArVoxelReadout") <<
"TPC not specified";
173 throw cet::exception(
"LArVoxelReadout") <<
"TPC not specified";
188 std::vector<sim::SimChannel>
192 throw cet::exception(
"LArVoxelReadout") <<
"TPC not specified";
195 std::vector<sim::SimChannel>
198 std::vector<sim::SimChannel> channels;
200 channels.reserve(chmap.size());
201 for (
const auto& chpair : chmap)
202 channels.push_back(chpair.second);
225 if (step->GetTotalEnergyDeposit() > 0) {
233 G4ThreeVector midPoint =
234 0.5 * (step->GetPreStepPoint()->GetPosition() + step->GetPostStepPoint()->GetPosition());
235 double g4time = step->GetPreStepPoint()->GetGlobalTime();
249 unsigned short int cryostat = 0, tpc = 0;
256 const G4VTouchable* pTouchable = step->GetPreStepPoint()->GetTouchable();
258 throw cet::exception(
"LArG4") <<
"Untouchable step in LArVoxelReadout::ProcessHits()";
266 while (depth < pTouchable->GetHistoryDepth()) {
269 if (!pPVinTPC)
continue;
270 cryostat = pPVinTPC->
ID.Cryostat;
271 tpc = pPVinTPC->
ID.TPC;
275 if (depth < pTouchable->GetHistoryDepth()) {
278 throw cet::exception(
"LArG4") <<
"No TPC ID found in LArVoxelReadout::ProcessHits()";
280 MF_LOG_DEBUG(
"LArVoxelReadoutHit") <<
" hit in C=" << cryostat <<
" T=" << tpc;
324 if ((offPlane.X() == 0.0) && (offPlane.Y() == 0.0))
return pos;
341 G4ThreeVector stepMidPoint,
342 const double simTime,
344 unsigned short int cryostat,
345 unsigned short int tpc,
348 auto const tpcClock = clockData.
TPCClock();
353 CLHEP::RandGauss PropRand(*
fPropGen);
362 static double RecipDriftVel[3] = {
370 add(
double more_energy,
double more_electrons)
372 energy += more_energy;
378 std::map<raw::ChannelID_t, std::map<unsigned int, Deposit_t>> DepositsToStore;
380 double xyz1[3] = {0.};
382 double const xyz[3] = {
383 stepMidPoint.x() / CLHEP::cm, stepMidPoint.y() / CLHEP::cm, stepMidPoint.z() / CLHEP::cm};
397 XDrift = stepMidPoint.x() / CLHEP::cm - tpcg.
PlaneLocation(0)[0];
399 XDrift = tpcg.
PlaneLocation(0)[0] - stepMidPoint.x() / CLHEP::cm;
401 if (XDrift < 0.)
return;
405 auto const* SCE = lar::providerFrom<spacecharge::SpaceChargeService>();
406 if (SCE->EnableSimSpatialSCE() ==
true) {
407 posOffsets = SCE->GetPosOffsets({xyz[0], xyz[1], xyz[2]});
412 posOffsets.SetX(-posOffsets.X());
416 XDrift += posOffsets.X();
422 if (XDrift < 0.) XDrift = 0.;
424 TDrift = XDrift * RecipDriftVel[0];
426 TDrift = ((XDrift - tpcg.
PlanePitch(0, 1)) * RecipDriftVel[0] +
430 const double lifetimecorrection = TMath::Exp(TDrift / LifetimeCorr_const);
431 const int nIonizedElectrons =
437 if (nIonizedElectrons <= 0) {
438 MF_LOG_DEBUG(
"LArVoxelReadout")
439 <<
"No electrons drifted to readout, " << energy <<
" MeV lost.";
443 const double nElectrons = nIonizedElectrons * lifetimecorrection;
446 double SqrtT = std::sqrt(TDrift);
447 double LDiffSig = SqrtT * LDiff_const;
448 double TDiffSig = SqrtT * TDiff_const;
451 int nClus = (int)std::ceil(nElectrons / electronclsize);
454 if (electronclsize < 1.0) { electronclsize = 1.0; }
455 nClus = (int)std::ceil(nElectrons / electronclsize);
459 std::vector<double> XDiff(nClus);
460 std::vector<double> YDiff(nClus);
461 std::vector<double> ZDiff(nClus);
462 std::vector<double> nElDiff(nClus, electronclsize);
463 std::vector<double> nEnDiff(nClus);
466 nElDiff.back() = nElectrons - (nClus - 1) * electronclsize;
468 for (
size_t xx = 0; xx < nElDiff.size(); ++xx) {
470 nEnDiff[xx] = energy / nElectrons * nElDiff[xx];
475 double const avegageYtransversePos = (stepMidPoint.y() / CLHEP::cm) + posOffsets.Y();
476 double const avegageZtransversePos = (stepMidPoint.z() / CLHEP::cm) + posOffsets.Z();
480 PropRand.fireArray(nClus, &XDiff[0], 0., LDiffSig);
482 XDiff.assign(nClus, 0.0);
484 if (TDiffSig > 0.0) {
486 PropRand.fireArray(nClus, &YDiff[0], avegageYtransversePos, TDiffSig);
487 PropRand.fireArray(nClus, &ZDiff[0], avegageZtransversePos, TDiffSig);
490 YDiff.assign(nClus, avegageYtransversePos);
491 ZDiff.assign(nClus, avegageZtransversePos);
505 for (
int k = 0;
k < nClus; ++
k) {
507 double TDiff = TDrift + XDiff[
k] * RecipDriftVel[0];
510 for (
size_t ip = 0; ip <
p; ++ip) {
512 tpcg.
PlanePitch(ip, ip + 1) * RecipDriftVel[tpcg.
Nplanes() == 3 ? ip + 1 : ip + 2];
530 xyz1[0] = landingPos.X();
531 xyz1[1] = landingPos.Y();
532 xyz1[2] = landingPos.Z();
535 uint32_t channel =
fGeoHandle->NearestChannel(xyz1, p, tpc, cryostat);
540 unsigned int tdc = tpcClock.Ticks(clockData.
G4ToElecTime(TDiff + simTime));
543 DepositsToStore[channel][tdc].add(nEnDiff[
k], nElDiff[k]);
545 catch (cet::exception&
e) {
546 MF_LOG_DEBUG(
"LArVoxelReadout")
547 <<
"unable to drift electrons from point (" << xyz[0] <<
"," << xyz[1] <<
","
548 << xyz[2] <<
") with exception " <<
e;
557 for (
auto const& deposit_per_channel : DepositsToStore) {
562 auto iChannelData = ChannelDataMap.find(channel);
568 sim::SimChannel& channelData = (iChannelData == ChannelDataMap.end()) ?
570 iChannelData->second;
573 for (
auto const& deposit_per_tdc : deposit_per_channel.second) {
575 deposit_per_tdc.first,
576 deposit_per_tdc.second.electrons,
578 deposit_per_tdc.second.energy,
585 catch (cet::exception&
e) {
586 MF_LOG_DEBUG(
"LArVoxelReadout") <<
"step cannot be found in a TPC\n" <<
e;
CLHEP::HepRandomEngine * propGen
Random engine for charge propagation.
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
double NumberIonizationElectrons() const
unsigned int fTPC
which TPC this LArVoxelReadout corresponds to
double fTransverseDiffusion
double PlanePitch(unsigned int p1=0, unsigned int p2=1) const
Utilities related to art service access.
Collection of what it takes to set a LArVoxelReadout up.
Energy deposited on a readout channel by simulated tracks.
static int GetCurrentOrigTrackID()
A G4PVPlacement with an additional identificator.
art::ServiceHandle< sim::LArG4Parameters const > fLgpHandle
Handle to the LArG4 parameters service.
ElecClock const & TPCClock() const noexcept
Borrow a const TPC clock with time set to Trigger time [us].
bool out_of_bounds(geo::Vector_t const &offset)
unsigned int Nplanes() const
Number of planes in this tpc.
art::ServiceHandle< geo::Geometry const > fGeoHandle
Handle to the Geometry service.
Geometry information for a single TPC.
double Temperature() const
In kelvin.
const ChannelMap_t & GetSimChannelMap() const
Returns the accumulated channel -> SimChannel map for the single TPC.
LArVoxelReadout(std::string const &name)
Constructor. Can detect which TPC to cover by the name.
Point ComposePoint(WireDecomposedVector_t const &decomp) const
Returns the 3D point from composition of projection and distance.
void Setup(Setup_t const &setupData)
Reads all the configuration elements from setupData
WidthDepthProjection_t PointWidthDepthProjection(geo::Point_t const &point) const
Returns the projection of the specified point on the plane.
int fMinNumberOfElCluster
void SetRandomEngines(CLHEP::HepRandomEngine *pPropGen)
Sets the random generators to be used.
double ElectronLifetime() const
detinfo::DetectorClocksData const * fClockData
Drift towards negative X values.
pure virtual base interface for detector clocks
double fLongitudinalDiffusion
void Reset(const G4Step *step)
double Efield(unsigned int planegap=0) const
kV/cm
bool bSingleTPC
true if this readout is associated with a single TPC
ID_t ID
Physical Volume identificator.
geo::Point_t RecoverOffPlaneDeposit(geo::Point_t const &pos, geo::PlaneGeo const &plane) const
Returns the point on the specified plane closest to position.
void SetSingleTPC(unsigned int cryostat, unsigned int tpc)
Associates this readout to one specific TPC.
std::map< unsigned int, sim::SimChannel > ChannelMap_t
Type of map channel -> sim::SimChannel.
double fElectronClusterSize
Use Geant4's user "hooks" to maintain a list of particles generated by Geant4.
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
std::vector< unsigned short int > fSkipWireSignalInTPCs
void DriftIonizationElectrons(detinfo::DetectorClocksData const &clockData, G4ThreeVector stepMidPoint, const double simTime, int trackID, unsigned short int cryostat, unsigned short int tpc, int origTrackID)
Utility function for testing if Space Charge offsets are out of bounds.
for($it=0;$it< $RaceTrack_number;$it++)
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
static IonizationAndScintillation * Instance()
std::vector< sim::SimChannel > GetSimChannels() const
Creates a list with the accumulated information for the single TPC.
detinfo::DetectorPropertiesData const * fDetProp
double DriftVelocity(double efield=0., double temperature=0.) const
cm/us
bool Has(std::vector< unsigned short int > v, unsigned short int tpc) const
virtual G4bool ProcessHits(G4Step *, G4TouchableHistory *)
Definition of data types for geometry description.
double Plane0Pitch(unsigned int p) const
DriftDirection_t DriftDirection() const
Returns an enumerator value describing the drift direction.
std::vector< std::vector< ChannelMap_t > > fChannelMaps
Maps of cryostat, tpc to channel data.
virtual void EndOfEvent(G4HCofThisEvent *)
double fOffPlaneMargin
Charge deposited within this many [cm] from the plane is lead onto it.
void SetDiscoverTPC()
Sets this readout to discover the TPC of each processed hit.
A Geant4 sensitive detector that accumulates voxel information.
double offPlaneMargin
Margin for charge recovery (see LArVoxelReadout).
WidthDepthProjection_t DeltaFromActivePlane(WidthDepthProjection_t const &proj, double wMargin, double dMargin) const
Returns a projection vector that, added to the argument, gives a projection inside (or at the border ...
double G4ToElecTime(double const g4_time) const
Drift towards positive X values.
Contains all timing reference information for the detector.
double DistanceFromPlane(geo::Point_t const &point) const
Returns the distance of the specified point from the wire plane.
unsigned int fCstat
and in which cryostat (if bSingleTPC is true)
void SetOffPlaneChargeRecoveryMargin(double margin)
Sets the margin for recovery of charge drifted off-plane.
Singleton to access a unified treatment of ionization and scintillation in LAr.
static int GetCurrentTrackID()
double EnergyDeposit() const
CLHEP::HepRandomEngine * fPropGen
random engine for charge propagation
virtual void Initialize(G4HCofThisEvent *)
Transports energy depositions from GEANT4 to TPC channels.
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
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.
unsigned int ChannelID_t
Type representing the ID of a readout channel.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
const double * PlaneLocation(unsigned int p) const