DUNE35tonOpDetResponse_service.cc
Go to the documentation of this file.
1 // -*- mode: c++; c-basic-offset: 4; -*-
2 ////////////////////////////////////////////////////////////////////////
3 //
4 // \file DUNE35tonOpDetResponse_service.cc
5 //
6 ////////////////////////////////////////////////////////////////////////
7 
8 
11 #include "TGeoNode.h"
12 #include "TGeoBBox.h"
16 #include "CLHEP/Random/RandFlat.h"
17 #include <boost/algorithm/string.hpp>
18 
19 
20 namespace opdet{
21 
22 
23  //--------------------------------------------------------------------
25  art::ActivityRegistry &/*reg*/)
26  {
27  this->doReconfigure(pset);
28  }
29 
30  //--------------------------------------------------------------------
32  { }
33 
34 
35  //--------------------------------------------------------------------
37  {
38  double tempfQE = pset.get<double>("QuantumEfficiency");
39  fWavelengthCutLow = pset.get<double>("WavelengthCutLow");
40  fWavelengthCutHigh = pset.get<double>("WavelengthCutHigh");
41  fLightGuideAttenuation = pset.get<bool>("LightGuideAttenuation");
42  fChannelConversion = pset.get<std::string>("ChannelConversion");
43  std::string tmpAxis = pset.get<std::string>("LongAxis");
44 
45  boost::algorithm::to_lower(tmpAxis);
46 
47  if (tmpAxis == "x") fLongAxis = 0;
48  if (tmpAxis == "y") fLongAxis = 1;
49  if (tmpAxis == "z") fLongAxis = 2;
50 
51  // Only allow channel conversion once - so it must be set to happen
52  // either during full simulation (library generation) or during
53  // fast simulation (library use).
54 
55  boost::algorithm::to_lower(fChannelConversion);
56 
57  fFullSimChannelConvert = false;
58  fFastSimChannelConvert = false;
59 
60  if (fChannelConversion == "full") fFullSimChannelConvert = true;
61  if (fChannelConversion == "fast") fFastSimChannelConvert = true;
62 
63  // Correct out the prescaling applied during simulation
64  auto const *LarProp = lar::providerFrom<detinfo::LArPropertiesService>();
65  fQE = tempfQE / LarProp->ScintPreScale();
66 
67  if (fQE > 1.0001 ) {
68  mf::LogError("DUNE35tonOpDetResponse_service") << "Quantum efficiency set in OpDetResponse_service, " << tempfQE
69  << " is too large. It is larger than the prescaling applied during simulation, "
70  << LarProp->ScintPreScale()
71  << ". Final QE must be equalt to or smaller than the QE applied at simulation time.";
72  assert(false);
73  }
74 
75  }
76 
77 
78  //--------------------------------------------------------------------
80  {
83  return geom->NOpChannels();
84  else
85  return geom->NOpDets();
86 
87  }
88 
89 
90  //--------------------------------------------------------------------
91  bool DUNE35tonOpDetResponse::doDetected(int OpDet, const sim::OnePhoton& Phot, int &newOpChannel) const
92  {
93 
94  // Find the Optical Detector using the geometry service
96  const TGeoNode* node = geom->OpDetGeoFromOpDet(OpDet).Node();
97 
98  // Identify the photon detector type
99  int pdtype;
100  std::string detname = node->GetName();
101  boost::to_lower(detname);
102  if (detname.find("bar") != std::string::npos ) pdtype = 0;
103  else if (detname.find("fiber") != std::string::npos ) pdtype = 1;
104  else if (detname.find("plank") != std::string::npos ) pdtype = 2;
105  else pdtype = -1;
106 
107 
109  // Override default number of channels for Fiber and Plank
110  float NOpHardwareChannels = geom->NOpHardwareChannels(OpDet);
111  if (pdtype == 1) NOpHardwareChannels = 3;
112  if (pdtype == 2) NOpHardwareChannels = 2;
113 
114  int hardwareChannel = (int) ( CLHEP::RandFlat::shoot(1.0) * NOpHardwareChannels );
115  newOpChannel = geom->OpChannel(OpDet, hardwareChannel);
116  }
117  else{
118  newOpChannel = OpDet;
119  }
120 
121  // Check QE
122  if ( CLHEP::RandFlat::shoot(1.0) > fQE ) return false;
123 
124  double wavel = wavelength(Phot.Energy);
125  // Check wavelength acceptance
126  if (wavel < fWavelengthCutLow) return false;
127  if (wavel > fWavelengthCutHigh) return false;
128 
130  // Get the length of the photon detector
131  TGeoBBox *box = (TGeoBBox*)node->GetVolume()->GetShape();
132  double opdetHalfLength = 0;
133  double sipmDistance = 0;
134 
135  if (fLongAxis == 0) {
136  opdetHalfLength = box->GetDX();
137  sipmDistance = opdetHalfLength - Phot.FinalLocalPosition.x();
138  }
139  else if (fLongAxis == 1) {
140  opdetHalfLength = box->GetDY();
141  sipmDistance = opdetHalfLength - Phot.FinalLocalPosition.y();
142  }
143  else if (fLongAxis == 2) {
144  opdetHalfLength = box->GetDZ();
145  sipmDistance = opdetHalfLength - Phot.FinalLocalPosition.z();
146  }
147  else {
148  mf::LogError("DUNE35tonOpDetResponse") << "Unknown axis, fLongAxis = " << fLongAxis;
149  assert(false);
150  }
151 
152 
153 
154  if (pdtype == 0) {
155  double normalize = 0.6961; // Normalize mean performance to be the same in all PDs
156  double lambdaShort = 5.56; // cm
157  double lambdaLong = 44.13; // cm
158  double fracShort = 0.40 * normalize;
159  double fracLong = 0.60 * normalize;
160 
161  double AttenuationProb = fracShort*exp(-sipmDistance/lambdaShort) + fracLong*exp(-sipmDistance/lambdaLong);
162 
163  //std::cout <<"GRAPH: " << OpDet << "," << Phot.FinalLocalPosition.y() << "," << sipmDistance << "," << AttenuationProb << std::endl;
164 
165  //mf::LogVerbatim("DUNE35tonOpDetResponse") << "OpDet: " << OpDet << " is a " << pdtype
166  // << " with length " << opdetHalfLength << " in detector "
167  // << box->GetDX() << " x " << box->GetDY() << " x " << box->GetDZ()
168  // << " named " << detname;
169  //mf::LogVerbatim("DUNE35tonOpDetResponse") << " Local Position = (" << Phot.FinalLocalPosition.x()
170  // << ", " << Phot.FinalLocalPosition.y() << ", " << Phot.FinalLocalPosition.z() << ")";
171  //mf::LogVerbatim("DUNE35tonOpDetResponse") << " Distance to SiPM = " << sipmDistance << " along axis " << fLongAxis;
172  //mf::LogVerbatim("DUNE35tonOpDetResponse") << " Attenuation Probability = " << AttenuationProb;
173 
174  // Throw away some photons based on attenuation
175  if ( CLHEP::RandFlat::shoot(1.0) > AttenuationProb ) return false;
176  }
177  else if (pdtype == 1) {
178  double normalize = 1.0; // Normalize mean performance to be the same in all PDs
179  double lambda = 14.6; // cm
180 
181  // Throw away some photons based on attenuation
182  double AttenuationProb = normalize*exp(-sipmDistance/lambda);
183 
184  //std::cout <<"GRAPH: " << OpDet << "," << Phot.FinalLocalPosition.y() << "," << sipmDistance << "," << AttenuationProb << std::endl;
185 
186  //mf::LogVerbatim("DUNE35tonOpDetResponse") << "OpDet: " << OpDet << " is a " << pdtype
187  // << " with length " << opdetHalfLength << " in detector "
188  // << box->GetDX() << " x " << box->GetDY() << " x " << box->GetDZ()
189  // << " named " << detname;
190  //mf::LogVerbatim("DUNE35tonOpDetResponse") << " Local Position = (" << Phot.FinalLocalPosition.x()
191  // << ", " << Phot.FinalLocalPosition.y() << ", " << Phot.FinalLocalPosition.z() << ")";
192  //mf::LogVerbatim("DUNE35tonOpDetResponse") << " Distance to SiPM = " << sipmDistance << " along axis " << fLongAxis;
193  //mf::LogVerbatim("DUNE35tonOpDetResponse") << " Attenuation Probability = " << AttenuationProb;
194 
195  // Throw away some photons based on attenuation
196  if ( CLHEP::RandFlat::shoot(1.0) > AttenuationProb ) return false;
197  }
198  else if (pdtype == 2) {
199  double normalize = 0.4498; // Normalize mean performance to be the same in all PDs
200  double lambda = 48.4; // cm
201  double altDistance = 2*opdetHalfLength - sipmDistance;
202  double frac = 0.5 * normalize;
203 
204  double AttenuationProb = frac*exp(-sipmDistance/lambda) + frac*exp(-altDistance/lambda);
205 
206  //std::cout <<"GRAPH: " << OpDet << "," << Phot.FinalLocalPosition.y() << "," << sipmDistance << "," << AttenuationProb << std::endl;
207 
208  //mf::LogVerbatim("DUNE35tonOpDetResponse") << "OpDet: " << OpDet << " is a " << pdtype
209  // << " with length " << opdetHalfLength << " in detector "
210  // << box->GetDX() << " x " << box->GetDY() << " x " << box->GetDZ()
211  // << " named " << detname;
212  //mf::LogVerbatim("DUNE35tonOpDetResponse") << " Local Position = (" << Phot.FinalLocalPosition.x()
213  // << ", " << Phot.FinalLocalPosition.y() << ", " << Phot.FinalLocalPosition.z() << ")";
214  //mf::LogVerbatim("DUNE35tonOpDetResponse") << " Distance to SiPM = " << sipmDistance << " along axis " << fLongAxis;
215  //mf::LogVerbatim("DUNE35tonOpDetResponse") << " Attenuation Probability = " << AttenuationProb;
216 
217  // Throw away some photons based on attenuation
218  if ( CLHEP::RandFlat::shoot(1.0) > AttenuationProb ) return false;
219  }
220  else {
221  mf::LogWarning("DUNE35tonOpDetResponse") << "OpDet: " << OpDet << " is an unknown PD type named: " << detname
222  << ". Assuming no attenuation.";
223  }
224 
225  }
226 
227  return true;
228  }
229 
230  //--------------------------------------------------------------------
231  bool DUNE35tonOpDetResponse::doDetectedLite(int OpDet, int &newOpChannel) const
232  {
234 
235  // Find the Optical Detector using the geometry service
237  // Here OpDet must be opdet since we are introducing
238  // channel mapping here.
239  const TGeoNode* node = geom->OpDetGeoFromOpDet(OpDet).Node();
240 
241 
242  // Identify the photon detector type
243  int pdtype;
244  std::string detname = node->GetName();
245  boost::to_lower(detname);
246  if (detname.find("bar") != std::string::npos ) pdtype = 0;
247  else if (detname.find("fiber") != std::string::npos ) pdtype = 1;
248  else if (detname.find("plank") != std::string::npos ) pdtype = 2;
249  else pdtype = -1;
250 
251  // Override default number of channels for Fiber and Plank
252  float NOpHardwareChannels = geom->NOpHardwareChannels(OpDet);
253  if (pdtype == 1) NOpHardwareChannels = 8;
254  if (pdtype == 2) NOpHardwareChannels = 2;
255 
256  int hardwareChannel = (int) ( CLHEP::RandFlat::shoot(1.0) * NOpHardwareChannels );
257  newOpChannel = geom->OpChannel(OpDet, hardwareChannel);
258  }
259  else{
260  newOpChannel = OpDet;
261  }
262 
263  // Check QE
264  if ( CLHEP::RandFlat::shoot(1.0) > fQE ) return false;
265 
266 
267  return true;
268  }
269 
270 } // namespace
271 
273 
const TGeoNode * Node() const
Returns the ROOT object describing the detector geometry.
Definition: OpDetGeo.h:146
OpDetGeo const & OpDetGeoFromOpDet(unsigned int OpDet) const
Returns the geo::OpDetGeo object for the given detector number.
virtual void doReconfigure(fhicl::ParameterSet const &p)
std::string string
Definition: nybbler.cc:12
virtual bool doDetected(int OpDet, const sim::OnePhoton &Phot, int &newOpChannel) const
All information of a photon entering the sensitive optical detector volume.
Definition: SimPhotons.h:64
unsigned int NOpHardwareChannels(int opDet) const
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
unsigned int NOpChannels() const
Number of electronics channels for all the optical detectors.
T get(std::string const &key) const
Definition: ParameterSet.h:271
unsigned int NOpDets() const
Number of OpDets in the whole detector.
unsigned int OpChannel(int detNum, int hardwareChannel) const
Convert detector number and hardware channel to unique channel.
Encapsulate the geometry of an optical detector.
virtual bool doDetectedLite(int OpDet, int &newOpChannel) const
Index NOpHardwareChannels(Index opDet)
geo::OpticalPoint_t FinalLocalPosition
Where photon enters the optical detector in local coordinates [cm].
Definition: SimPhotons.h:75
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
DUNE35tonOpDetResponse(fhicl::ParameterSet const &pset, art::ActivityRegistry &reg)
float Energy
Scintillation photon energy [GeV].
Definition: SimPhotons.h:82
virtual float wavelength(double energy) const
#define DEFINE_ART_SERVICE_INTERFACE_IMPL(svc, iface)