LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
PhotonGen_module.cc
Go to the documentation of this file.
1 // Plugin Type: producer
3 // File: PhotonGen_module.cc
4 // Description:
5 // Produce photons at the vertex uniformly distributed in the active volume
6 // Oct. 20, 2020 by Mu Wei wmu@fnal.gov
7 //
8 // Add new feature: user-defined region (arbitrary rectangular block) of
9 // photon emission vertex
10 // Jan 10, 2024 by Shuaiixang (Shu) Zhang, szh2@iu.edu
12 
13 // C++ includes.
14 #include <cmath>
15 #include <fstream>
16 #include <memory>
17 #include <string>
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <time.h>
22 
23 // ART includes
29 #include "art_root_io/TFileService.h"
31 #include "cetlib_except/exception.h"
32 #include "fhiclcpp/ParameterSet.h"
34 
35 // art extensions
39 
40 // lar includes
43 
44 #include "TLorentzVector.h"
45 #include "TTree.h"
46 #include "TVector3.h"
47 
48 #include "CLHEP/Random/RandFlat.h"
49 #include "CLHEP/Random/RandGaussQ.h"
50 
51 namespace evgen {
52  class PhotonGen : public art::EDProducer {
53  public:
54  explicit PhotonGen(fhicl::ParameterSet const& pset);
55  void produce(art::Event& evt);
56  void beginRun(art::Run& run);
57 
58  private:
59  void Sample(simb::MCTruth& truth);
60 
61  //Flags
62  static const int kUNIF = 0;
63  static const int kGAUS = 1;
64 
65  //TTree to keep track of where particles have been shot
66  bool fFillTree; // Do we want to create a TTree of shot particles?
67  TTree* fPhotonGen;
68  TLorentzVector fShotPos;
69  TLorentzVector fShotMom;
70  Int_t fEvID;
71 
72  //Scan simulation
73  bool fScan; // Do we want to scan x, y, z or just simulate a random point?
74  double fPx;
75  double fPy; // Fixed coordinate
76  double fPz;
77 
78  //Parameters used to shoot in distributions
79  int fPosDist; //
80  int fTDist; // Random distributions to use : 1= gauss, 0= uniform
81  int fPDist; //
82  double fX; // central x position of source
83  double fY; // central y position of source
84  double fZ; // central z position of source
85  double fT; // central t position of source
86  double fSigmaT; // t width
87  double fP; // central momentm of photon
88  double fSigmaP; // mom width;
89 
90  //Number of photons per event
91  int fN; // number of photons per event
92 
93  CLHEP::HepRandomEngine& fEngine;
94 
95  //Boundaries of the detector
96  double fXmin;
97  double fXmax;
98  double fYmin;
99  double fYmax;
100  double fZmin;
101  double fZmax;
102  };
103 
104  //----------------------------------------------------------------
106  : art::EDProducer{pset}
107  , fFillTree{pset.get<bool>("FillTree")}
108  , fScan{pset.get<bool>("Scan")}
109  , fPosDist{pset.get<int>("PosDist")}
110  , fTDist{pset.get<int>("TDist")}
111  , fPDist{pset.get<int>("PDist")}
112  , fT{pset.get<double>("T0")}
113  , fSigmaT{pset.get<double>("SigmaT")}
114  , fP{pset.get<double>("P")}
115  , fSigmaP{pset.get<double>("SigmaP")}
116  , fN{pset.get<int>("N")}
117 
118  , fEngine(art::ServiceHandle<rndm::NuRandomService>()->registerAndSeedEngine(createEngine(0),
119  pset,
120  "Seed"))
121  {
122  produces<sumdata::RunData, art::InRun>();
123  produces<std::vector<simb::MCTruth>>();
124 
125  if (fFillTree) {
127  fPhotonGen = tfs->make<TTree>("PhGen", "PhGen");
128  fPhotonGen->Branch("X", &(fShotPos[0]), "X/D");
129  fPhotonGen->Branch("Y", &(fShotPos[1]), "Y/D");
130  fPhotonGen->Branch("Z", &(fShotPos[2]), "Z/D");
131  fPhotonGen->Branch("T", &(fShotPos[3]), "T/D");
132  fPhotonGen->Branch("PX", &(fShotMom[0]), "PX/D");
133  fPhotonGen->Branch("PY", &(fShotMom[1]), "PY/D");
134  fPhotonGen->Branch("PZ", &(fShotMom[2]), "PZ/D");
135  fPhotonGen->Branch("PT", &(fShotMom[3]), "PT/D");
136  fPhotonGen->Branch("EventID", &fEvID, "EventID/I");
137  }
138 
139  if (fScan) {
140  fPx = pset.get<double>("X");
141  fPy = pset.get<double>("Y");
142  fPz = pset.get<double>("Z");
143  std::cout << "Will generate photons from 3 points." << std::endl;
144  }
145 
146  if (auto boundaries = pset.get_if_present<fhicl::ParameterSet>("boundaries")) {
147  fXmin = boundaries->get<double>("Xmin");
148  fXmax = boundaries->get<double>("Xmax");
149  fYmin = boundaries->get<double>("Ymin");
150  fYmax = boundaries->get<double>("Ymax");
151  fZmin = boundaries->get<double>("Zmin");
152  fZmax = boundaries->get<double>("Zmax");
153 
154  //Boundaries set by user---
155  std::cout << "\n\nPhoton Emission Region (user-defined) [cm]:" << std::endl;
156  std::cout << "Xmin: " << fXmin << " Xmax: " << fXmax << " Ymin: " << fYmin
157  << " Ymax: " << fYmax << " Zmin: " << fZmin << " Zmax: " << fZmax << "\n\n"
158  << std::endl;
159  }
160  else {
162  auto const CryoBounds = geo->Cryostat().Boundaries();
163  fXmin = CryoBounds.MinX();
164  fXmax = CryoBounds.MaxX();
165  fYmin = CryoBounds.MinY();
166  fYmax = CryoBounds.MaxY();
167  fZmin = CryoBounds.MinZ();
168  fZmax = CryoBounds.MaxZ();
169  //Initial default boundaries---
170  std::cout << "\n\nPhoton Emission Region (default Cryo Boundaries) [cm]:" << std::endl;
171  std::cout << "Xmin: " << fXmin << " Xmax: " << fXmax << " Ymin: " << fYmin
172  << " Ymax: " << fYmax << " Zmin: " << fZmin << " Zmax: " << fZmax << "\n\n"
173  << std::endl;
174  }
175  }
176 
177  //____________________________________________________________________________
179  {
180  std::cout << "\n\nBegin Job\n\n" << std::endl;
181 
183  std::cout << "Number of optical detector: " << int(geo1->Cryostat().NOpDet()) << std::endl;
184 
185  run.put(std::make_unique<sumdata::RunData>(geo1->DetectorName()), art::fullRun());
186  }
187 
188  //----------------------------------------------------------------
190  {
191  std::mt19937 rng;
192  rng.seed(std::random_device()());
193  std::uniform_real_distribution<double> distX(fXmin, fXmax);
194  std::uniform_real_distribution<double> distY(fYmin, fYmax);
195  std::uniform_real_distribution<double> distZ(fZmin, fZmax);
196  std::uniform_real_distribution<double> width(-2.0, 2.0); //scan width---
197 
198  std::unique_ptr<std::vector<simb::MCTruth>> truthcol(new std::vector<simb::MCTruth>);
199  simb::MCTruth truth;
201 
202  if (fScan) {
203  fX = distX(rng);
204  fY = fPy + width(rng);
205  fZ = fPz + width(rng);
206  Sample(truth);
207  }
208  else {
209  fX = distX(rng);
210  fY = distY(rng);
211  fZ = distZ(rng);
212 
213  Sample(truth);
214  }
215 
216  truthcol->push_back(truth);
217  evt.put(std::move(truthcol));
218  }
219 
221  {
222  std::cout << "\n\nPhotons Shooting at the Position: " << fX << " " << fY << " " << fZ << "\n\n"
223  << std::endl;
224 
225  CLHEP::RandFlat flat(fEngine);
226  CLHEP::RandGaussQ gauss(fEngine);
227 
228  for (int j = 0; j != fN; ++j) {
229  TVector3 pos;
230  pos[0] = fX;
231  pos[1] = fY;
232  pos[2] = fZ;
233 
234  double time;
235  if (fTDist == kGAUS) { time = gauss.fire(fT, fSigmaT); }
236  else {
237  time = fT + fSigmaT * (2.0 * flat.fire() - 1.0);
238  }
239  fShotPos = TLorentzVector(pos[0], pos[1], pos[2], time);
240 
241  //momentum (supplied in eV, convert to GeV)
242  double p = fP;
243  if (fPDist == kGAUS) { p = gauss.fire(fP, fSigmaP); }
244  else {
245  p = fP + fSigmaP * (2.0 * flat.fire() - 1.0);
246  }
247  p /= 1000000000.;
248 
249  //angles
250  double costh = 2 * flat.fire() - 1;
251  double sinth = std::sqrt(1 - costh * costh);
252  double phi = 2 * M_PI * flat.fire();
253 
254  //momentum 4-vector
255  fShotMom = TLorentzVector(p * sinth * cos(phi), p * sinth * sin(phi), p * costh, p);
256 
257  int trackid =
258  -1 *
259  (j + 1); // set track id to negative as these are all primary particles and have id <= 0
260  int PDG = 0; // optical photons have PDG 0
261  simb::MCParticle particle(trackid, PDG, "primary");
263 
264  if (fFillTree) { fPhotonGen->Fill(); }
265 
266  mct.Add(particle);
267  }
268  }
269 }
270 
base_engine_t & createEngine(seed_t seed)
PhotonGen(fhicl::ParameterSet const &pset)
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
Definition: MCParticle.h:258
constexpr auto fullRun()
static const int kUNIF
void SetOrigin(simb::Origin_t origin)
Definition: MCTruth.h:82
TLorentzVector fShotMom
void beginRun(art::Run &run)
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
void Sample(simb::MCTruth &truth)
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Run.h:121
Particle class.
Definition: Run.h:37
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
single particles thrown at the detector
Definition: MCTruth.h:26
CLHEP::HepRandomEngine & fEngine
TLorentzVector fShotPos
static const int kGAUS
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
CryostatGeo const & Cryostat(CryostatID const &cryoid=details::cryostat_zero) const
Returns the specified cryostat.
void Add(simb::MCParticle const &part)
Definition: MCTruth.h:80
unsigned int NOpDet() const
Number of optical detectors in this TPC.
Definition: CryostatGeo.h:317
Definition: MVAAlg.h:12
BoxBoundedGeo const & Boundaries() const
Returns boundaries of the cryostat (in centimetres).
Definition: CryostatGeo.h:113
std::string const & DetectorName() const
Returns a string with the name of the detector, as configured.
Definition: GeometryCore.h:140
TCEvent evt
Definition: DataStructs.cxx:8
Event generator information.
Definition: MCTruth.h:32
ROOT libraries.
void produce(art::Event &evt)
Event Generation using GENIE, cosmics or single particles.
static ServiceHandle< RandomNumberGenerator > & rng()
art framework interface to geometry description