17 #include "Geant4/G4HCofThisEvent.hh" 18 #include "Geant4/G4TouchableHistory.hh" 19 #include "Geant4/G4TouchableHandle.hh" 20 #include "Geant4/G4Step.hh" 21 #include "Geant4/G4StepPoint.hh" 22 #include "Geant4/G4ThreeVector.hh" 23 #include "Geant4/G4VPhysicalVolume.hh" 26 #include "cetlib_except/exception.h" 37 #include "CLHEP/Random/RandGauss.h" 38 #include "CLHEP/Random/RandPoisson.h" 39 #include "CLHEP/Random/RandFlat.h" 48 : G4VSensitiveDetector(name)
58 unsigned int cryostat, tpc;
59 if (std::sscanf(name.c_str(),
"%*19s%1u%*4s%u",&cryostat, &tpc) == 2)
70 (std::string
const& name,
unsigned int cryostat,
unsigned int tpc)
90 << GetName() <<
"covers C=" <<
fCstat <<
" T=" <<
fTPC;
97 LOG_DEBUG(
"LArVoxelReadout") << GetName() <<
" autodetects TPC";
110 auto const * detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
112 for (
int i = 0; i<3; ++i)
114 detprop->Temperature())/1000.;
123 LOG_DEBUG(
"LArVoxelReadout") <<
" e lifetime: " << fElectronLifetime
124 <<
"\n Temperature: " << detprop->Temperature()
152 for (
auto& channelsMap: cryoData) channelsMap.clear();
170 (
unsigned short cryo,
unsigned short tpc)
const 174 (
unsigned short cryo,
unsigned short tpc)
184 (
unsigned short cryo,
unsigned short tpc)
const 186 std::vector<sim::SimChannel> channels;
188 channels.reserve(chmap.size());
189 for(
const auto& chpair: chmap) channels.push_back(chpair.second);
212 if ( step->GetTotalEnergyDeposit() > 0 ){
220 G4ThreeVector midPoint = 0.5*( step->GetPreStepPoint()->GetPosition()
221 + step->GetPostStepPoint()->GetPosition() );
222 double g4time = step->GetPreStepPoint()->GetGlobalTime();
232 unsigned short int cryostat = 0, tpc = 0;
239 const G4VTouchable* pTouchable = step->GetPreStepPoint()->GetTouchable();
242 (
"LArG4") <<
"Untouchable step in LArVoxelReadout::ProcessHits()";
250 while (depth < pTouchable->GetHistoryDepth()) {
253 (pTouchable->GetVolume(depth++));
254 if (!pPVinTPC)
continue;
255 cryostat = pPVinTPC->
ID.Cryostat;
256 tpc = pPVinTPC->
ID.TPC;
263 if (depth < pTouchable->GetHistoryDepth()) {
267 (
"LArG4") <<
"No TPC ID found in LArVoxelReadout::ProcessHits()";
269 LOG_DEBUG(
"LArVoxelReadoutHit") <<
" hit in C=" << cryostat <<
" T=" << tpc;
313 if ((offPlane.X() == 0.0) && (offPlane.Y() == 0.0))
return pos;
332 const double simTime,
334 unsigned short int cryostat,
unsigned short int tpc)
336 auto const * ts = lar::providerFrom<detinfo::DetectorClocksService>();
341 CLHEP::RandGauss PropRand(*
fPropGen);
356 double electrons = 0.;
358 void add(
double more_energy,
double more_electrons)
359 { energy += more_energy; electrons += more_electrons; }
363 std::map<raw::ChannelID_t, std::map<unsigned int, Deposit_t>> DepositsToStore;
365 double xyz1[3] = {0.};
367 double const xyz[3] = {stepMidPoint.x() / CLHEP::cm,
368 stepMidPoint.y() / CLHEP::cm,
369 stepMidPoint.z() / CLHEP::cm};
380 double XDrift = std::abs(stepMidPoint.x()/CLHEP::cm - tpcg.
PlaneLocation(0)[0]);
383 XDrift = stepMidPoint.x()/CLHEP::cm - tpcg.
PlaneLocation(0)[0];
385 XDrift = tpcg.
PlaneLocation(0)[0] - stepMidPoint.x()/CLHEP::cm;
387 if(XDrift < 0.)
return;
391 auto const* SCE = lar::providerFrom<spacecharge::SpaceChargeService>();
392 if (SCE->EnableSimSpatialSCE() ==
true)
394 posOffsets = SCE->GetPosOffsets({ xyz[0], xyz[1], xyz[2] });
396 posOffsets.SetX(-posOffsets.X());
400 XDrift += posOffsets.X();
406 if (XDrift < 0.) XDrift = 0.;
408 TDrift = XDrift * RecipDriftVel[0];
410 TDrift = ((XDrift - tpcg.
PlanePitch(0,1)) * RecipDriftVel[0]
414 const double lifetimecorrection = TMath::Exp(TDrift / LifetimeCorr_const);
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);
438 if (electronclsize < 1.0)
440 electronclsize = 1.0;
442 nClus = (int) std::ceil(nElectrons / electronclsize);
446 std::vector< double > XDiff(nClus);
447 std::vector< double > YDiff(nClus);
448 std::vector< double > ZDiff(nClus);
449 std::vector< double > nElDiff(nClus, electronclsize);
450 std::vector< double > nEnDiff(nClus);
453 nElDiff.back() = nElectrons - (nClus-1)*electronclsize;
455 for(
size_t xx = 0;
xx < nElDiff.size(); ++
xx){
456 if(nElectrons > 0) nEnDiff[
xx] = energy/nElectrons*nElDiff[
xx];
457 else nEnDiff[
xx] = 0.;
460 double const avegageYtransversePos
461 = (stepMidPoint.y()/CLHEP::cm) + posOffsets.Y();
462 double const avegageZtransversePos
463 = (stepMidPoint.z()/CLHEP::cm) + posOffsets.Z();
467 PropRand.fireArray( nClus, &XDiff[0], 0., LDiffSig);
469 XDiff.assign(nClus, 0.0);
471 if (TDiffSig > 0.0) {
473 PropRand.fireArray( nClus, &YDiff[0], avegageYtransversePos, TDiffSig);
474 PropRand.fireArray( nClus, &ZDiff[0], avegageZtransversePos, TDiffSig);
477 YDiff.assign(nClus, avegageYtransversePos);
478 ZDiff.assign(nClus, avegageZtransversePos);
482 for(
size_t p = 0; p < tpcg.
Nplanes(); ++p){
492 for(
int k = 0; k < nClus; ++k){
494 double TDiff = TDrift + XDiff[k] * RecipDriftVel[0];
497 for (
size_t ip = 0; ip<p; ++ip){
515 auto const landingPos
517 xyz1[0] = landingPos.X();
518 xyz1[1] = landingPos.Y();
519 xyz1[2] = landingPos.Z();
527 unsigned int tdc =
fClock.
Ticks(ts->G4ToElecTime(TDiff + simTime));
530 DepositsToStore[channel][tdc].add(nEnDiff[k], nElDiff[k]);
533 mf::LogWarning(
"LArVoxelReadout") <<
"unable to drift electrons from point (" 534 << xyz[0] <<
"," << xyz[1] <<
"," << xyz[2]
535 <<
") with exception " <<
e;
544 for(
auto const& deposit_per_channel: DepositsToStore){
549 auto iChannelData = ChannelDataMap.find(channel);
556 = (iChannelData == ChannelDataMap.end())
558 : iChannelData->second;
561 for(
auto const& deposit_per_tdc: deposit_per_channel.second) {
563 deposit_per_tdc.first,
564 deposit_per_tdc.second.electrons,
566 deposit_per_tdc.second.energy);
573 mf::LogWarning(
"LArVoxelReadout") <<
"step cannot be found in a TPC\n" 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
Returns the center of the TPC volume in world coordinates [cm].
virtual const ::detinfo::ElecClock & TPCClock() const =0
Lends a constant TPC clock with time set to trigger time.
Collection of what it takes to set a LArVoxelReadout up.
Energy deposited on a readout channel by simulated tracks.
A G4PVPlacement with an additional identificator.
unsigned int Nplanes() const
Number of planes in this tpc.
Geometry information for a single TPC.
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.
art::ServiceHandle< sim::LArG4Parameters > fLgpHandle
Handle to the LArG4 parameters service.
Point ComposePoint(WireDecomposedVector_t const &decomp) const
Returns the 3D vector from composition of projection and distance.
virtual ~LArVoxelReadout()
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.
int Ticks() const
Current clock tick (that is, the number of tick Time() falls in).
art::ServiceHandle< geo::Geometry > fGeoHandle
Handle to the Geometry service.
Drift towards negative X values.
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
double fLongitudinalDiffusion
void Reset(const G4Step *step)
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
double ElectronClusterSize() const
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.
bool Has(std::vector< unsigned short int > v, unsigned short int tpc) const
virtual G4bool ProcessHits(G4Step *, G4TouchableHistory *)
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.
Conversion of times between different formats and references.
const std::vector< unsigned short int > SkipWireSignalInTPCs() const
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
void AddIonizationElectrons(TrackID_t trackID, TDC_t tdc, double numberElectrons, double const *xyz, double energy)
Add ionization electrons and energy to this channel.
void DriftIonizationElectrons(G4ThreeVector stepMidPoint, const double simTime, int trackID, unsigned short int cryostat, unsigned short int tpc)
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 ...
Drift towards positive X values.
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.
static int GetCurrentTrackID()
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
double EnergyDeposit() const
CLHEP::HepRandomEngine * fPropGen
random engine for charge propagation
virtual void Initialize(G4HCofThisEvent *)
::detinfo::ElecClock fClock
TPC electronics clock.
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
double LongitudinalDiffusion() const
unsigned int ChannelID_t
Type representing the ID of a readout channel.
raw::ChannelID_t NearestChannel(geo::Point_t const &worldLoc, geo::PlaneID const &planeid) const
Returns the ID of the channel nearest to the specified position.
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
Returns the coordinates of the center of the specified plane [cm].
cet::coded_exception< error, detail::translate > exception
bool DisableWireplanes() const