Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
collider.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file collider.cxx
1 // TRENTO: Reduced Thickness Event-by-event Nuclear Topology
2 // Copyright 2015 Jonah E. Bernhard, J. Scott Moreland
3 // TRENTO3D: Three-dimensional extension of TRENTO by Weiyao Ke
4 // MIT License
5 
6 #include "collider.h"
7 
8 #include <cmath>
9 #include <string>
10 #include <vector>
11 
12 #include <boost/program_options/variables_map.hpp>
13 
14 #include "fwd_decl.h"
15 #include "nucleus.h"
16 #include <iostream>
17 
18 namespace trento {
19 
20 namespace {
21 
22 // Helper functions for Collider ctor.
23 
24 // Create one nucleus from the configuration.
25 NucleusPtr create_nucleus(const VarMap& var_map, std::size_t index) {
26  const auto& species = var_map["projectile"]
27  .as<std::vector<std::string>>().at(index);
28  const auto& nucleon_dmin = var_map["nucleon-min-dist"].as<double>();
29  const auto& nucleon_width = var_map["nucleon-width"].as<double>();
30  return Nucleus::create(species, nucleon_width, nucleon_dmin);
31 }
32 
33 // Determine the maximum impact parameter. If the configuration contains a
34 // non-negative value for bmax, use it; otherwise, fall back to the minimum-bias
35 // default.
36 double determine_bmax(const VarMap& var_map,
37  const Nucleus& A, const Nucleus& B, const NucleonProfile& profile) {
38  auto bmax = var_map["b-max"].as<double>();
39  if (bmax < 0.)
40  bmax = A.radius() + B.radius() + profile.max_impact();
41  return bmax;
42 }
43 
44 // Determine the asymmetry parameter (Collider::asymmetry_) for a pair of
45 // nuclei. It's just rA/(rA+rB), falling back to 1/2 if both radii are zero
46 // (i.e. for proton-proton).
47 double determine_asym(const Nucleus& A, const Nucleus& B) {
48  double rA = A.radius();
49  double rB = B.radius();
50  double sum = rA + rB;
51  if (sum < 0.1)
52  return 0.5;
53  else
54  return rA/sum;
55 }
56 
57 } // unnamed namespace
58 
59 // Lots of members to initialize...
60 // Several helper functions are defined above.
61 Collider::Collider(const VarMap& var_map)
62  : nucleusA_(create_nucleus(var_map, 0)),
63  nucleusB_(create_nucleus(var_map, 1)),
64  nucleon_profile_(var_map),
65  nevents_(var_map["number-events"].as<int>()),
66  ntrys_(0),
67  bmin_(var_map["b-min"].as<double>()),
68  bmax_(determine_bmax(var_map, *nucleusA_, *nucleusB_, nucleon_profile_)),
69  npartmin_(var_map["npart-min"].as<int>()),
70  npartmax_(var_map["npart-max"].as<int>()),
71  stotmin_(var_map["s-min"].as<double>()),
72  stotmax_(var_map["s-max"].as<double>()),
73  asymmetry_(determine_asym(*nucleusA_, *nucleusB_)),
74  event_(var_map),
75  output_(var_map),
76  with_ncoll_(var_map["ncoll"].as<bool>())
77 {
78  // Constructor body begins here.
79  // Set random seed if requested.
80  auto seed = var_map["random-seed"].as<int64_t>();
81  if (seed > 0)
82  random::engine.seed(static_cast<random::Engine::result_type>(seed));
83 }
84 
85 // See header for explanation.
86 Collider::~Collider() = default;
87 
89  // The main event loop.
90  for (int n = 0; n < nevents_; ++n) {
91  if (n%1000 == 0 && n!=0) std::cout<< "# "<< n << " events generated" << std::endl;
92  // Sampling the impact parameter also implicitly prepares the nuclei for
93  // event computation, i.e. by sampling nucleon positions and participants.
94 
95  // WK: an extra do-while loop, sample events, until it meets the Npart or
96  // Entropy cut provided from command lines
97  bool fullfil_Npart_cut=false, fullfil_Entropy_cut=false;
98  double b;
99  do{
100  b = sample_impact_param();
101  // Pass the prepared nuclei to the Event. It computes the entropy profile
102  // (thickness grid) and other event observables.
104  fullfil_Npart_cut = (npartmin_ < event_.npart())
105  && (event_.npart() <= npartmax_);
106  fullfil_Entropy_cut = (stotmin_ < event_.multiplicity())
107  && (event_.multiplicity() <= stotmax_);
108  }while( (!fullfil_Npart_cut) || (!fullfil_Entropy_cut) );
109  // Write event data.
110  output_(n, b, event_);
111  records this_event;
112  this_event.i = n;
113  this_event.b = b;
114  this_event.npart = event_.npart();
115  this_event.mult = event_.multiplicity();
116  all_records_.push_back(this_event);
117  }
118  double cross_section = nevents_*M_PI*(bmax_*bmax_ - bmin_*bmin_)/ntrys_;
119  double cross_section_err = cross_section/std::sqrt(1.*nevents_);
120  //std::cout << "# cross-section = " << cross_section
121  // << " +/- " << cross_section_err <<" [fm^2]" << std::endl;
122 }
123 
125  // Sample impact parameters until at least one nucleon-nucleon pair
126  // participates. The bool 'collision' keeps track -- it is effectively a
127  // logical OR over all possible participant pairs.
128  double b;
129  bool collision = false;
130 
131  do {
132  // Sample b from P(b)db = 2*pi*b.
133  b = std::sqrt(bmin_ * bmin_ + (bmax_ * bmax_ - bmin_ * bmin_) * random::canonical<double>());
134 
135  // Offset each nucleus depending on the asymmetry parameter (see header).
136  nucleusA_->sample_nucleons(asymmetry_ * b);
137  nucleusB_->sample_nucleons((asymmetry_ - 1.) * b);
138 
139  // Check each nucleon-nucleon pair.
140  for (auto&& A : *nucleusA_) {
141  for (auto&& B : *nucleusB_) {
142  bool AB_collide = nucleon_profile_.participate(A, B);
143 
144  if (with_ncoll_) {
145  // WK: only init Ncoll and Ncoll density at the first binary collision:
146  if (AB_collide && (!collision) ) event_.clear_TAB();
147  // WK: to calculate binary collision denstiy, each collision
148  // contribute independently its Tpp. Therefore, if one pair collide,
149  // it calls the event object to accumulate Tpp to the Ncoll density
150  // Ncoll density = Sum Tpp
151  if (AB_collide) event_.accumulate_TAB(A, B, nucleon_profile_);
152  }
153 
154  // update collision flag
155  collision = AB_collide || collision;
156  }
157  }
158  ntrys_ ++;
159  } while (!collision);
160 
161  return b;
162 }
163 
164 } // namespace trento