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" 44 #include "CLHEP/Random/RandGauss.h" 62 unsigned int cryostat, tpc;
63 if (std::sscanf(name.c_str(),
"%*19s%1u%*4s%u", &cryostat, &tpc) == 2)
76 unsigned int cryostat,
104 MF_LOG_DEBUG(
"LArVoxelReadout") << GetName() <<
" autodetects TPC";
112 "You must use set the clock data pointer at the beginning " 113 "of each module's event-level call. This might be done through the " 114 "LArVoxelReadoutGeometry::Sentry class.");
116 "You must use set the detector-properties data pointer at the beginning " 117 "of each module's event-level call. This might be done through the " 118 "LArVoxelReadoutGeometry::Sentry class.");
121 for (
int i = 0; i < 3; ++i)
159 for (
auto& channelsMap : cryoData)
177 unsigned short tpc)
const 195 unsigned short tpc)
const 197 std::vector<sim::SimChannel> channels;
199 channels.reserve(chmap.size());
200 for (
const auto& chpair : chmap)
201 channels.push_back(chpair.second);
221 if (step->GetTotalEnergyDeposit() > 0) {
228 G4ThreeVector midPoint =
229 0.5 * (step->GetPreStepPoint()->GetPosition() + step->GetPostStepPoint()->GetPosition());
230 double g4time = step->GetPreStepPoint()->GetGlobalTime();
243 unsigned short int cryostat = 0, tpc = 0;
250 const G4VTouchable* pTouchable = step->GetPreStepPoint()->GetTouchable();
252 throw cet::exception(
"LArG4") <<
"Untouchable step in LArVoxelReadout::ProcessHits()";
260 while (depth < pTouchable->GetHistoryDepth()) {
263 if (!pPVinTPC)
continue;
264 cryostat = pPVinTPC->
ID.Cryostat;
265 tpc = pPVinTPC->
ID.TPC;
269 if (depth < pTouchable->GetHistoryDepth()) {
272 throw cet::exception(
"LArG4") <<
"No TPC ID found in LArVoxelReadout::ProcessHits()";
274 MF_LOG_DEBUG(
"LArVoxelReadoutHit") <<
" hit in C=" << cryostat <<
" T=" << tpc;
281 *
fClockData, midPoint, g4time, trackID, cryostat, tpc, origTrackID);
309 if ((offPlane.X() == 0.0) && (offPlane.Y() == 0.0))
return pos;
319 return plane.
ComposePoint(distance, landingPos + offPlane);
325 G4ThreeVector stepMidPoint,
326 const double simTime,
328 unsigned short int cryostat,
329 unsigned short int tpc,
332 auto const tpcClock = clockData.
TPCClock();
337 CLHEP::RandGauss PropRand(*
fPropGen);
345 static double RecipDriftVel[3] = {
350 double electrons = 0.;
352 void add(
double more_energy,
double more_electrons)
354 energy += more_energy;
355 electrons += more_electrons;
360 std::map<raw::ChannelID_t, std::map<unsigned int, Deposit_t>> DepositsToStore;
364 double const xyz[3] = {
365 stepMidPoint.x() / CLHEP::cm, stepMidPoint.y() / CLHEP::cm, stepMidPoint.z() / CLHEP::cm};
378 double XDrift =
std::abs(stepMidPoint.x() / CLHEP::cm - plane_center.X());
381 XDrift = stepMidPoint.x() / CLHEP::cm - plane_center.X();
383 XDrift = plane_center.X() - stepMidPoint.x() / CLHEP::cm;
385 if (XDrift < 0.)
return;
389 auto const* SCE = lar::providerFrom<spacecharge::SpaceChargeService>();
390 if (SCE->EnableSimSpatialSCE() ==
true) {
391 posOffsets = SCE->GetPosOffsets({xyz[0], xyz[1], xyz[2]});
394 posOffsets.SetX(-posOffsets.X());
398 XDrift += posOffsets.X();
404 if (XDrift < 0.) XDrift = 0.;
406 TDrift = XDrift * RecipDriftVel[0];
410 TDrift = ((XDrift - pitch) * RecipDriftVel[0] + pitch * RecipDriftVel[1]);
413 const double lifetimecorrection = TMath::Exp(TDrift / LifetimeCorr_const);
414 const int nIonizedElectrons =
420 if (nIonizedElectrons <= 0) {
422 <<
"No electrons drifted to readout, " << energy <<
" MeV lost.";
426 const double nElectrons = nIonizedElectrons * lifetimecorrection;
429 double SqrtT = std::sqrt(TDrift);
430 double LDiffSig = SqrtT * LDiff_const;
431 double TDiffSig = SqrtT * TDiff_const;
434 int nClus = (int)std::ceil(nElectrons / electronclsize);
437 if (electronclsize < 1.0) { electronclsize = 1.0; }
438 nClus = (int)std::ceil(nElectrons / electronclsize);
442 std::vector<double> XDiff(nClus);
443 std::vector<double> YDiff(nClus);
444 std::vector<double> ZDiff(nClus);
445 std::vector<double> nElDiff(nClus, electronclsize);
446 std::vector<double> nEnDiff(nClus);
449 nElDiff.back() = nElectrons - (nClus - 1) * electronclsize;
451 for (
size_t xx = 0;
xx < nElDiff.size(); ++
xx) {
453 nEnDiff[
xx] = energy / nElectrons * nElDiff[
xx];
458 double const averageYtransversePos = (stepMidPoint.y() / CLHEP::cm) + posOffsets.Y();
459 double const averageZtransversePos = (stepMidPoint.z() / CLHEP::cm) + posOffsets.Z();
463 PropRand.fireArray(nClus, &XDiff[0], 0., LDiffSig);
465 XDiff.assign(nClus, 0.0);
467 if (TDiffSig > 0.0) {
469 PropRand.fireArray(nClus, &YDiff[0], averageYtransversePos, TDiffSig);
470 PropRand.fireArray(nClus, &ZDiff[0], averageZtransversePos, TDiffSig);
473 YDiff.assign(nClus, averageYtransversePos);
474 ZDiff.assign(nClus, averageZtransversePos);
484 xyz1.SetX(plane_0_center_x - Plane0Pitch);
487 for (
int k = 0; k < nClus; ++k) {
489 double TDiff = TDrift + XDiff[k] * RecipDriftVel[0];
492 for (
unsigned int ip = 0; ip < plane.ID().Plane; ++ip) {
494 RecipDriftVel[nplanes == 3 ? ip + 1 : ip + 2];
517 unsigned int tdc = tpcClock.Ticks(clockData.
G4ToElecTime(TDiff + simTime));
520 DepositsToStore[channel][tdc].add(nEnDiff[k], nElDiff[k]);
524 <<
"unable to drift electrons from point (" << xyz[0] <<
"," << xyz[1] <<
"," 525 << xyz[2] <<
") with exception " <<
e;
534 for (
auto const& deposit_per_channel : DepositsToStore) {
539 auto iChannelData = ChannelDataMap.find(channel);
545 sim::SimChannel& channelData = (iChannelData == ChannelDataMap.end()) ?
547 iChannelData->second;
550 for (
auto const& deposit_per_tdc : deposit_per_channel.second) {
552 deposit_per_tdc.first,
553 deposit_per_tdc.second.electrons,
555 deposit_per_tdc.second.energy,
563 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
double fTransverseDiffusion
Point_t ComposePoint(WireDecomposedVector_t const &decomp) const
Returns the 3D point from composition of projection and distance.
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.
double Plane0Pitch(TPCID const &tpcid, unsigned int p1) const
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 NTPC(CryostatID const &cryoid=details::cryostat_zero) const
Returns the total number of TPCs in the specified cryostat.
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.
for(Int_t i=0;i< nentries;i++)
void Setup(Setup_t const &setupData)
Reads all the configuration elements from setupData
double PlanePitch(TPCID const &tpcid, unsigned int p1=0, unsigned int p2=1) const
int fMinNumberOfElCluster
void SetRandomEngines(CLHEP::HepRandomEngine *pPropGen)
Sets the random generators to be used.
double DistanceFromPlane(Point_t const &point) const
Returns the distance of the specified point from the wire plane.
double ElectronLifetime() const
detinfo::DetectorClocksData const * fClockData
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
DriftAxis DriftAxisWithSign() const
Returns the expected drift direction based on geometry.
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.
Access the description of the physical detector geometry.
geo::Point_t RecoverOffPlaneDeposit(geo::Point_t const &pos, geo::PlaneGeo const &plane) const
Returns the point on the specified plane closest to position.
geo::GeometryCore const * fGeo
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
Interface for a class providing readout channel mapping to geometry.
Drift towards negative values.
WidthDepthProjection_t PointWidthDepthProjection(Point_t const &point) const
Returns the projection of the specified point on the plane.
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.
Description of the physical geometry of one entire detector.
virtual G4bool ProcessHits(G4Step *, G4TouchableHistory *)
Definition of data types for geometry description.
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.
raw::ChannelID_t NearestChannel(Point_t const &worldLoc, PlaneID const &planeid) const
Returns the ID of the channel nearest to the specified position.
unsigned int Nplanes(TPCID const &tpcid=details::tpc_zero) const
Returns the total number of planes in the specified TPC.
Drift towards positive values.
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.
PlaneGeo const & FirstPlane(TPCID const &tpcid) const
Returns the first plane of the specified TPC.
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
Contains all timing reference information for the detector.
int MinNumberOfElCluster() const
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
range_type< T > Iterate() const
CLHEP::HepRandomEngine * fPropGen
random engine for charge propagation
virtual void Initialize(G4HCofThisEvent *)
sim::LArG4Parameters const * fLgp
Transports energy depositions from GEANT4 to TPC channels.
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.
TPCGeo const & TPC(TPCID const &tpcid=details::tpc_zero) const
Returns the specified TPC.
geo::WireReadoutGeom const * fWireReadoutGeom
Interface to geometry for wire readouts .
cet::coded_exception< error, detail::translate > exception
LArVoxelReadout(std::string const &name, geo::GeometryCore const *geom, geo::WireReadoutGeom const *wireReadoutGeom, sim::LArG4Parameters const *lgp)
Constructor. Can detect which TPC to cover by the name.
bool DisableWireplanes() const
The data type to uniquely identify a cryostat.