All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MagDriftAna_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // MagDriftAna class
4 //
5 // dmckee@phys.ksu.edu
6 //
7 ////////////////////////////////////////////////////////////////////////
8 
9 // C++ std library includes
10 #include <algorithm>
11 #include <string>
12 
13 // Framework includes
14 #include "art/Framework/Core/EDAnalyzer.h"
15 #include "art/Framework/Core/ModuleMacros.h"
16 #include "art/Framework/Principal/Event.h"
17 #include "art/Framework/Principal/Handle.h"
18 #include "art/Framework/Services/Registry/ServiceHandle.h"
19 #include "art_root_io/TFileService.h"
20 #include "canvas/Persistency/Common/Ptr.h"
21 #include "fhiclcpp/ParameterSet.h"
22 #include "messagefacility/MessageLogger/MessageLogger.h"
23 
24 // Root Includes
25 #include "TH2.h"
26 #include "TLine.h"
27 
28 // LArSoft includes
37 #include "nug4/MagneticFieldServices/MagneticFieldService.h"
38 
39 /// Detector simulation of raw signals on wires
40 namespace hit {
41 
42  /// Base class for creation of raw signals on wires.
43  class MagDriftAna : public art::EDAnalyzer {
44  public:
45  explicit MagDriftAna(fhicl::ParameterSet const& pset);
46 
47  private:
48  void analyze(const art::Event& evt) override;
49  void endJob() override;
50 
51  // intilize the histograms
52  //
53  // Can't be done in Begin job because I want to use LArProperties
54  // which used the database, so I test and run on each
55  // event. Wasteful and silly, but at least it *works*.
56  void ensureHists(art::Event const& evt, detinfo::DetectorClocksData const& clockData);
57 
59  std::string fLArG4ModuleLabel;
60 
61  // Flag for initialization done, because we set up histograms the
62  // first time through beginRun() so that we can use the
63  // database...
64  bool initDone{false};
65 
66  // Drift properties
67  double fDirCosY{0.};
68  double fDirCosZ{0.};
69 
70  TH1D* fChargeXpos{nullptr}; // << position of the MC Truth charge deposition
71  TH1D* fChargeYpos{nullptr};
72  TH1D* fChargeZpos{nullptr};
73  TH1D* fHitZpos{nullptr}; // << Z position of the recorded hit (from the
74  // z-sensitive wire)
75 
76  TH1D* fDriftDeltaZ{nullptr}; // << Difference in MC charge Z and recorded hit Z
77  TH1D* fDeltaZoverX{nullptr}; // << Delta Z as a function of drift distance
78  TH2D* fDeltaZvsX{nullptr};
79 
80  // Same as above, but only for long drift distances (greater than
81  // 4/5 of the detector)
82  TH1D* fDriftDeltaZAway{nullptr}; // << Difference in MC charge Z and recorded hit Z
83  TH1D* fDeltaZoverXAway{nullptr}; // << Delta Z as a function of drift distance
84 
85  }; // class MagdriftAna
86 
87  //-------------------------------------------------
88  MagDriftAna::MagDriftAna(fhicl::ParameterSet const& pset)
89  : EDAnalyzer(pset)
90  , fFFTHitFinderModuleLabel{pset.get<std::string>("HitsModuleLabel")}
91  , fLArG4ModuleLabel{pset.get<std::string>("LArGeantModuleLabel")}
92  {}
93 
94  //-------------------------------------------------
95  void
96  MagDriftAna::ensureHists(art::Event const& evt, detinfo::DetectorClocksData const& clockData)
97  {
98  if (initDone) return; // Bail if we've already done this.
99  initDone = true; // Insure that we bail later on
100 
101  art::ServiceHandle<art::TFileService const> tfs;
102 
103  // Find magnetic field related corrections
104  auto const detProp =
105  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt, clockData);
106 
107  // art::ServiceHandle<mag::MagneticField const> MagField;
108  art::ServiceHandle<mag::MagneticFieldService const> MagFieldHandle;
109  auto const* MagField = MagFieldHandle->provider();
110  double Efield = detProp.Efield();
111  double Temperature = detProp.Temperature();
112  double DriftVelocity = detProp.DriftVelocity(Efield, Temperature) / 1000.;
113 
114  // MagneticField::FieldAtPoint() returns (0, 0, 0) if there is no
115  // field at the requested point, so these direction cosines are
116  // 0 if there is no field
117  fDirCosY = -DriftVelocity * MagField->FieldAtPoint().z() / Efield;
118  fDirCosZ = +DriftVelocity * MagField->FieldAtPoint().y() / Efield;
119  MF_LOG_VERBATIM("MagDriftAna") << "Drift ratios: "
120  << "dY/dX = " << fDirCosY << ", "
121  << "dZ/dX = " << fDirCosZ;
122 
123  // geometry data.
124  art::ServiceHandle<geo::Geometry const> geom;
125  // assumes all TPCs are the same
126  double width = 2 * geom->TPC(0).HalfWidth();
127  double halfHeight = geom->TPC(0).HalfHeight();
128  double length = geom->TPC(0).Length();
129 
130  double zScale = std::max(fDirCosZ / 2.0, 4e-4);
131 
132  // Assumes microboone dimensions. Ideally we'd fix this later...
133  fChargeXpos =
134  tfs->make<TH1D>("hChargeXpos", "MC X charge depositions; X (cm); Events", 101, 0.0, width);
135  fChargeYpos = tfs->make<TH1D>(
136  "hChargeYpos", "MC Y charge depositions; Y (cm); Events", 101, -halfHeight, halfHeight);
137  fChargeZpos =
138  tfs->make<TH1D>("hChargeZpos", "MC Z charge depositions; Z (cm); Events", 101, 0.0, length);
139  fHitZpos = tfs->make<TH1D>("hHitZpos", "Z charge collection; Z (cm); Events", 101, 0.0, length);
140 
141  fDriftDeltaZ = tfs->make<TH1D>("hDriftDeltaZ",
142  "Z drift of charge; delta Z (cm); Events",
143  101,
144  -5 * zScale * width,
145  5 * zScale * width);
146  fDeltaZoverX = tfs->make<TH1D>(
147  "hDeltaZoverX", "Z drift of charge; delta Z/X; Events", 51, -10 * zScale, 10 * zScale);
148  fDeltaZvsX = tfs->make<TH2D>("hDeltaZvsX",
149  "delta Z vs X; X (cm); delta Z (cm), Events",
150  51,
151  0.0,
152  width,
153  51,
154  -20 * zScale,
155  20 * zScale);
156 
157  // Some stats only when the Xdrift is large (more than 3/4)
158  fDriftDeltaZAway = tfs->make<TH1D>("hDriftDeltaZAway",
159  "Z drift of charge (long drift); delta Z (cm); Events",
160  101,
161  -5 * zScale * width,
162  5 * zScale * width);
163  fDeltaZoverXAway = tfs->make<TH1D>("hDeltaZoverXAway",
164  "Z drift of charge (long drift); delta Z/X; Events",
165  51,
166  -10 * zScale,
167  10 * zScale);
168  }
169 
170  //-------------------------------------------------
171  void
173  {
174  // Add a line on the deltaZ/X graph to denote the calculated value
175  // of the drift ration
176  TLine* l = new TLine(fDirCosZ, 0, fDirCosZ, 1.05 * fDeltaZoverX->GetMaximum());
177  l->SetLineColor(kRed);
178  l->SetLineStyle(kDotted);
179  fDeltaZoverX->GetListOfFunctions()->Add(l);
180 
181  // I know this looks like a memory leak, but each historgram needs
182  // it's own copy of the line to prevent double freeing by the
183  // framework...
184  l = new TLine(fDirCosZ, 0, fDirCosZ, 1.05 * fDeltaZoverX->GetMaximum());
185 
186  l->SetLineColor(kRed);
187  l->SetLineStyle(kDotted);
188  fDeltaZoverXAway->GetListOfFunctions()->Add(l);
189  }
190 
191  //-------------------------------------------------
192  void
193  MagDriftAna::analyze(const art::Event& evt)
194  {
195  if (evt.isRealData()) {
196  throw cet::exception("MagDriftAna: ") << "Not for use on Data yet...\n";
197  }
198 
199  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
200 
201  ensureHists(evt, clockData);
202 
203  art::Handle<std::vector<recob::Hit>> hitHandle;
204  evt.getByLabel(fFFTHitFinderModuleLabel, hitHandle);
205 
206  art::ServiceHandle<geo::Geometry const> geom;
207 
208  // We're going to want to compare the reconstructed Z with the
209  // simulted Z. For that purpose we use the simultion backtracking.
210 
211  art::ServiceHandle<cheat::BackTrackerService const> bt_serv;
212 
213  std::vector<art::Ptr<recob::Hit>> hits;
214  art::fill_ptr_vector(hits, hitHandle);
215 
216  geo::WireID hitWireID;
217 
218  //++++++++++
219  // Loop over the hits (data) and fill histos
220  //++++++++++
221  for (auto itr : hits) {
222 
223  hitWireID = itr->WireID();
224  // By assumption the drift occurs only in the z-direction, so
225  // we can get all the info we need from the z-measug plane.
226  if (hitWireID.Plane != (geom->Nplanes() - 1)) continue;
227 
228  // Charge collected at the wire
229  //
230  // Exactly once for each recob::Hit
231  double w0pos[3] = {0.};
232  geom->TPC(hitWireID.TPC).Plane(hitWireID.Plane).Wire(0).GetCenter(w0pos);
233  double HitZpos = w0pos[2] + hitWireID.Wire * geom->TPC(hitWireID.TPC).WirePitch();
234  double Charge = itr->Integral();
235  fHitZpos->Fill(HitZpos, Charge);
236 
237  // Charge deposition in the detector
238  std::vector<double> xyz = bt_serv->HitToXYZ(clockData, itr);
239  fChargeXpos->Fill(xyz[0], Charge);
240  fChargeYpos->Fill(xyz[1], Charge);
241  double ChargeZpos = xyz[2];
242  fChargeZpos->Fill(ChargeZpos, Charge);
243 
244  // Delta-Z
245  //
246  // Compares the collected z position from the wire to the
247  // simulated z position
248  double DeltaZ = HitZpos - ChargeZpos;
249  fDriftDeltaZ->Fill(DeltaZ, Charge);
250  // Delta Z correlation with X
251  fDeltaZoverX->Fill(DeltaZ / xyz[0], Charge);
252  fDeltaZvsX->Fill(xyz[0], DeltaZ, Charge);
253  // The X related histograms know the dimensions of the
254  // detector, so we use them to set the "away" limit
255  if (xyz[0] > (fChargeYpos->GetXaxis()->GetXmax() * 0.80)) {
256  fDriftDeltaZAway->Fill(DeltaZ, Charge);
257  fDeltaZoverXAway->Fill(DeltaZ / xyz[0], Charge);
258  }
259 
260  } // loop on Hits
261 
262  return;
263  } // end analyze method
264 
265  DEFINE_ART_MODULE(MagDriftAna)
266 
267 } // end of hit namespace
void analyze(const art::Event &evt) override
Declaration of signal hit object.
std::string fLArG4ModuleLabel
std::string fFFTHitFinderModuleLabel
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
process_name hit
Definition: cheaterreco.fcl:51
float Efield
Definition: dedx.py:126
Base class for creation of raw signals on wires.
void endJob() override
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
MagDriftAna(fhicl::ParameterSet const &pset)
Encapsulate the geometry of a wire.
void ensureHists(art::Event const &evt, detinfo::DetectorClocksData const &clockData)
Encapsulate the construction of a single detector plane.
Contains all timing reference information for the detector.
do i e
constexpr WireID()=default
Default constructor: an invalid TPC ID.
art::ServiceHandle< art::TFileService > tfs
TCEvent evt
Definition: DataStructs.cxx:8
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
art framework interface to geometry description
auto const detProp
Encapsulate the construction of a single detector plane.