LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
LightSource_module.cc
Go to the documentation of this file.
1 
79 // C++ includes.
80 #include <cassert>
81 #include <cmath>
82 #include <fstream>
83 #include <memory>
84 #include <set>
85 #include <string>
86 #include <vector>
87 
88 // ART includes
94 #include "art_root_io/TFileService.h"
96 #include "cetlib/pow.h" // cet::square()
97 #include "cetlib_except/exception.h"
98 #include "fhiclcpp/ParameterSet.h"
100 
101 // art extensions
103 
104 // nusimdata includes
107 
108 // lar includes
116 
117 #include "TGeoManager.h"
118 #include "TGeoMaterial.h"
119 #include "TGeoNavigator.h"
120 #include "TList.h"
121 #include "TLorentzVector.h"
122 #include "TTree.h"
123 #include "TVector3.h"
124 
125 #include "CLHEP/Random/RandFlat.h"
126 #include "CLHEP/Random/RandGaussQ.h"
127 
128 namespace evgen {
129 
131  class LightSource : public art::EDProducer {
132  public:
133  explicit LightSource(fhicl::ParameterSet const& pset);
134 
135  void produce(art::Event& evt);
136  void beginRun(art::Run& run);
137 
138  private:
141  public:
144  std::set<std::string> const& materialNames);
145 
147 
148  // @{
150  bool accept(geo::Point_t const& point);
151  bool operator()(geo::Point_t const& point) { return accept(point); }
152  // @}
153 
154  private:
155  TGeoManager* fManager = nullptr;
156  TGeoNavigator* fNavigator = nullptr;
157 
159  std::set<std::string> const& fMaterials;
160 
162  TGeoMaterial const* materialAt(geo::Point_t const& point);
163 
165  TGeoMaterial const* findMaterial(std::string const& name) const;
166 
167  }; // MaterialPointFilter
168 
170 
172  void checkMaterials() const;
173 
177 
178  // for c2: fSeed is unused
179  //int fSeed; //random number seed
180  std::string fVersion; //version of the configuration
181 
182  // Flags to mark module modes
183  static const int kUNIF = 0;
184  static const int kGAUS = 1;
185  static const int kFILE = 0;
186  static const int kSCAN = 1;
187 
188  // File stream, filename and empty string for file processing
189  std::ifstream fInputFile;
190  std::string fFileName;
191  char fDummyString[256];
192 
193  // A ttree to keep track of where particles have been shot - ends up in histos.root
195  TLorentzVector fShotPos;
196  TLorentzVector fShotMom;
197  Int_t fEvID;
198 
199  // Parameters loaded from config - both modes
200  int fSourceMode; // Mode to run in - scan or file
201  bool fFillTree; // Do we want to create a TTree of shot particles?
202  int fPosDist; //
203  int fTDist; // Random distributions to use : 1= gauss, 0= uniform
204  int fPDist; //
205 
207  std::set<std::string> const fSelectedMaterials;
208 
209  //Scan mode specific parameters
210  int fXSteps; //
211  int fYSteps; // Number of steps to take in each dimension
212  int fZSteps; //
213 
214  sim::PhotonVoxelDef fThePhotonVoxelDef; // The photon voxel definition object for scan mode
215 
216  int fVoxelCount; // Total number of voxels
217  int fCurrentVoxel; // Counter to keep track of vox ID
218 
219  // TPC Measurements
221  std::vector<double> fRegionMin;
222  std::vector<double> fRegionMax;
224 
225  // Parameters used to shoot in distributions
227  bool fPointSource; // Point-like light source in fCenter
228  double fT; // central t position of source
229  double fSigmaX; // x width
230  double fSigmaY; // y width
231  double fSigmaZ; // z width
232  double fSigmaT; // t width
233  double fP; // central momentm of photon
234  double fSigmaP; // mom width;
235 
236  // Number of photons per event
237  int fN; // number of photons per event
238 
240  double const fNMaxF;
241 
244 
245  CLHEP::HepRandomEngine& fEngine;
247  };
248 }
249 
250 namespace {
251 
253  template <typename Coll>
254  std::set<typename Coll::value_type> makeSet(Coll const& coll)
255  {
256  return {begin(coll), end(coll)};
257  }
258 
259 } // local namespace
260 
261 namespace evgen {
262 
263  //----------------------------------------------------------------
265  : art::EDProducer{pset}
266  , fSourceMode{pset.get<int>("SourceMode")}
267  , fFillTree{pset.get<bool>("FillTree")}
268  , fPosDist{pset.get<int>("PosDist")}
269  , fTDist{pset.get<int>("TDist")}
270  , fPDist{pset.get<int>("PDist")}
271  , fSelectedMaterials{makeSet(pset.get<std::vector<std::string>>("SelectMaterials", {}))}
272  , fNMaxF{pset.get<double>("NMaxFactor", 100.0)}
273  // create a default random engine; obtain the random seed from NuRandomService,
274  // unless overridden in configuration with key "Seed"
275  , fEngine(art::ServiceHandle<rndm::NuRandomService>()->registerAndSeedEngine(createEngine(0),
276  pset,
277  "Seed"))
278  , fGeom(*lar::providerFrom<geo::Geometry const>())
279  {
280 
281  checkMaterials();
282 
283  // load optional parameters in function
284  produces<sumdata::RunData, art::InRun>();
285  produces<std::vector<simb::MCTruth>>();
286 
287  if (fSourceMode == kFILE) {
288  fFileName = pset.get<std::string>("SteeringFile");
289  fInputFile.open(fFileName.c_str());
290  fInputFile.getline(fDummyString, 256);
291  }
292  else if (fSourceMode == kSCAN) {
293  fT = pset.get<double>("T0");
294  fSigmaT = pset.get<double>("SigmaT");
295  fN = pset.get<int>("N");
296 
297  fFirstVoxel = pset.get<int>("FirstVoxel");
298  fLastVoxel = pset.get<int>("LastVoxel");
299 
300  fP = pset.get<double>("P");
301  fSigmaP = pset.get<double>("SigmaP");
302 
303  fUseCustomRegion = pset.get<bool>("UseCustomRegion");
304  fPointSource = pset.get<bool>("PointSource", false);
305 
306  if (fUseCustomRegion) {
307  fRegionMin = pset.get<std::vector<double>>("RegionMin");
308  fRegionMax = pset.get<std::vector<double>>("RegionMax");
309  fXSteps = pset.get<int>("XSteps");
310  fYSteps = pset.get<int>("YSteps");
311  fZSteps = pset.get<int>("ZSteps");
312  }
313 
314  // get TPC dimensions removed. -TA
315 
316  fCurrentVoxel = 0;
317 
318  // define voxelization based on parameters read from config.
319  // There are two modes - either read the dimensions of the TPC from
320  // the geometry, or use values specified by the user.
321  if (!fUseCustomRegion) {
324  }
325  else {
327  fRegionMax[0],
328  fXSteps,
329  fRegionMin[1],
330  fRegionMax[1],
331  fYSteps,
332  fRegionMin[2],
333  fRegionMax[2],
334  fZSteps);
335  }
336 
337  // Set distribution widths to voxel size
338 
342 
343  // Get number of voxels we will step through
344 
346 
347  if (fLastVoxel < 0) fLastVoxel = fVoxelCount;
348 
349  mf::LogVerbatim("LightSource") << "Light Source : Determining voxel params : " << fVoxelCount
350  << " " << fSigmaX << " " << fSigmaY << " " << fSigmaZ;
351  }
352  else {
353  throw cet::exception("LightSource")
354  << "EVGEN Light Source : Unrecognised light source mode\n";
355  }
356 
357  if (fFillTree) {
359  fPhotonsGenerated = tfs->make<TTree>("PhotonsGenerated", "PhotonsGenerated");
360  fPhotonsGenerated->Branch("X", &(fShotPos[0]), "X/D");
361  fPhotonsGenerated->Branch("Y", &(fShotPos[1]), "Y/D");
362  fPhotonsGenerated->Branch("Z", &(fShotPos[2]), "Z/D");
363  fPhotonsGenerated->Branch("T", &(fShotPos[3]), "T/D");
364  fPhotonsGenerated->Branch("PX", &(fShotMom[0]), "PX/D");
365  fPhotonsGenerated->Branch("PY", &(fShotMom[1]), "PY/D");
366  fPhotonsGenerated->Branch("PZ", &(fShotMom[2]), "PZ/D");
367  fPhotonsGenerated->Branch("PT", &(fShotMom[3]), "PT/D");
368  fPhotonsGenerated->Branch("EventID", &fEvID, "EventID/I");
369  }
370  }
371 
372  //____________________________________________________________________________
374  {
375  run.put(std::make_unique<sumdata::RunData>(fGeom.DetectorName()), art::fullRun());
376 
378  }
379 
380  //----------------------------------------------------------------
382  {
383  if (fSourceMode == kFILE) {
384  // Each event, read coordinates of gun and number of photons to shoot from file
385 
386  // read in one line
388  // Loop file if required
389  mf::LogWarning("LightSource") << "EVGEN Light Source : Warning, reached end of file,"
390  << " looping back to beginning";
391  fInputFile.clear();
392  fInputFile.seekg(0, std::ios::beg);
393  fInputFile.getline(fDummyString, 256);
394 
396  throw cet::exception("LightSource")
397  << "EVGEN Light Source : File error in " << fFileName << "\n";
398  }
399  }
400 
402  fCenter.X() + fSigmaX,
403  1,
404  fCenter.Y() - fSigmaY,
405  fCenter.Y() + fSigmaY,
406  1,
407  fCenter.Z() - fSigmaZ,
408  fCenter.Z() + fSigmaZ,
409  1);
410 
411  fCurrentVoxel = 0;
412  }
413  else if (fSourceMode == kSCAN) {
414  // Step through detector using a number of steps provided in the config file
415  // firing a constant number of photons from each point
417  }
418  else {
419  // Neither file or scan mode, probably a config file error
420  throw cet::exception("LightSource") << "EVGEN : Light Source, unrecognised source mode\n";
421  }
422 
423  auto truthcol = std::make_unique<std::vector<simb::MCTruth>>();
424 
425  truthcol->push_back(Sample());
426  int const nPhotons = truthcol->back().NParticles();
427 
428  evt.put(std::move(truthcol));
429 
430  phot::PhotonVisibilityService* vis = nullptr;
431  try {
433  }
434  catch (art::Exception const& e) {
435  // if the service is not configured, then this is not a build job
436  // (it is a simple generation job instead)
437  if (e.categoryCode() != art::errors::ServiceNotFound) throw;
438  }
439 
440  if (vis && vis->IsBuildJob()) {
441  mf::LogVerbatim("LightSource") << "Light source : Stowing voxel params ";
442  vis->StoreLightProd(fCurrentVoxel, nPhotons);
443  }
444 
445  if (fCurrentVoxel != fLastVoxel) { ++fCurrentVoxel; }
446  else {
447  mf::LogVerbatim("LightSource")
448  << "EVGEN Light Source fully scanned detector. Starting over.";
450  }
451  }
452 
454  {
455  mf::LogVerbatim("LightSource") << "Light source debug : Shooting at " << fCenter;
456 
457  CLHEP::RandFlat flat(fEngine, -1.0, 1.0);
458  CLHEP::RandGaussQ gauss(fEngine);
459 
461 
462  simb::MCTruth mct;
464 
465  unsigned long long int const nMax = static_cast<unsigned long long int>(double(fN) * fNMaxF);
466  unsigned long long int fired = 0ULL;
467  while (mct.NParticles() < fN) {
468  if (fired >= nMax) break;
469 
470  // Choose momentum (supplied in eV, convert to GeV)
471  double const p =
472  1e-9 * ((fPDist == kGAUS) ? gauss.fire(fP, fSigmaP) : fP + fSigmaP * flat.fire());
473 
474  // Choose position
475  ++fired;
476  geo::Point_t x;
477  if (fPointSource) { x = fCenter; }
478  else {
479  if (fPosDist == kGAUS) {
480  x = {gauss.fire(fCenter.X(), fSigmaX),
481  gauss.fire(fCenter.Y(), fSigmaY),
482  gauss.fire(fCenter.Z(), fSigmaZ)};
483  }
484  else {
485  x = {fCenter.X() + fSigmaX * flat.fire(),
486  fCenter.Y() + fSigmaY * flat.fire(),
487  fCenter.Z() + fSigmaZ * flat.fire()};
488  }
489 
490  if (!filter.accept(x)) continue;
491  }
492 
493  // Choose time
494  double t;
495  if (fTDist == kGAUS) { t = gauss.fire(fT, fSigmaT); }
496  else {
497  t = fT + fSigmaT * flat.fire();
498  }
499 
500  //assume the position is relative to the center of the TPC
501  //x += fTPCCenter;
502 
503  fShotPos = TLorentzVector(x.X(), x.Y(), x.Z(), t);
504 
505  // Choose angles
506  double costh = flat.fire();
507  double sinth = std::sqrt(1.0 - cet::square(costh));
508  double phi = 2 * M_PI * flat.fire();
509 
510  // Generate momentum 4-vector
511 
512  fShotMom = TLorentzVector(p * sinth * cos(phi), p * sinth * sin(phi), p * costh, p);
513 
514  int trackid = -(mct.NParticles() +
515  1); // set track id to -i as these are all primary particles and have id <= 0
516  std::string primary("primary");
517  int PDG = 0; //optical photons have PDG 0
518 
519  simb::MCParticle part(trackid, PDG, primary);
521 
522  if (fFillTree) fPhotonsGenerated->Fill();
523 
524  mct.Add(part);
525  }
526 
527  mf::LogInfo("LightSource") << "Generated " << mct.NParticles() << " photons after " << fired
528  << " tries.";
529  if (mct.NParticles() < fN) {
530  // this may mean `NMaxFactor` is too small, or the volume is wrong;
531  // or it may be just expected
532  mf::LogWarning("LightSource")
533  << "Warning: " << mct.NParticles() << " photons generated after " << fired << " tries, but "
534  << fN << " were requested.";
535  }
536 
537  return mct;
538  } // LightSource::Sample()
539 
540  // ---------------------------------------------------------------------------
542  {
543 
544  TGeoManager const& manager = *(fGeom.ROOTGeoManager());
545 
546  { // start scope
547  mf::LogDebug log("LightSource");
548  auto const& matList = *(manager.GetListOfMaterials());
549  log << matList.GetSize() << " elements/materials in the geometry:";
550  for (auto const* obj : matList) {
551  auto const mat = dynamic_cast<TGeoMaterial const*>(obj);
552  log << "\n '" << mat->GetName() << "' (Z=" << mat->GetZ() << " A=" << mat->GetA() << ")";
553  } // for
554  } // end scope
555 
556  std::set<std::string> missingMaterials;
557  for (auto const& matName : fSelectedMaterials) {
558  if (!manager.GetMaterial(matName.c_str())) missingMaterials.insert(matName);
559  }
560  if (missingMaterials.empty()) return;
561 
563  e << "Requested filtering on " << missingMaterials.size()
564  << " materials which are not present in the geometry:";
565  for (auto const& matName : missingMaterials)
566  e << "\n '" << matName << "'";
567  throw e << "\n";
568 
569  } // LightSource::checkMaterials()
570 
571  // ---------------------------------------------------------------------------
572  // --- LightSource::MaterialPointFilter
573  // ---------------------------------------------------------------------------
575  std::set<std::string> const& materialNames)
576  : fManager(geom.ROOTGeoManager())
577  , fNavigator(fManager->AddNavigator())
578  , fMaterials(materialNames)
579  {
580  assert(fManager);
581  assert(fNavigator);
582  }
583 
584  // ---------------------------------------------------------------------------
586  {
587  fManager->RemoveNavigator(fNavigator); // this deletes the navigator
588  fNavigator = nullptr;
589  } // LightSource::MaterialPointFilter::~MaterialPointFilter()
590 
591  // ---------------------------------------------------------------------------
593  {
594  TGeoNode const* node = fNavigator->FindNode(point.X(), point.Y(), point.Z());
595  return node ? node->GetVolume()->GetMaterial() : nullptr;
596  } // LightSource::MaterialPointFilter::materialAt()
597 
598  // ---------------------------------------------------------------------------
600  {
601  if (fMaterials.empty()) return true;
602  TGeoMaterial const* material = materialAt(point);
603  MF_LOG_TRACE("LightSource") << "Material at " << point << ": "
604  << (material ? material->GetName() : "not found");
605  return material ? (fMaterials.count(material->GetName()) > 0) : false;
606  } // LightSource::MaterialPointFilter::accept()
607 
608  //----------------------------------------------------------------------------
610  {
611  double x, y, z;
612  fInputFile >> x >> y >> z >> fT >> fSigmaX >> fSigmaY >> fSigmaZ >> fSigmaT >> fP >> fSigmaP >>
613  fN;
614  fCenter = {x, y, z};
615  if (!fInputFile.good()) return false;
616 
617  std::string dummy;
618  std::getline(fInputFile, dummy); // this can fail for what I care
619  return true;
620  } // LightSource::readParametersFromInputFile()
621 
622  // ---------------------------------------------------------------------------
623 
624 } // namespace evgen
625 
Definitions of voxel data structures.
Float_t x
Definition: compare.C:6
std::vector< double > fRegionMin
base_engine_t & createEngine(seed_t seed)
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
MaterialPointFilter(geo::GeometryCore const &geom, std::set< std::string > const &materialNames)
Constructor: sets up the filter configuration.
LightSource(fhicl::ParameterSet const &pset)
Utilities related to art service access.
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
Definition: MCParticle.h:258
constexpr auto fullRun()
geo::GeometryCore const & fGeom
Geometry service provider (cached).
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:160
void SetOrigin(simb::Origin_t origin)
Definition: MCTruth.h:82
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
Vector GetVoxelSize() const
Returns a vector describing the span of a single voxel in x, y an z [cm].
Definition: PhotonVoxels.h:208
static const int kSCAN
TGeoNavigator * fNavigator
Our own ROOT geometry navigator.
Float_t y
Definition: compare.C:6
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
Double_t z
Definition: plot.C:276
Representation of a region of space diced into voxels.
Definition: PhotonVoxels.h:58
static const int kGAUS
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Run.h:121
std::vector< double > fRegionMax
int NParticles() const
Definition: MCTruth.h:75
Particle class.
double const fNMaxF
Maximum number of attempted samplings (factor on top of fN).
TGeoManager * ROOTGeoManager() const
Access to the ROOT geometry description manager.
void checkMaterials() const
Throws an exception if any of the configured materials is not present.
Definition: Run.h:37
Framework includes.
bool operator()(geo::Point_t const &point)
Returns whether the specified point can be accepted.
void produce(art::Event &evt)
CLHEP::HepRandomEngine & fEngine
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
void StoreLightProd(int VoxID, double N)
Access the description of detector geometry.
TString part[npart]
Definition: Style.C:32
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
Definitions of geometry vector data types.
std::set< std::string > const & fMaterials
Names of materials to select.
single particles thrown at the detector
Definition: MCTruth.h:26
simb::MCTruth Sample()
#define MF_LOG_TRACE(id)
Float_t mat
Definition: plot.C:38
Filters a point according to the material at that point.
Description of geometry of one entire detector.
Definition: GeometryCore.h:119
TGeoMaterial const * materialAt(geo::Point_t const &point)
Returns a pointer to the material of the volume at specified point.
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
TGeoMaterial const * findMaterial(std::string const &name) const
Returns a pointer to the material with the specified name.
void beginRun(art::Run &run)
sim::PhotonVoxelDef fThePhotonVoxelDef
static const int kUNIF
const sim::PhotonVoxelDef & GetVoxelDef() const
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
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:180
void Add(simb::MCParticle const &part)
Definition: MCTruth.h:80
geo::Point_t fCenter
Central position of source [cm].
TGeoManager * fManager
ROOT geometry manager.
Point GetCenter() const
Returns the center of the voxel (type Point).
Definition: PhotonVoxels.h:186
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
static const int kFILE
unsigned int GetNVoxels() const
Returns the total number of voxels in the volume.
Definition: MVAAlg.h:12
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
std::string const & DetectorName() const
Returns a string with the name of the detector, as configured.
Definition: GeometryCore.h:203
A module for optical MC testing and library building.
TCEvent evt
Definition: DataStructs.cxx:8
bool accept(geo::Point_t const &point)
Returns whether the specified point can be accepted.
Event generator information.
Definition: MCTruth.h:32
Float_t e
Definition: plot.C:35
Event Generation using GENIE, cosmics or single particles.
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
std::set< std::string > const fSelectedMaterials
Names of materials to consider scintillation from.
PhotonVoxel GetPhotonVoxel(int ID) const