NeutronOsc_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: NeutronOsc
3 // Module Type: producer
4 // GENIE neutron-antineutron oscillation generator
5 //
6 // Adapted from NucleonDecay_module.cc (tjyang@fnal.gov)
7 // by jhewes15@fnal.gov
8 //
9 // Neutron-antineutron oscillation mode ID:
10 // ---------------------------------------------------------
11 // ID | Decay Mode
12 // |
13 // ---------------------------------------------------------
14 // 0 | Random oscillation mode
15 // 1 | p + nbar --> \pi^{+} + \pi^{0}
16 // 2 | p + nbar --> \pi^{+} + 2\pi^{0}
17 // 3 | p + nbar --> \pi^{+} + 3\pi^{0}
18 // 4 | p + nbar --> 2\pi^{+} + \pi^{-} + \pi^{0}
19 // 5 | p + nbar --> 2\pi^{+} + \pi^{-} + 2\pi^{0}
20 // 6 | p + nbar --> 2\pi^{+} + \pi^{-} + 2\omega^{0}
21 // 7 | p + nbar --> 3\pi^{+} + 2\pi^{-} + \pi^{0}
22 // 8 | n + nbar --> \pi^{+} + \pi^{-}
23 // 9 | n + nbar --> 2\pi^{0}
24 // 10 | n + nbar --> \pi^{+} + \pi^{-} + \pi^{0}
25 // 11 | n + nbar --> \pi^{+} + \pi^{-} + 2\pi^{0}
26 // 12 | n + nbar --> \pi^{+} + \pi^{-} + 3\pi^{0}
27 // 13 | n + nbar --> 2\pi^{+} + 2\pi^{-}
28 // 14 | n + nbar --> 2\pi^{+} + 2\pi^{-} + \pi^{0}
29 // 15 | n + nbar --> \pi^{+} + \pi^{-} + \omega^{0}
30 // 16 | n + nbar --> 2\pi^{+} + 2\pi^{-} + 2\pi^{0}
31 // ---------------------------------------------------------
32 //
33 ////////////////////////////////////////////////////////////////////////
34 
39 #include "fhiclcpp/ParameterSet.h"
41 
42 // GENIE includes
50 
51 // larsoft includes
54 
55 #include "nugen/EventGeneratorBase/GENIE/GENIE2ART.h"
56 
59 #include "nurandom/RandomUtils/NuRandomService.h"
60 
61 // c++ includes
62 #include <memory>
63 #include <string>
64 
65 #include "CLHEP/Random/RandFlat.h"
66 
67 namespace evgen {
68  class NeutronOsc;
69 }
70 
72 public:
73  explicit NeutronOsc(fhicl::ParameterSet const & p);
74  // The destructor generated by the compiler is fine for classes
75  // without bare pointers or other resource use.
76 
77  // Plugins should not be copied or assigned.
78  NeutronOsc(NeutronOsc const &) = delete;
79  NeutronOsc(NeutronOsc &&) = delete;
80  NeutronOsc & operator = (NeutronOsc const &) = delete;
81  NeutronOsc & operator = (NeutronOsc &&) = delete;
82 
83  // Required functions.
84  void produce(art::Event & e) override;
85 
86  // Selected optional functions.
87  void beginRun(art::Run& run) override;
88 
89 private:
90 
91  // Additional functions
92  int SelectAnnihilationMode(int pdg_code);
93 
94  // Declare member data here.
96  genie::NNBarOscMode_t gOptDecayMode = genie::kNONull; // neutron-antineutron oscillation mode
97  CLHEP::RandFlat flatDist;
98 
99 };
100 
101 
103  : art::EDProducer{p}
104  // create a default random engine; obtain the random seed from NuRandomService,
105  // unless overridden in configuration with key "Seed"
106  , flatDist{art::ServiceHandle<rndm::NuRandomService>{}->createEngine(*this, p, "Seed")}
107 {
108  genie::PDGLibrary::Instance(); //Ensure Messenger is started first in GENIE.
109 
110  string sname = "genie::EventGenerator";
111  // GENIE v2 // string sconfig = "NeutronOsc";
112  string sconfig = "NNBarOsc";
113  // GENIE v3 needs a tune (even if irrelevant)
114  evgb::SetEventGeneratorListAndTune("Default","Default");
115 
117  mcgen =
118  dynamic_cast<const genie::EventRecordVisitorI *> (algf->GetAlgorithm(sname,sconfig));
119  if(!mcgen) {
120  throw cet::exception("NeutronOsc") << "Couldn't instantiate the neutron-antineutron oscillation generator";
121  }
122  int fDecayMode = p.get<int>("DecayMode");
123  gOptDecayMode = (genie::NNBarOscMode_t) fDecayMode;
124 
125  produces< std::vector<simb::MCTruth> >();
126  produces< sumdata::RunData, art::InRun >();
127 
128  unsigned int seed = art::ServiceHandle<rndm::NuRandomService>()->getSeed();
130 }
131 
133 {
134  // Implementation of required member function here.
136  int target = 1000180400; //Only use argon target
137  int decay = SelectAnnihilationMode(target);
139  event->AttachSummary(interaction);
140 
141  // Simulate decay
143 
144 // genie::Interaction *inter = event->Summary();
145 // const genie::InitialState &initState = inter->InitState();
146 // std::cout<<"initState = "<<initState.AsString()<<std::endl;
147 // const genie::ProcessInfo &procInfo = inter->ProcInfo();
148 // std::cout<<"procInfo = "<<procInfo.AsString()<<std::endl;
149  MF_LOG_DEBUG("NeutronOsc")
150  << "Generated event: " << *event;
151 
152  std::unique_ptr< std::vector<simb::MCTruth> > truthcol(new std::vector<simb::MCTruth>);
153  simb::MCTruth truth;
154 
156 
157  // Find boundary of active volume
158  double minx = 1e9;
159  double maxx = -1e9;
160  double miny = 1e9;
161  double maxy = -1e9;
162  double minz = 1e9;
163  double maxz = -1e9;
164  for (size_t i = 0; i<geo->NTPC(); ++i){
165  const geo::TPCGeo &tpc = geo->TPC(i);
166  if (minx>tpc.MinX()) minx = tpc.MinX();
167  if (maxx<tpc.MaxX()) maxx = tpc.MaxX();
168  if (miny>tpc.MinY()) miny = tpc.MinY();
169  if (maxy<tpc.MaxY()) maxy = tpc.MaxY();
170  if (minz>tpc.MinZ()) minz = tpc.MinZ();
171  if (maxz<tpc.MaxZ()) maxz = tpc.MaxZ();
172  }
173 
174  // Assign vertice position
175  double X0 = flatDist.fire( minx, maxx );
176  double Y0 = flatDist.fire( miny, maxy );
177  double Z0 = flatDist.fire( minz, maxz );
178 
179  TIter partitr(event);
180  genie::GHepParticle *part = 0;
181  // GHepParticles return units of GeV/c for p. the V_i are all in fermis
182  // and are relative to the center of the struck nucleus.
183  // add the vertex X/Y/Z to the V_i for status codes 0 and 1
184  int trackid = 0;
185  std::string primary("primary");
186 
187  while( (part = dynamic_cast<genie::GHepParticle *>(partitr.Next())) ){
188 
189  simb::MCParticle tpart(trackid,
190  part->Pdg(),
191  primary,
192  part->FirstMother(),
193  part->Mass(),
194  part->Status());
195 
196  TLorentzVector pos(X0, Y0, Z0, 0);
197  TLorentzVector mom(part->Px(), part->Py(), part->Pz(), part->E());
198  tpart.AddTrajectoryPoint(pos,mom);
199  if(part->PolzIsSet()) {
200  TVector3 polz;
201  part->GetPolarization(polz);
202  tpart.SetPolarization(polz);
203  }
204  truth.Add(tpart);
205 
206  ++trackid;
207  }// end loop to convert GHepParticles to MCParticles
208  truth.SetOrigin(simb::kUnknown);
209  truthcol->push_back(truth);
210  //FillHistograms(truth);
211  e.put(std::move(truthcol));
212 
213  delete event;
214 }
215 
217 {
219  run.put(std::make_unique<sumdata::RunData>(geo->DetectorName()));
220 }
221 
222 
224 {
225  // if the mode is set to 'random' (the default), pick one at random!
226  if ((int)gOptDecayMode == 0) {
227  int mode;
228 
229  std::string pdg_string = std::to_string(static_cast<long long>(pdg_code));
230  if (pdg_string.size() != 10) {
231  std::cout << "Expecting PDG code to be a 10-digit integer; instead, it's the following: " << pdg_string << std::endl;
232  exit(1);
233  }
234 
235  // count number of protons & neutrons
236  int n_nucleons = std::stoi(pdg_string.substr(6,3)) - 1;
237  int n_protons = std::stoi(pdg_string.substr(3,3));
238 
239  // factor proton / neutron ratio into branching ratios
240  double proton_frac = ((double)n_protons) / ((double)n_nucleons);
241  double neutron_frac = 1 - proton_frac;
242 
243  // set branching ratios, taken from bubble chamber data
244  const int n_modes = 16;
245  double br [n_modes] = { 0.010, 0.080, 0.100, 0.220,
246  0.360, 0.160, 0.070, 0.020,
247  0.015, 0.065, 0.110, 0.280,
248  0.070, 0.240, 0.100, 0.100 };
249 
250  for (int i = 0; i < n_modes; i++) {
251  if (i < 7)
252  br[i] *= proton_frac;
253  else
254  br[i] *= neutron_frac;
255  }
256 
257  // randomly generate a number between 1 and 0
258  double p = flatDist.fire();
259 
260  // loop through all modes, figure out which one our random number corresponds to
261  double threshold = 0;
262  for (int i = 0; i < n_modes; i++) {
263  threshold += br[i];
264  if (p < threshold) {
265  // once we've found our mode, return it!
266  mode = i + 1;
267  return mode;
268  }
269  }
270 
271  // error message, in case the random number selection fails
272  std::cout << "Random selection of final state failed!" << std::endl;
273  exit(1);
274  }
275 
276  // if specific annihilation mode specified, just use that
277  else {
278  int mode = (int) gOptDecayMode;
279  return mode;
280  }
281 }
282 
void RandGen(long int seed)
Definition: AppInit.cxx:30
NeutronOsc(fhicl::ParameterSet const &p)
void beginRun(art::Run &run) override
virtual void ProcessEventRecord(GHepRecord *event_rec) const =0
double E(void) const
Get energy.
Definition: GHepParticle.h:91
void SetOrigin(simb::Origin_t origin)
Definition: MCTruth.h:82
Defines the EventRecordVisitorI interface. Concrete implementations of this interface use the &#39;Visito...
std::string string
Definition: nybbler.cc:12
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
double MinX() const
Returns the world x coordinate of the start of the box.
Definition: BoxBoundedGeo.h:88
Geometry information for a single TPC.
Definition: TPCGeo.h:38
double MaxX() const
Returns the world x coordinate of the end of the box.
Definition: BoxBoundedGeo.h:91
double Mass(void) const
Mass that corresponds to the PDG code.
Particle class.
int SelectAnnihilationMode(int pdg_code)
double Pz(void) const
Get Pz.
Definition: GHepParticle.h:90
GHepStatus_t Status(void) const
Definition: GHepParticle.h:64
art framework interface to geometry description
Definition: Run.h:17
double Px(void) const
Get Px.
Definition: GHepParticle.h:88
int Pdg(void) const
Definition: GHepParticle.h:63
int FirstMother(void) const
Definition: GHepParticle.h:66
Summary information for an interaction.
Definition: Interaction.h:56
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
std::string DetectorName() const
Returns a string with the name of the detector, as configured.
enum genie::ENNBarOscMode NNBarOscMode_t
def move(depos, offset)
Definition: depos.py:107
const Algorithm * GetAlgorithm(const AlgId &algid)
Definition: AlgFactory.cxx:75
double MinZ() const
Returns the world z coordinate of the start of the box.
p
Definition: test.py:223
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
bool PolzIsSet(void) const
void produce(art::Event &e) override
double MaxY() const
Returns the world y coordinate of the end of the box.
const genie::EventRecordVisitorI * mcgen
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
void GetPolarization(TVector3 &polz)
Generated Event Record. It is a GHepRecord object that can accept / be visited by EventRecordVisitorI...
Definition: EventRecord.h:37
void Add(simb::MCParticle const &part)
Definition: MCTruth.h:80
static PDGLibrary * Instance(void)
Definition: PDGLibrary.cxx:57
static AlgFactory * Instance()
Definition: AlgFactory.cxx:64
genie::NNBarOscMode_t gOptDecayMode
double MaxZ() const
Returns the world z coordinate of the end of the box.
#define MF_LOG_DEBUG(id)
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
The GENIE Algorithm Factory.
Definition: AlgFactory.h:39
Event generator information.
Definition: MCTruth.h:32
LArSoft geometry interface.
Definition: ChannelGeo.h:16
double MinY() const
Returns the world y coordinate of the start of the box.
Event Generation using GENIE, cosmics or single particles.
STDHEP-like event record entry that can fit a particle or a nucleus.
Definition: GHepParticle.h:39
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
Event finding and building.
static Interaction * NOsc(int tgt, int annihilation_mode=-1)
NeutronOsc & operator=(NeutronOsc const &)=delete
CLHEP::RandFlat flatDist
double Py(void) const
Get Py.
Definition: GHepParticle.h:89