All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DetectorPropertiesStandard.cxx
Go to the documentation of this file.
1 /**
2  * @file lardataalg/DetectorInfo/DetectorPropertiesStandard.cxx
3  * @brief Separation of service from Detector info class.
4  * @author Jonathan Paley (jpaley@fnal.gov)
5  */
6 
7 // Framework includes
8 
9 // LArSoft includes
11 #include "larcorealg/CoreUtils/ProviderUtil.h" // lar::IgnorableProviderConfigKeys()
16 
17 #include "cetlib/pow.h"
18 #include "messagefacility/MessageLogger/MessageLogger.h"
19 
20 // Art includes
21 #include "fhiclcpp/types/Table.h"
22 
23 // C/C++ libraries
24 #include <sstream> // std::ostringstream
25 
26 namespace detinfo {
27 
28  //--------------------------------------------------------------------
30  const geo::GeometryCore* geo,
31  const detinfo::LArProperties* lp,
32  std::set<std::string> const& ignore_params)
33  : fLP(lp), fGeo(geo)
34  {
35  ValidateAndConfigure(pset, ignore_params);
36  }
37 
38  //--------------------------------------------------------------------
39  void
41  std::set<std::string> const& ignore_params)
42  {
43  {
44  mf::LogInfo debug("setupProvider<DetectorPropertiesStandard>");
45 
46  debug << "Asked to ignore " << ignore_params.size() << " keys:";
47  for (auto const& key : ignore_params)
48  debug << " '" << key << "'";
49  }
50 
51  std::set<std::string> ignorable_keys = lar::IgnorableProviderConfigKeys();
52  ignorable_keys.insert(ignore_params.begin(), ignore_params.end());
53 
54  // parses and validates the parameter set:
55  fhicl::Table<Configuration_t> const config{p, ignorable_keys};
56 
57  fEfield = config().Efield();
58  fElectronlifetime = config().Electronlifetime();
59  fTemperature = config().Temperature();
60  fElectronsToADC = config().ElectronsToADC();
61  fNumberTimeSamples = config().NumberTimeSamples();
62  fReadOutWindowSize = config().ReadOutWindowSize();
63 
64  std::set<geo::View_t> present_views;
65  if (config().TimeOffsetU(fTimeOffsetU)) present_views.insert(geo::kU);
66  if (config().TimeOffsetV(fTimeOffsetV)) present_views.insert(geo::kV);
67  if (config().TimeOffsetZ(fTimeOffsetZ)) present_views.insert(geo::kZ);
68  if (config().TimeOffsetY(fTimeOffsetY)) present_views.insert(geo::kY);
69  if (config().TimeOffsetX(fTimeOffsetX)) present_views.insert(geo::kX);
70 
71  std::string const errors = CheckTimeOffsets(present_views);
72  if (!errors.empty()) {
73  throw cet::exception("DetectorPropertiesStandard") << "Detected configuration errors: \n"
74  << errors;
75  }
76 
77  fSternheimerParameters.a = config().SternheimerA();
78  fSternheimerParameters.k = config().SternheimerK();
79  fSternheimerParameters.x0 = config().SternheimerX0();
80  fSternheimerParameters.x1 = config().SternheimerX1();
81  fSternheimerParameters.cbar = config().SternheimerCbar();
82 
83  fDriftVelFudgeFactor = config().DriftVelFudgeFactor();
84 
85  fUseIcarusMicrobooneDriftModel = config().UseIcarusMicrobooneDriftModel();
86 
87  fIncludeInterPlanePitchInXTickOffsets = config().IncludeInterPlanePitchInXTickOffsets();
88 
89  fSimpleBoundary = config().SimpleBoundary();
90 
91  fModBoxA = config().ModBoxAlpha();
92  fModBoxB = config().ModBoxBeta();
93  }
94 
95  //------------------------------------------------------------------------------------//
96  double
97  DetectorPropertiesStandard::Efield(unsigned int const planegap) const
98  {
99  if (planegap >= fEfield.size())
100  throw cet::exception("DetectorPropertiesStandard")
101  << "requesting Electric field in a plane gap that is not defined\n";
102 
103  return fEfield[planegap];
104  }
105 
106  //------------------------------------------------
107  double
108  DetectorPropertiesStandard::Density(double temperature) const
109  {
110  // Default temperature use internal value.
111  if (temperature == 0.) temperature = Temperature();
112 
113  return -0.00615 * temperature + 1.928;
114  }
115 
116  //----------------------------------------------------------------------------------
117  // Restricted mean energy loss (dE/dx) in units of MeV/cm.
118  //
119  // For unrestricted mean energy loss, set tcut = 0, or tcut large.
120  //
121  // Arguments:
122  //
123  // mom - Momentum of incident particle in GeV/c.
124  // mass - Mass of incident particle in GeV/c^2.
125  // tcut - Maximum kinetic energy of delta rays (MeV).
126  //
127  // Returned value is positive.
128  //
129  // Based on Bethe-Bloch formula as contained in particle data book.
130  // Material parameters (stored in larproperties.fcl) are taken from
131  // pdg web site http://pdg.lbl.gov/AtomicNuclearProperties/
132  //
133  double
134  DetectorPropertiesStandard::Eloss(double mom, double mass, double tcut) const
135  {
136  // Some constants.
137  constexpr double K = 0.307075; // 4 pi N_A r_e^2 m_e c^2 (MeV cm^2/mol).
138  constexpr double me = 0.510998918; // Electron mass (MeV/c^2).
139 
140  // Calculate kinematic quantities.
141  double const bg = mom / mass; // beta*gamma.
142  double const gamma = sqrt(1. + bg * bg); // gamma.
143  double const beta = bg / gamma; // beta (velocity).
144  double const mer = 0.001 * me / mass; // electron mass / mass of incident particle.
145  double const tmax =
146  2. * me * bg * bg / (1. + 2. * gamma * mer + mer * mer); // Maximum delta ray energy (MeV).
147 
148  // Make sure tcut does not exceed tmax.
149  if (tcut == 0. || tcut > tmax) tcut = tmax;
150 
151  // Calculate density effect correction (delta).
152  double const x = std::log10(bg);
153  double delta = 0.;
154  if (x >= fSternheimerParameters.x0) {
155  delta = 2. * std::log(10.) * x - fSternheimerParameters.cbar;
156  if (x < fSternheimerParameters.x1)
157  delta += fSternheimerParameters.a *
159  }
160 
161  // Calculate stopping number.
162  double B =
163  0.5 * std::log(2. * me * bg * bg * tcut / (1.e-12 * cet::square(fLP->ExcitationEnergy()))) -
164  0.5 * beta * beta * (1. + tcut / tmax) - 0.5 * delta;
165 
166  // Don't let the stopping number become negative.
167  if (B < 1.) B = 1.;
168 
169  // Calculate dE/dx.
170  return Density() * K * fLP->AtomicNumber() * B / (fLP->AtomicMass() * beta * beta);
171  }
172 
173  //----------------------------------------------------------------------------------
174  double
175  DetectorPropertiesStandard::ElossVar(double const mom, double const mass) const
176  {
177  // Some constants.
178  constexpr double K = 0.307075; // 4 pi N_A r_e^2 m_e c^2 (MeV cm^2/mol).
179  constexpr double me = 0.510998918; // Electron mass (MeV/c^2).
180 
181  // Calculate kinematic quantities.
182  double const bg = mom / mass; // beta*gamma.
183  double const gamma2 = 1. + bg * bg; // gamma^2.
184  double const beta2 = bg * bg / gamma2; // beta^2.
185  return gamma2 * (1. - 0.5 * beta2) * me * (fLP->AtomicNumber() / fLP->AtomicMass()) * K *
186  Density();
187  }
188 
189  //------------------------------------------------------------------------------------//
190  double
191  DetectorPropertiesStandard::DriftVelocity(double efield, double temperature) const
192  {
193  // Drift Velocity as a function of Electric Field and LAr Temperature
194  // from : W. Walkowiak, NIM A 449 (2000) 288-294
195  //
196  // Option to use MicroBooNE+ICARUS model (as in arXiv:2008.09765) provided as
197  // well, with temperature depenence as prescribed by Mike Mooney based on
198  // looking at the Walkowiak data.
199  //
200  // Efield should have units of kV/cm
201  // Temperature should have units of Kelvin
202 
203  // Default Efield, use internal value.
204  if (efield == 0.) efield = Efield();
205 
206  if (efield > 4.0)
207  mf::LogWarning("DetectorPropertiesStandard")
208  << "DriftVelocity Warning! : E-field value of " << efield
209  << " kV/cm is outside of range covered by drift"
210  << " velocity parameterization. Returned value"
211  << " may not be correct";
212 
213  // Default temperature use internal value.
214  if (temperature == 0.) temperature = Temperature();
215 
216  if (temperature < 87.0 || temperature > 94.0)
217  mf::LogWarning("DetectorPropertiesStandard")
218  << "DriftVelocity Warning! : Temperature value of " << temperature
219  << " K is outside of range covered by drift velocity"
220  << " parameterization. Returned value may not be"
221  << " correct";
222 
223  double vd;
224 
226  double const tshift = -87.203 + temperature;
227  double const xFit = 0.0938163 - 0.0052563 * tshift - 0.0001470 * tshift * tshift;
228  double const uFit = 5.18406 + 0.01448 * tshift - 0.003497 * tshift * tshift -
229  0.000516 * tshift * tshift * tshift;
230 
231  // Icarus Parameter Set, use as default
232  constexpr double P1 = -0.04640; // K^-1
233  constexpr double P2 = 0.01712; // K^-1
234  constexpr double P3 = 1.88125; // (kV/cm)^-1
235  constexpr double P4 = 0.99408; // kV/cm
236  constexpr double P5 = 0.01172; // (kV/cm)^-P6
237  constexpr double P6 = 4.20214;
238  constexpr double T0 = 105.749; // K
239 
240  // Walkowiak Parameter Set
241  constexpr double P1W = -0.01481; // K^-1
242  constexpr double P2W = -0.0075; // K^-1
243  constexpr double P3W = 0.141; // (kV/cm)^-1
244  constexpr double P4W = 12.4; // kV/cm
245  constexpr double P5W = 1.627; // (kV/cm)^-P6
246  constexpr double P6W = 0.317;
247  constexpr double T0W = 90.371; // K
248 
249  // From Craig Thorne . . . currently not documented
250  // smooth transition from linear at small fields to
251  // icarus fit at most fields to Walkowiak at very high fields
252  if (efield < xFit)
253  vd = efield * uFit;
254  else if (efield < 0.619) {
255  vd = ((P1 * (temperature - T0) + 1) *
256  (P3 * efield * std::log(1 + P4 / efield) + P5 * std::pow(efield, P6)) +
257  P2 * (temperature - T0));
258  }
259  else if (efield < 0.699) {
260  vd = 12.5 * (efield - 0.619) *
261  ((P1W * (temperature - T0W) + 1) *
262  (P3W * efield * std::log(1 + P4W / efield) + P5W * std::pow(efield, P6W)) +
263  P2W * (temperature - T0W)) +
264  12.5 * (0.699 - efield) *
265  ((P1 * (temperature - T0) + 1) *
266  (P3 * efield * std::log(1 + P4 / efield) + P5 * std::pow(efield, P6)) +
267  P2 * (temperature - T0));
268  }
269  else {
270  vd = ((P1W * (temperature - T0W) + 1) *
271  (P3W * efield * std::log(1 + P4W / efield) + P5W * std::pow(efield, P6W)) +
272  P2W * (temperature - T0W));
273  }
274  }
275 
276  // MicroBooNE+ICARUS model (arXiv:2008.09765) with temperature dependence given by
277  // Mike Mooney based on looking at Walkowiak data (NIM A 449 (2000) 288-294)
279  constexpr double P0 = 0.;
280  constexpr double P1 = 5.53416;
281  constexpr double P2 = -6.53093;
282  constexpr double P3 = 3.20752;
283  constexpr double P4 = 0.389696;
284  constexpr double P5 = -0.556184;
285  vd = (1.0 - 0.0184 * (temperature - 89.0)) *
286  (P0 + P1 * cet::pow<1>(efield) + P2 * cet::pow<2>(efield) + P3 * cet::pow<3>(efield) +
287  P4 * cet::pow<4>(efield) + P5 * cet::pow<5>(efield));
288  }
289 
290  vd *= fDriftVelFudgeFactor / 10.;
291 
292  return vd; // in cm/us
293  }
294 
295  //----------------------------------------------------------------------------------
296  // The below function assumes that the user has applied the lifetime
297  // correction and effective pitch between the wires (usually after 3D
298  // reconstruction). Using with mean wire pitch will not give correct results.
299  // parameters:
300  // dQdX in electrons/cm, charge (amplitude or integral obtained) divided by
301  // effective pitch for a given 3D track.
302  // Electric Field in the drift region in KV/cm/
303  // returns dEdX in MeV/cm
304  double
306  {
307  return BirksCorrection(dQdx, Efield());
308  }
309  double
310  DetectorPropertiesStandard::BirksCorrection(double dQdx, double E_field) const
311  {
312  // Correction for charge quenching using parameterization from
313  // S.Amoruso et al., NIM A 523 (2004) 275
314 
315  constexpr double A3t = util::kRecombA;
316  double K3t = util::kRecombk; // in KV/cm*(g/cm^2)/MeV
317  double const rho = Density(); // LAr density in g/cm^3
318  constexpr double Wion = 1000. / util::kGeVToElectrons; // 23.6 eV = 1e, Wion in MeV/e
319  K3t /= rho; // KV/MeV
320  double const dEdx = dQdx / (A3t / Wion - K3t / E_field * dQdx); // MeV/cm
321 
322  return dEdx;
323  }
324 
325  //----------------------------------------------------------------------------------
326  // Modified Box model correction
327  double
329  {
330  return ModBoxCorrection(dQdx, Efield());
331  }
332  double
333  DetectorPropertiesStandard::ModBoxCorrection(double dQdx, double E_field) const
334  {
335  // Modified Box model correction has better behavior than the Birks
336  // correction at high values of dQ/dx.
337  double const rho = Density(); // LAr density in g/cm^3
338  constexpr double Wion = 1000. / util::kGeVToElectrons; // 23.6 eV = 1e, Wion in MeV/e
339  double const Beta = fModBoxB / (rho * E_field);
340  double const Alpha = fModBoxA;
341  double const dEdx = (exp(Beta * Wion * dQdx) - Alpha) / Beta;
342 
343  return dEdx;
344  }
345 
346  //--------------------------------------------------------------------
347  // x<--> ticks conversion methods
348  //
349  // Ben Jones April 2012,
350  // based on code by Herb Greenlee in SpacePointService
351  //
352 
353  //--------------------------------------------------------------------
354  // Recalculate x<-->ticks conversion parameters from detector constants
355 
358  {
359  double const samplingRate = sampling_rate(clock_data);
360  double const efield = Efield();
361  double const temperature = Temperature();
362  double const driftVelocity = DriftVelocity(efield, temperature);
363  double const x_ticks_coefficient = 0.001 * driftVelocity * samplingRate;
364 
365  double const triggerOffset = trigger_offset(clock_data);
366 
367  std::vector<std::vector<std::vector<double>>> x_ticks_offsets(fGeo->Ncryostats());
368  std::vector<std::vector<double>> drift_direction(fGeo->Ncryostats());
369 
370  for (size_t cstat = 0; cstat < fGeo->Ncryostats(); ++cstat) {
371  x_ticks_offsets[cstat].resize(fGeo->Cryostat(cstat).NTPC());
372  drift_direction[cstat].resize(fGeo->Cryostat(cstat).NTPC());
373 
374  for (size_t tpc = 0; tpc < fGeo->Cryostat(cstat).NTPC(); ++tpc) {
375  const geo::TPCGeo& tpcgeom = fGeo->Cryostat(cstat).TPC(tpc);
376 
377  const double dir((tpcgeom.DriftDirection() == geo::kNegX) ? +1.0 : -1.0);
378  drift_direction[cstat][tpc] = dir;
379 
380  int nplane = tpcgeom.Nplanes();
381  x_ticks_offsets[cstat][tpc].resize(nplane, 0.);
382  for (int plane = 0; plane < nplane; ++plane) {
383  const geo::PlaneGeo& pgeom = tpcgeom.Plane(plane);
384 
385  // Calculate geometric time offset.
386  // only works if xyz[0]<=0
387  const double* xyz = tpcgeom.PlaneLocation(0);
388 
389  x_ticks_offsets[cstat][tpc][plane] =
390  -xyz[0] / (dir * x_ticks_coefficient) + triggerOffset;
391 
393  // Get field in gap between planes
394  double efieldgap[3];
395  double driftVelocitygap[3];
396  double x_ticks_coefficient_gap[3];
397  for (int igap = 0; igap < 3; ++igap) {
398  efieldgap[igap] = Efield(igap);
399  driftVelocitygap[igap] = DriftVelocity(efieldgap[igap], temperature);
400  x_ticks_coefficient_gap[igap] = 0.001 * driftVelocitygap[igap] * samplingRate;
401  }
402 
403  if (nplane == 3) {
404  /*
405  | ---------- plane = 2 (collection)
406  | Coeff[2]
407  | ---------- plane = 1 (2nd induction)
408  | Coeff[1]
409  | ---------- plane = 0 (1st induction) x = xyz[0]
410  | Coeff[0]
411  | ---------- x = 0
412  V For plane = 0, t offset is -xyz[0]/Coeff[0]
413  x */
414  for (int ip = 0; ip < plane; ++ip) {
415  x_ticks_offsets[cstat][tpc][plane] +=
416  tpcgeom.PlanePitch(ip, ip + 1) / x_ticks_coefficient_gap[ip + 1];
417  }
418  }
419  else if (nplane == 2) { ///< special case for ArgoNeuT
420  /*
421  | ---------- plane = 1 (collection)
422  | Coeff[2]
423  | ---------- plane = 0 (2nd induction) x = xyz[0]
424  | ---------- x = 0, Coeff[1]
425  V ---------- first induction plane
426  x Coeff[0]
427  For plane = 0, t offset is pitch/Coeff[1] -
428  (pitch+xyz[0])/Coeff[0] = -xyz[0]/Coeff[0] -
429  pitch*(1/Coeff[0]-1/Coeff[1])
430  */
431  for (int ip = 0; ip < plane; ++ip) {
432  x_ticks_offsets[cstat][tpc][plane] +=
433  tpcgeom.PlanePitch(ip, ip + 1) / x_ticks_coefficient_gap[ip + 2];
434  }
435  x_ticks_offsets[cstat][tpc][plane] -=
436  tpcgeom.PlanePitch() * (1 / x_ticks_coefficient - 1 / x_ticks_coefficient_gap[1]);
437  }
438 
439  } // end if fIncludeInterPlanePitchInXTickOffsets
440 
441  // Add view dependent offset
442  // FIXME the offset should be plane-dependent
443  geo::View_t view = pgeom.View();
444  switch (view) {
445  case geo::kU: x_ticks_offsets[cstat][tpc][plane] += fTimeOffsetU; break;
446  case geo::kV: x_ticks_offsets[cstat][tpc][plane] += fTimeOffsetV; break;
447  case geo::kZ: x_ticks_offsets[cstat][tpc][plane] += fTimeOffsetZ; break;
448  case geo::kY: x_ticks_offsets[cstat][tpc][plane] += fTimeOffsetY; break;
449  case geo::kX: x_ticks_offsets[cstat][tpc][plane] += fTimeOffsetX; break;
450  default: throw cet::exception(__FUNCTION__) << "Bad view = " << view << "\n";
451  } // switch
452  }
453  }
454  }
455 
456  return DetectorPropertiesData{
457  *this, x_ticks_coefficient, move(x_ticks_offsets), move(drift_direction)};
458  }
459 
460  std::string
461  DetectorPropertiesStandard::CheckTimeOffsets(std::set<geo::View_t> const& requested_views) const
462  {
463  auto const& present_views = fGeo->Views();
464 
465  auto view_diff = [&present_views, &requested_views](geo::View_t const view) {
466  return static_cast<int>(present_views.count(view)) -
467  static_cast<int>(requested_views.count(view));
468  };
469 
470  // It is not an error to specify an offset if the view does not
471  // exist. However, if a view does exist, and an offset does not,
472  // then that will end the job.
473  std::ostringstream errors;
474  if (auto diff = view_diff(geo::kU); diff > 0) { errors << "TimeOffsetU missing for view U.\n"; }
475  if (auto diff = view_diff(geo::kV); diff > 0) { errors << "TimeOffsetV missing for view V.\n"; }
476  if (auto diff = view_diff(geo::kZ); diff > 0) { errors << "TimeOffsetZ missing for view Z.\n"; }
477  if (auto diff = view_diff(geo::kY); diff > 0) { errors << "TimeOffsetY missing for view Y.\n"; }
478  if (auto diff = view_diff(geo::kX); diff > 0) { errors << "TimeOffsetX missing for view X.\n"; }
479  return errors.str();
480  }
481 } // namespace
DetectorPropertiesStandard(fhicl::ParameterSet const &pset, const geo::GeometryCore *geo, const detinfo::LArProperties *lp, std::set< std::string > const &ignore_params={})
double ModBoxCorrection(double dQdX) const override
virtual double AtomicNumber() const =0
Atomic number of the liquid.
double PlanePitch(unsigned int p1=0, unsigned int p2=1) const
Definition: TPCGeo.cxx:388
Encapsulate the construction of a single cyostat.
DetectorPropertiesData DataFor(detinfo::DetectorClocksData const &clock_data) const override
process_name opflash particleana ie x
double Temperature() const override
In kelvin.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
Planes which measure V.
Definition: geo_types.h:130
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:165
double Eloss(double mom, double mass, double tcut) const override
Restricted mean energy loss (dE/dx)
void ValidateAndConfigure(fhicl::ParameterSet const &p, std::set< std::string > const &ignore_params)
Configures the provider, first validating the configuration.
std::set< geo::View_t > const & Views() const
Returns a list of possible views in the detector.
pdgs p
Definition: selectors.fcl:22
Planes which measure X direction.
Definition: geo_types.h:134
Geometry information for a single TPC.
Definition: TPCGeo.h:38
unsigned int fNumberTimeSamples
number of clock ticks per event
virtual double Density() const
Returns argon density at the temperature from Temperature()
Planes which measure Z direction.
Definition: geo_types.h:132
Drift towards negative X values.
Definition: geo_types.h:162
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
virtual double ExcitationEnergy() const =0
Mean excitation energy of the liquid (eV)
Planes which measure Y direction.
Definition: geo_types.h:133
Access the description of detector geometry.
Planes which measure U.
Definition: geo_types.h:129
View_t View() const
Which coordinate does this plane measure.
Definition: PlaneGeo.h:184
constexpr double kGeVToElectrons
23.6eV per ion pair, 1e9 eV/GeV
double ElossVar(double mom, double mass) const override
Energy loss fluctuation ( )
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:82
SternheimerParameters_t fSternheimerParameters
Sternheimer parameters.
unsigned int NTPC() const
Number of TPCs in this cryostat.
Definition: CryostatGeo.h:181
std::set< std::string > const & IgnorableProviderConfigKeys()
Returns a list of configuration keys that providers should ignore.
Definition: ProviderUtil.h:35
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
std::string CheckTimeOffsets(std::set< geo::View_t > const &requested_views) const
Description of geometry of one entire detector.
DriftDirection_t DriftDirection() const
Returns an enumerator value describing the drift direction.
Definition: TPCGeo.h:144
float dEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, TP3D &tp3d)
Definition: PFPUtils.cxx:2687
tuple dir
Definition: dropbox.py:28
double DriftVelocity(double efield=0., double temperature=0.) const override
cm/us
int Wion
Definition: dedx.py:125
Encapsulate the construction of a single detector plane.
Contains all timing reference information for the detector.
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
Definition: CryostatGeo.cxx:93
unsigned int fReadOutWindowSize
number of clock ticks per readout window
float mass
Definition: dedx.py:47
constexpr double kRecombk
double BirksCorrection(double dQdX) const override
dQ/dX in electrons/cm, returns dE/dX in MeV/cm.
do i e
int trigger_offset(DetectorClocksData const &data)
std::vector< double > fEfield
kV/cm (per inter-plane volume) !
Simple utilities for service providers.
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
Definition: TPCGeo.cxx:263
constexpr double kRecombA
A constant.
process_name physics producers generator hPHist_pi physics producers generator P0
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
const double * PlaneLocation(unsigned int p) const
Definition: TPCGeo.cxx:382
virtual double AtomicMass() const =0
Atomic mass of the liquid (g/mol)
double Efield(unsigned int planegap=0) const override
kV/cm
Encapsulate the construction of a single detector plane.
process_name opdaq physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator T0
Definition: gen_protons.fcl:45