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" 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)
94 MF_LOG_DEBUG(
"LArVoxelReadout") << GetName() <<
" autodetects TPC";
102 "You must use set the clock data pointer at the beginning " 103 "of each module's event-level call. This might be done through the " 104 "LArVoxelReadoutGeometry::Sentry class.");
106 "You must use set the detector-properties data pointer at the beginning " 107 "of each module's event-level call. This might be done through the " 108 "LArVoxelReadoutGeometry::Sentry class.");
111 for (
int i = 0; i < 3; ++i)
149 for (
auto& channelsMap : cryoData)
167 unsigned short tpc)
const 185 unsigned short tpc)
const 187 std::vector<sim::SimChannel> channels;
189 channels.reserve(chmap.size());
190 for (
const auto& chpair : chmap)
191 channels.push_back(chpair.second);
213 if (step->GetTotalEnergyDeposit() > 0) {
221 G4ThreeVector midPoint =
222 0.5 * (step->GetPreStepPoint()->GetPosition() + step->GetPostStepPoint()->GetPosition());
223 double g4time = step->GetPreStepPoint()->GetGlobalTime();
237 unsigned short int cryostat = 0, tpc = 0;
244 const G4VTouchable* pTouchable = step->GetPreStepPoint()->GetTouchable();
246 throw cet::exception(
"LArG4") <<
"Untouchable step in LArVoxelReadout::ProcessHits()";
254 while (depth < pTouchable->GetHistoryDepth()) {
257 if (!pPVinTPC)
continue;
258 cryostat = pPVinTPC->
ID.Cryostat;
259 tpc = pPVinTPC->
ID.TPC;
263 if (depth < pTouchable->GetHistoryDepth()) {
266 throw cet::exception(
"LArG4") <<
"No TPC ID found in LArVoxelReadout::ProcessHits()";
268 MF_LOG_DEBUG(
"LArVoxelReadoutHit") <<
" hit in C=" << cryostat <<
" T=" << tpc;
275 *
fClockData, midPoint, g4time, trackID, cryostat, tpc, origTrackID);
312 if ((offPlane.X() == 0.0) && (offPlane.Y() == 0.0))
return pos;
322 return plane.
ComposePoint(distance, landingPos + offPlane);
328 G4ThreeVector stepMidPoint,
329 const double simTime,
331 unsigned short int cryostat,
332 unsigned short int tpc,
335 auto const tpcClock = clockData.
TPCClock();
340 CLHEP::RandGauss PropRand(*
fPropGen);
349 static double RecipDriftVel[3] = {
354 double electrons = 0.;
356 void add(
double more_energy,
double more_electrons)
358 energy += more_energy;
359 electrons += more_electrons;
364 std::map<raw::ChannelID_t, std::map<unsigned int, Deposit_t>> DepositsToStore;
368 double const xyz[3] = {
369 stepMidPoint.x() / CLHEP::cm, stepMidPoint.y() / CLHEP::cm, stepMidPoint.z() / CLHEP::cm};
381 double XDrift =
std::abs(stepMidPoint.x() / CLHEP::cm - plane_center.X());
384 XDrift = stepMidPoint.x() / CLHEP::cm - plane_center.X();
386 XDrift = plane_center.X() - stepMidPoint.x() / CLHEP::cm;
388 if (XDrift < 0.)
return;
392 auto const* SCE = lar::providerFrom<spacecharge::SpaceChargeService>();
393 if (SCE->EnableSimSpatialSCE() ==
true) {
394 posOffsets = SCE->GetPosOffsets({xyz[0], xyz[1], xyz[2]});
397 posOffsets.SetX(-posOffsets.X());
401 XDrift += posOffsets.X();
407 if (XDrift < 0.) XDrift = 0.;
409 TDrift = XDrift * RecipDriftVel[0];
411 TDrift = ((XDrift - tpcg.
PlanePitch(0, 1)) * RecipDriftVel[0] +
415 const double lifetimecorrection = TMath::Exp(TDrift / LifetimeCorr_const);
416 const int nIonizedElectrons =
422 if (nIonizedElectrons <= 0) {
424 <<
"No electrons drifted to readout, " << energy <<
" MeV lost.";
428 const double nElectrons = nIonizedElectrons * lifetimecorrection;
431 double SqrtT = std::sqrt(TDrift);
432 double LDiffSig = SqrtT * LDiff_const;
433 double TDiffSig = SqrtT * TDiff_const;
436 int nClus = (int)std::ceil(nElectrons / electronclsize);
439 if (electronclsize < 1.0) { electronclsize = 1.0; }
440 nClus = (int)std::ceil(nElectrons / electronclsize);
444 std::vector<double> XDiff(nClus);
445 std::vector<double> YDiff(nClus);
446 std::vector<double> ZDiff(nClus);
447 std::vector<double> nElDiff(nClus, electronclsize);
448 std::vector<double> nEnDiff(nClus);
451 nElDiff.back() = nElectrons - (nClus - 1) * electronclsize;
453 for (
size_t xx = 0;
xx < nElDiff.size(); ++
xx) {
455 nEnDiff[
xx] = energy / nElectrons * nElDiff[
xx];
460 double const averageYtransversePos = (stepMidPoint.y() / CLHEP::cm) + posOffsets.Y();
461 double const averageZtransversePos = (stepMidPoint.z() / CLHEP::cm) + posOffsets.Z();
465 PropRand.fireArray(nClus, &XDiff[0], 0., LDiffSig);
467 XDiff.assign(nClus, 0.0);
469 if (TDiffSig > 0.0) {
471 PropRand.fireArray(nClus, &YDiff[0], averageYtransversePos, TDiffSig);
472 PropRand.fireArray(nClus, &ZDiff[0], averageZtransversePos, TDiffSig);
475 YDiff.assign(nClus, averageYtransversePos);
476 ZDiff.assign(nClus, averageZtransversePos);
480 for (
size_t p = 0; p < tpcg.
Nplanes(); ++p) {
490 for (
int k = 0; k < nClus; ++k) {
492 double TDiff = TDrift + XDiff[k] * RecipDriftVel[0];
495 for (
size_t ip = 0; ip < p; ++ip) {
497 tpcg.
PlanePitch(ip, ip + 1) * RecipDriftVel[tpcg.
Nplanes() == 3 ? ip + 1 : ip + 2];
521 unsigned int tdc = tpcClock.Ticks(clockData.
G4ToElecTime(TDiff + simTime));
524 DepositsToStore[channel][tdc].add(nEnDiff[k], nElDiff[k]);
528 <<
"unable to drift electrons from point (" << xyz[0] <<
"," << xyz[1] <<
"," 529 << xyz[2] <<
") with exception " <<
e;
538 for (
auto const& deposit_per_channel : DepositsToStore) {
543 auto iChannelData = ChannelDataMap.find(channel);
549 sim::SimChannel& channelData = (iChannelData == ChannelDataMap.end()) ?
551 iChannelData->second;
554 for (
auto const& deposit_per_tdc : deposit_per_channel.second) {
556 deposit_per_tdc.first,
557 deposit_per_tdc.second.electrons,
559 deposit_per_tdc.second.energy,
567 MF_LOG_DEBUG(
"LArVoxelReadout") <<
"step cannot be found in a TPC\n" <<
e;
CLHEP::HepRandomEngine * propGen
Random engine for charge propagation.
double NumberIonizationElectrons() const
unsigned int fTPC
which TPC this LArVoxelReadout corresponds to
unsigned int NTPC(CryostatID const &cryoid=cryostat_zero) const
Returns the total number of TPCs in the specified cryostat.
double fTransverseDiffusion
Point_t ComposePoint(WireDecomposedVector_t const &decomp) const
Returns the 3D point from composition of projection and distance.
double PlanePitch(unsigned int p1=0, unsigned int p2=1) const
Returns the center of the TPC volume in world coordinates [cm].
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.
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Point_t const & GetCenter() const
Returns the centre of the wire plane in world coordinates [cm].
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.
constexpr auto abs(T v)
Returns the absolute value of the argument.
LArVoxelReadout(std::string const &name)
Constructor. Can detect which TPC to cover by the name.
for(Int_t i=0;i< nentries;i++)
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.
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
pure virtual base interface for detector clocks
double fLongitudinalDiffusion
void Reset(const G4Step *step)
double Efield(unsigned int planegap=0) const
kV/cm
TPCGeo const & TPC(TPCID const &tpcid=tpc_zero) const
Returns the specified TPC.
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.
double TransverseDiffusion() const
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.
bool NoElectronPropagation() const
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)
const std::vector< unsigned short int > & SkipWireSignalInTPCs() const
Utility function for testing if Space Charge offsets are out of bounds.
double ElectronClusterSize() const
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
static IonizationAndScintillation * Instance()
ElecClock const & TPCClock() const noexcept
Borrow a const TPC clock with time set to Trigger time [us].
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
The data type to uniquely identify a TPC.
virtual G4bool ProcessHits(G4Step *, G4TouchableHistory *)
Definition of data types for geometry description.
double Plane0Pitch(unsigned int p) const
Returns the center of the TPC volume in world coordinates [cm].
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.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
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.
int MinNumberOfElCluster() const
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.
geo::PlaneID const & ID() const
Returns the identifier of this plane.
static int GetCurrentTrackID()
double EnergyDeposit() const
CLHEP::HepRandomEngine * fPropGen
random engine for charge propagation
virtual void Initialize(G4HCofThisEvent *)
raw::ChannelID_t NearestChannel(Point_t const &worldLoc, PlaneID const &planeid) const
Returns the ID of the channel nearest to the specified position.
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.
double LongitudinalDiffusion() const
unsigned int ChannelID_t
Type representing the ID of a readout channel.
cet::coded_exception< error, detail::translate > exception
bool DisableWireplanes() const
The data type to uniquely identify a cryostat.