LArVoxelReadout.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file LArVoxelReadout.h
3 /// \brief A Geant4 sensitive detector that accumulates voxel information.
4 ///
5 /// \author seligman@nevis.columbia.edu
6 ////////////////////////////////////////////////////////////////////////
7 ///
8 /// One way to implement voxels in Geant4 is to create a parallel
9 /// "read-out" geometry along with the real, physical geometry. The
10 /// read-out geometry is implemented in LArVoxelReadoutGeometry; this
11 /// class is the sensitive detector for that geometry. That is,
12 /// Geant4 will call this routine every time there is a step within a
13 /// volume of the read-out geometry; this routine then accumulates
14 /// information from that step.
15 ///
16 /// In general, Geant4 expects to have per-event user information
17 /// attached to the G4Event in some way; their G4VSensitiveDetector
18 /// class supports this by allowing user-defined hit collections to
19 /// added to a G4HCOfThisEvent object (a collection of hit
20 /// collections; yes, it makes my head ache too!) that's part of each
21 /// G4Event.
22 ///
23 /// This class works differently, by accumulating the information in
24 /// its internal sim::LArVoxelList. See LArVoxelListAction for how
25 /// this information is made available to the main LArG4 module.
26 ///
27 /// Why define a parallel geometry? Here are some reasons:
28 ///
29 /// - The regular LAr TPC is one large volume of liquid argon. When
30 /// Geant4 does its physics modeling, it can be unconstrained in
31 /// step size by the voxels. Only for readout would the steps be
32 /// sub-divided.
33 ///
34 /// - There may be more than one kind of readout, depending on a
35 /// detector's instrumentation (e.g., OpDets in addition to the wire
36 /// planes). It's possible that the voxelization appropriate for
37 /// the wire planes may not be an appropriate readout for the other
38 /// readouts. Geant4 allows the construction of multiple parallel
39 /// readouts, so this mechanism is relatively easy to extend for
40 /// each type of readout.
41 ///
42 /// =================================================================
43 /// N.B. At the beginning of each event, the clock data pointer must
44 /// be set to the event currently being processed. This is a
45 /// thread-safety problem which should be reconciled for the
46 /// larg4 package if it has not already been. The way that is
47 /// done for the LArG4_module is for the LArVoxelReadoutGeometry
48 /// object to update the state of the LArVoxelReadout object
49 /// through a sentry object.
50 /// =================================================================
51 
52 #ifndef LArG4_LArVoxelReadout_h
53 #define LArG4_LArVoxelReadout_h
54 
55 #include <algorithm> // std::max()
56 #include <stddef.h>
57 #include <vector>
58 
59 #include "Geant4/G4PVPlacement.hh"
60 #include "Geant4/G4VSensitiveDetector.hh"
61 
67 namespace detinfo {
68  class DetectorClocksData;
69  class DetectorPropertiesData;
70 }
71 
72 // Forward declarations
73 class G4HCofThisEvent;
74 class G4TouchableHistory;
75 class G4Step;
76 
77 namespace CLHEP {
78  class HepRandomEngine;
79 }
80 
81 namespace larg4 {
82 
83  /// Simple structure holding a TPC and cryostat number
84  struct TPCID_t {
85  unsigned short int Cryostat, TPC;
86  bool
87  operator<(const TPCID_t& than) const
88  {
89  return (Cryostat < than.Cryostat) || ((Cryostat == than.Cryostat) && (TPC < than.TPC));
90  } // operator< ()
91  }; // TPCID_t
92 
93  /**
94  * @brief A G4PVPlacement with an additional identificator
95  * @param IDTYPE type of ID class
96  *
97  * This class is a G4PVPlacement with in addition an ID parameter.
98  * The ID type is an object which can be default-constructed and copied,
99  * better to be a POD.
100  *
101  * This being a very stupid utility class, only the constructor that we
102  * actually use is available. The others can be implemented in the same way.
103  * Also the merry company of copy and move constuctors and operators is left
104  * to the good will of the compiler, despite the destructor is specified.
105  */
106  template <class IDTYPE>
107  class G4PVPlacementWithID : public G4PVPlacement {
108  public:
109  typedef IDTYPE ID_t;
110 
111  ID_t ID; ///< Physical Volume identificator
112 
113  /// Constructor
114  G4PVPlacementWithID(const G4Transform3D& Transform3D,
115  const G4String& pName,
116  G4LogicalVolume* pLogical,
117  G4VPhysicalVolume* pMother,
118  G4bool pMany,
119  G4int pCopyNo,
120  G4bool pSurfChk = false,
121  ID_t id = ID_t())
122  : G4PVPlacement(Transform3D, pName, pLogical, pMother, pMany, pCopyNo, pSurfChk), ID(id)
123  {}
124 
125  /// Virtual destructor: does nothing more
126  virtual ~G4PVPlacementWithID() {}
127  }; // G4PVPlacementWithID<>
128 
129  /// A physical volume with a TPC ID
131 
132  /**
133  * @brief Transports energy depositions from GEANT4 to TPC channels.
134  *
135  * This class acts on single energy depositions from GEANT4, simulating the
136  * transportation of the ensuing ionisation electrons to the readout channels:
137  *
138  * 1. the number of ionisation electrons is read from the current
139  * `larg4::IonizationAndScintillation` instance
140  * 2. space charge displacement is optionally applied
141  * 3. lifetime correction is applied
142  * 4. charge is split in small electron clusters
143  * 5. each cluster is subject to longitudinal and transverse diffusion
144  * 6. each cluster is assigned to one TPC channel for each wire plane
145  * 7. optionally, charge is forced to stay on the planes; otherwise charge
146  * drifting outside the plane is lost
147  *
148  * For each energy deposition, entries on the appropriate `sim::SimChannel`
149  * are added, with the information of the position where the energy deposit
150  * happened (in global coordinates, centimeters), the ID of the Geant4
151  * track which produced the deposition, and the quantized time of arrival to
152  * the channel (in global TDC tick units).
153  * At most one entry is added for each electron cluster, but entries from the
154  * same energy deposit can be compacted if falling on the same TDC tick.
155  *
156  * The main entry point of this class is the method `ProcessHits()`.
157  *
158  * Options
159  * --------
160  *
161  * A few optional behaviours are supported:
162  *
163  * * lead off-plane charge to the planes: regulated by
164  * `RecoverOffPlaneDeposit()`, if charge which reaches a wire plane
165  * is actually off it by less than the chosen margin, it's accounted for by
166  * that plane; by default the margin is 0 and all the charge off the plane
167  * is lost (with a warning)
168  *
169  */
170  class LArVoxelReadout : public G4VSensitiveDetector {
171  public:
172  /// Type of map channel -> sim::SimChannel
173  typedef std::map<unsigned int, sim::SimChannel> ChannelMap_t;
174 
175  /// Collection of what it takes to set a `LArVoxelReadout` up.
176  struct Setup_t {
177 
178  /// Random engine for charge propagation.
179  CLHEP::HepRandomEngine* propGen = nullptr;
180 
181  /// Margin for charge recovery (see `LArVoxelReadout`).
182  double offPlaneMargin = 0.0;
183  }; // struct Setup_t
184 
185  /// Constructor. Can detect which TPC to cover by the name
187 
188  /// Constructor. Sets which TPC to work on
189  LArVoxelReadout(std::string const& name, unsigned int cryostat, unsigned int tpc);
190 
191  /// Reads all the configuration elements from `setupData`
192  void Setup(Setup_t const& setupData);
193 
194  /// Associates this readout to one specific TPC
195  void SetSingleTPC(unsigned int cryostat, unsigned int tpc);
196 
197  /// Sets this readout to discover the TPC of each processed hit
198  void SetDiscoverTPC();
199 
200  // Required for classes that inherit from G4VSensitiveDetector.
201  //
202  // Called at start and end of each event.
203  virtual void Initialize(G4HCofThisEvent*);
204  virtual void EndOfEvent(G4HCofThisEvent*);
205 
206  // Called to clear any accumulated information.
207  virtual void clear();
208 
209  // The key method of this class. It's called by Geant4 for each
210  // step within the read-out geometry. It accumulates the energy
211  // in the G4Step in the LArVoxelList.
212  virtual G4bool ProcessHits(G4Step*, G4TouchableHistory*);
213 
214  // Empty methods; they have to be defined, but they're rarely
215  // used in Geant4 applications.
216  virtual void DrawAll();
217  virtual void PrintAll();
218 
219  // Independent method; clears the vector of SimChannels as well as the
220  // channel number to SimChannel map. Has to be separate from the
221  // clear method above because that run is run for every G4 event, ie
222  // each MCTruth in the art::Event, while we want to only run this at
223  // the end of the G4 processing for each art::Event.
224  void ClearSimChannels();
225 
226  /// Creates a list with the accumulated information for the single TPC
227  std::vector<sim::SimChannel> GetSimChannels() const;
228 
229  /// Creates a list with the accumulated information for specified TPC
230  std::vector<sim::SimChannel> GetSimChannels(unsigned short cryo, unsigned short tpc) const;
231 
232  //@{
233  /// Returns the accumulated channel -> SimChannel map for the single TPC
234  const ChannelMap_t& GetSimChannelMap() const;
235  ChannelMap_t& GetSimChannelMap();
236  //@}
237 
238  //@{
239  /// Returns the accumulated channel -> SimChannel map for the specified TPC
240  const ChannelMap_t& GetSimChannelMap(unsigned short cryo, unsigned short tpc) const;
241  ChannelMap_t& GetSimChannelMap(unsigned short cryo, unsigned short tpc);
242  //@}
243 
244  private:
245  // N.B. This code is not thread-safe, as it presupposes that there
246  // is a "current" clock-data object. Such a pattern should be
247  // avoided for the users of larg4.
249 
250  void
251  SetClockData(detinfo::DetectorClocksData const* const clockData) noexcept
252  {
253  fClockData = clockData;
254  }
255 
256  void
257  SetPropertiesData(detinfo::DetectorPropertiesData const* const detProp) noexcept
258  {
259  fDetProp = detProp;
260  }
261 
262  /**
263  * @brief Sets the margin for recovery of charge drifted off-plane.
264  * @param margin the extent of the margin on each frame coordinate [cm]
265  *
266  * This method sets the margin for the recovery of off-plane ionization
267  * charge. See `RecoverOffPlaneDeposit()` for a description of that feature.
268  *
269  * This method is used by `LArVoxelReadout::Setup()`.
270  */
271  void
273  {
274  fOffPlaneMargin = std::max(margin, 0.0);
275  }
276 
277  /// Sets the random generators to be used.
278  void SetRandomEngines(CLHEP::HepRandomEngine* pPropGen);
279 
280  /**
281  * @brief Returns the point on the specified plane closest to position.
282  * @param pos the position to be tested (global coordinates, centimeters)
283  * @param plane the plane to test the position against
284  * @return a position on plane, unless pos is too far from it
285  *
286  * This method considers the distance of the position `pos` from the active
287  * part of the `plane` (see `geo::Plane::DeltaFromActivePlane()`).
288  * If the position is less than a configurable margin far from the plane,
289  * the closest point on the plane to that position is returned. Otherwise,
290  * the position itself is returned.
291  *
292  * Ionization charge may be drifted so that when it arrives to the plane, it
293  * actually does not hit the area covered by wires. This can happen for many
294  * reasons:
295  * * space charge distortion led the point outside the fiducial volume
296  * (this may be prevented by specific code)
297  * * diffusion pushes the charge outside the instrumented region
298  * * the geometry of the wire planes is such that planes have different
299  * coverage and what one plane can cover, the next can't
300  *
301  * The "recovery" consists in forcing the charge to the instrumented area
302  * covered by the plane wires.
303  * The distance of the drifted charge from each plane border is computed and
304  * compared to the margin. If that distance is smaller than the margin, it
305  * is neglected and the charge is assigned a new position on that border.
306  *
307  * This method provides the position that should be used for the charge
308  * deposition.
309  *
310  * This is a simplistic approach to the simulation of border effects,
311  * assuming that in fact the electric field, which is continuous and
312  * pointing to the collection wires, will drive the charge to the wires even
313  * when they are "off track".
314  * No correction is applied for the additional time that such deviation
315  * would take.
316  *
317  */
318  geo::Point_t RecoverOffPlaneDeposit(geo::Point_t const& pos, geo::PlaneGeo const& plane) const;
319 
320  void DriftIonizationElectrons(detinfo::DetectorClocksData const& clockData,
321  G4ThreeVector stepMidPoint,
322  const double simTime,
323  int trackID,
324  unsigned short int cryostat,
325  unsigned short int tpc);
326 
327  bool
328  Has(std::vector<unsigned short int> v, unsigned short int tpc) const
329  {
330  for (auto c : v)
331  if (c == tpc) return true;
332  return false;
333  }
334 
335  // Used in electron-cluster calculations
336  // External parameters for the electron-cluster calculation.
337  // obtained from LArG4Parameters, LArProperties, and DetectorProperties services
338  double fDriftVelocity[3];
345  std::vector<unsigned short int> fSkipWireSignalInTPCs;
346  /// Charge deposited within this many [cm] from the plane is lead onto it.
347  double fOffPlaneMargin = 0.0;
348 
349  std::vector<std::vector<ChannelMap_t>> fChannelMaps; ///< Maps of cryostat, tpc to channel data
350  art::ServiceHandle<geo::Geometry const> fGeoHandle; ///< Handle to the Geometry service
352  fLgpHandle; ///< Handle to the LArG4 parameters service
353  unsigned int fTPC; ///< which TPC this LArVoxelReadout corresponds to
354  unsigned int fCstat; ///< and in which cryostat (if bSingleTPC is true)
355  bool bSingleTPC; ///< true if this readout is associated with a single TPC
356 
357  CLHEP::HepRandomEngine* fPropGen = nullptr; ///< random engine for charge propagation
358 
359  detinfo::DetectorClocksData const* fClockData{nullptr};
360  detinfo::DetectorPropertiesData const* fDetProp{nullptr};
361 
362  //these are the things for doing the separated EDeps
363  void ProcessStep(G4Step*);
364 
365  G4ThreeVector fStepStart;
366  G4ThreeVector fStepEnd;
367  size_t fNSteps;
368  };
369 
370 }
371 
372 #endif // LArG4_LArVoxelReadout_h
static QCString name
Definition: declinfo.cpp:673
void PrintAll(detinfo::DetectorPropertiesData const &detProp, std::string someText)
Definition: Utils.cxx:5519
Store parameters for running LArG4.
unsigned int fTPC
which TPC this LArVoxelReadout corresponds to
Collection of what it takes to set a LArVoxelReadout up.
A G4PVPlacement with an additional identificator.
art::ServiceHandle< sim::LArG4Parameters const > fLgpHandle
Handle to the LArG4 parameters service.
std::string string
Definition: nybbler.cc:12
art::ServiceHandle< geo::Geometry const > fGeoHandle
Handle to the Geometry service.
Geant4 interface.
unsigned short int Cryostat
art framework interface to geometry description
bool bSingleTPC
true if this readout is associated with a single TPC
ID_t ID
Physical Volume identificator.
bool operator<(ProductInfo const &a, ProductInfo const &b)
Definition: ProductInfo.cc:51
std::map< unsigned int, sim::SimChannel > ChannelMap_t
Type of map channel -> sim::SimChannel.
std::vector< unsigned short int > fSkipWireSignalInTPCs
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:82
void Initialize(void)
G4PVPlacementWithID< TPCID_t > G4PVPlacementInTPC
A physical volume with a TPC ID.
General LArSoft Utilities.
static int max(int a, int b)
bool Has(std::vector< unsigned short int > v, unsigned short int tpc) const
std::vector< std::vector< ChannelMap_t > > fChannelMaps
Maps of cryostat, tpc to channel data.
Simple structure holding a TPC and cryostat number.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:184
virtual ~G4PVPlacementWithID()
Virtual destructor: does nothing more.
void SetClockData(detinfo::DetectorClocksData const *const clockData) noexcept
Contains all timing reference information for the detector.
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.
G4PVPlacementWithID(const G4Transform3D &Transform3D, const G4String &pName, G4LogicalVolume *pLogical, G4VPhysicalVolume *pMother, G4bool pMany, G4int pCopyNo, G4bool pSurfChk=false, ID_t id=ID_t())
Constructor.
Definitions of geometry vector data types.
Transports energy depositions from GEANT4 to TPC channels.
vector< vector< double > > clear
unsigned short int TPC
void SetPropertiesData(detinfo::DetectorPropertiesData const *const detProp) noexcept