Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TrentoInitial.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TrentoInitial.cc
1 /*******************************************************************************
2  * Copyright (c) The JETSCAPE Collaboration, 2018
3  *
4  * Modular, task-based framework for simulating all aspects of heavy-ion collisions
5  *
6  * For the list of contributors see AUTHORS.
7  *
8  * Report issues at https://github.com/JETSCAPE/JETSCAPE/issues
9  *
10  * or via email to bugs.jetscape@gmail.com
11  *
12  * Distributed under the GNU General Public License 3.0 (GPLv3 or later).
13  * See COPYING for details.
14  ******************************************************************************/
15 
16 #include <cstdlib>
17 #include <sstream>
18 #include <fstream>
19 #include <boost/bind.hpp>
20 #include <boost/tokenizer.hpp>
21 #include <algorithm>
22 #include <functional>
23 #include <string>
24 #include "JetScapeLogger.h"
25 
26 #include "TrentoInitial.h"
27 
28 namespace Jetscape {
29 
30 // Register the module with the base class
31 RegisterJetScapeModule<TrentoInitial> TrentoInitial::reg("TrentoInitial");
32 
33 namespace {
40 std::vector<std::string> tokenize(const std::string &input) {
41  typedef boost::escaped_list_separator<char> separator_type;
42  separator_type separator("\\", // The escape characters.
43  "= ", // The separator characters.
44  "\"\'"); // The quote characters.
45 
46  // Tokenize the intput.
47  boost::tokenizer<separator_type> tokens(input, separator);
48 
49  // Copy non-empty tokens from the tokenizer into the result.
50  std::vector<std::string> result;
51  copy_if(tokens.begin(), tokens.end(), std::back_inserter(result),
52  !boost::bind(&std::string::empty, _1));
53  return result;
54 }
55 } // end namespace
56 
57 // See header for explanation.
59 
61 
63  JSINFO << " Initialzie TRENTo initial condition ";
64 
65  // TRENTO OPTION DESK
66  using namespace trento;
67  using OptDesc = po::options_description;
68  using VecStr = std::vector<std::string>;
69  OptDesc main_opts{};
70  main_opts.add_options()(
71  "projectile",
72  po::value<VecStr>()
73  ->required()
74  ->notifier( // use a lambda to verify there are exactly two projectiles
75  [](const VecStr &projectiles) {
76  if (projectiles.size() != 2)
77  throw po::required_option{"projectile"};
78  }),
79  "projectile symbols")("number-events", po::value<int>()->default_value(1),
80  "number of events");
81 
82  // Make all main arguments positional.
83  po::positional_options_description positional_opts{};
84  positional_opts.add("projectile", 2).add("number-events", 1);
85 
86  using VecPath = std::vector<fs::path>;
87  OptDesc general_opts{"general options"};
88  general_opts.add_options()("help,h", "show this help message and exit")(
89  "version", "print version information and exit")(
90  "bibtex", "print bibtex entry and exit")
91  // ("default-config", "print a config file with default settings and exit")
92  ("config-file,c", po::value<VecPath>()->value_name("FILE"),
93  "configuration file\n(can be passed multiple times)");
94 
95  OptDesc output_opts{"output options"};
96  output_opts.add_options()("quiet,q", po::bool_switch(),
97  "do not print event properties to stdout")(
98  "output,o", po::value<fs::path>()->value_name("PATH"),
99  "HDF5 file or directory for text files")(
100  "no-header", po::bool_switch(), "do not write headers to text files");
101 
102  OptDesc phys_opts{"physical options"};
103  phys_opts.add_options()(
104  "reduced-thickness,p",
105  po::value<double>()->value_name("FLOAT")->default_value(0., "0"),
106  "reduced thickness parameter")(
107  "fluctuation,k",
108  po::value<double>()->value_name("FLOAT")->default_value(1., "1"),
109  "gamma fluctuation shape parameter")(
110  "nucleon-width,w",
111  po::value<double>()->value_name("FLOAT")->default_value(.5, "0.5"),
112  "Gaussian nucleon width [fm]")(
113  "nucleon-min-dist,d",
114  po::value<double>()->value_name("FLOAT")->default_value(0., "0"),
115  "minimum nucleon-nucleon distance [fm]")(
116  "mean-coeff,m",
117  po::value<double>()->value_name("FLOAT")->default_value(1., "1."),
118  "rapidity mean coefficient")(
119  "std-coeff,s",
120  po::value<double>()->value_name("FLOAT")->default_value(3., "3."),
121  "rapidity std coefficient")(
122  "skew-coeff,t",
123  po::value<double>()->value_name("FLOAT")->default_value(0., "0."),
124  "rapidity skew coefficient")(
125  "skew-type,r", po::value<int>()->value_name("INT")->default_value(1, "1"),
126  "rapidity skew type: 1: relative, 2: absolute, other: no skew")(
127  "jacobian,j",
128  po::value<double>()->value_name("FLOAT")->default_value(0.8, "0.8"),
129  "<pt>/<mt> used in Jacobian")(
130  "normalization,n",
131  po::value<double>()->value_name("FLOAT")->default_value(1., "1"),
132  "normalization factor");
133 
134  OptDesc coll_opts{"collision options"};
135  coll_opts.add_options()(
136  "beam-energy,e",
137  po::value<double>()->value_name("FLOAT")->default_value(2760, "2760"),
138  "collision beam energy sqrt(s) [GeV], initializes cross section")(
139  "cross-section,x",
140  po::value<double>()->value_name("FLOAT")->default_value(-1, "off"),
141  "manual inelastic nucleon-nucleon cross section sigma_NN [fm^2]")(
142  "b-min", po::value<double>()->value_name("FLOAT")->default_value(0., "0"),
143  "minimum impact parameter [fm]")(
144  "b-max",
145  po::value<double>()->value_name("FLOAT")->default_value(-1., "auto"),
146  "maximum impact parameter [fm]")(
147  "npart-min", po::value<int>()->value_name("INT")->default_value(0, "0"),
148  "minimum Npart cut")("npart-max",
149  po::value<int>()->value_name("INT")->default_value(
150  std::numeric_limits<int>::max(), "INT_MAX"),
151  "maximum Npart cut")(
152  "s-min", po::value<double>()->value_name("FLOAT")->default_value(0., "0"),
153  "minimum entropy cut")(
154  "s-max",
155  po::value<double>()->value_name("FLOAT")->default_value(
156  std::numeric_limits<double>::max(), "DOUBLE_MAX"),
157  "maxmimum entropy cut")(
158  "random-seed",
159  po::value<int64_t>()->value_name("INT")->default_value(-1, "auto"),
160  "random seed")(
161  "ncoll,b", po::bool_switch(),
162  "calculate # of binary collision and binary collision density");
163 
164  OptDesc grid_opts{"grid options"};
165  grid_opts.add_options()(
166  "xy-max",
167  po::value<double>()->value_name("FLOAT")->default_value(10., "10.0"),
168  "xy max [fm]\n(transverse grid from -max to +max)")(
169  "xy-step",
170  po::value<double>()->value_name("FLOAT")->default_value(0.2, "0.2"),
171  "transverse step size [fm]")(
172  "eta-max",
173  po::value<double>()->value_name("FLOAT")->default_value(0.0, "0.0"),
174  "pseudorapidity max \n(eta grid from -max to +max)")(
175  "eta-step",
176  po::value<double>()->value_name("FLOAT")->default_value(0.5, "0.5"),
177  "pseudorapidity step size");
178 
179  // Make a meta-group containing all the option groups except the main
180  // positional options (don't want the auto-generated usage info for those).
181  OptDesc usage_opts{};
182  usage_opts.add(general_opts)
183  .add(output_opts)
184  .add(phys_opts)
185  .add(coll_opts)
186  .add(grid_opts);
187 
188  // Now a meta-group containing _all_ options.
189  OptDesc all_opts{};
190  all_opts.add(usage_opts).add(main_opts);
191 
192  // Will be used several times.
193  const std::string usage_str{
194  "usage: trento [options] projectile projectile [number-events = 1]\n"};
195  const std::string usage_str3d{
196  "To operate in 3D mode, make sure --eta-max is nonzero.\n"};
197 
198  // NOW LETS FILL IN THE OPTION DESK
199  auto phy_opts = GetXMLElement({"IS", "Trento", "PhysicsInputs"});
200  auto cut_opts = GetXMLElement({"IS", "Trento", "CutInputs"});
201  auto trans_opts = GetXMLElement({"IS", "Trento", "TransInputs"});
202  auto longi_opts = GetXMLElement({"IS", "Trento", "LongiInputs"});
203 
204  double xymax = GetXMax(), dxy = GetXStep();
205  double etamax = GetZMax(), deta = GetZStep();
206 
207  auto random_seed = (*GetMt19937Generator())();
208  //TEMPORARY FOR TESTING
209  //auto random_seed = 1;
210  //TEMPORARY
211  JSINFO << "Random seed used for Trento " << random_seed;
212 
213  std::string proj(phy_opts->Attribute("projectile"));
214  std::string targ(phy_opts->Attribute("target"));
215  double sqrts = std::atof(phy_opts->Attribute("sqrts"));
216  double cross_section = std::atof(phy_opts->Attribute("cross-section"));
217  double normalization = std::atof(phy_opts->Attribute("normalization"));
218 
219  int cen_low = std::atoi(cut_opts->Attribute("centrality-low"));
220  int cen_high = std::atoi(cut_opts->Attribute("centrality-high"));
221 
222  double p = std::atof(trans_opts->Attribute("reduced-thickness"));
223  double k = std::atof(trans_opts->Attribute("fluctuation"));
224  double w = std::atof(trans_opts->Attribute("nucleon-width"));
225  double d = std::atof(trans_opts->Attribute("nucleon-min-dist"));
226 
227  double mean = std::atof(longi_opts->Attribute("mean-coeff"));
228  double var = std::atof(longi_opts->Attribute("std-coeff"));
229  double skew = std::atof(longi_opts->Attribute("skew-coeff"));
230  int skew_type = std::atof(longi_opts->Attribute("skew-type"));
231  double J = std::atof(longi_opts->Attribute("jacobian"));
232 
233  std::string options1 =
234  +" --random-seed " + std::to_string(random_seed) + " --cross-section " +
235  std::to_string(cross_section) + " --beam-energy " +
236  std::to_string(sqrts) + " --reduced-thickness " + std::to_string(p) +
237  " --fluctuation " + std::to_string(k) + " --nucleon-width " +
238  std::to_string(w) + " --nucleon-min-dist " + std::to_string(d) +
239  " --mean-coeff " + std::to_string(mean) + " --std-coeff " +
240  std::to_string(var) + " --skew-coeff " + std::to_string(skew) +
241  " --skew-type " + std::to_string(skew_type) + " --jacobian " +
242  std::to_string(J) + " --quiet ";
243  std::string options2 = " --normalization " + std::to_string(normalization) +
244  " --ncoll " // calcualte # of binary collision
245  + " --xy-max " + std::to_string(xymax) +
246  " --xy-step " + std::to_string(dxy) + " --eta-max " +
247  std::to_string(etamax) + " --eta-step " +
248  std::to_string(deta);
249  // Handle centrality table, not normzlized, default grid, 2D (fast) !!!
250  std::string cmd_basic = proj + " " + targ + " 10000 " + options1;
251  VarMap var_map_basic{};
252  po::store(po::command_line_parser(tokenize(cmd_basic))
253  .options(all_opts)
254  .positional(positional_opts)
255  .run(),
256  var_map_basic);
257 
258  std::string options_cut = "";
259  if (cen_low == 0 && cen_high == 100) {
260  JSINFO << "TRENTo Minimum Biased Mode Generates 0-100(%) of nuclear "
261  "inelastic cross-section";
262  } else {
263  auto Ecut = GenCenTab(proj, targ, var_map_basic, cen_low, cen_high);
264  double Ehigh = Ecut.first * normalization; // rescale the cut
265  double Elow = Ecut.second * normalization; // rescale the cut
266 
267  JSINFO << "The total energy density cut for centrality = [" << cen_low
268  << ", " << cen_high << "] (%) is:";
269  JSINFO << Elow << "<dE/deta(eta=0)<" << Ehigh;
270  options_cut = " --s-max " + std::to_string(Ehigh) + " --s-min " +
271  std::to_string(Elow);
272  // Set trento configuration
273  }
274  std::string cmd =
275  proj + " " + targ + " 1 " + options1 + options2 + options_cut;
276  JSINFO << cmd;
277  VarMap var_map{};
278  po::store(po::command_line_parser(tokenize(cmd))
279  .options(all_opts)
280  .positional(positional_opts)
281  .run(),
282  var_map);
283  TrentoGen_ = std::make_shared<trento::Collider>(var_map);
284  SetRanges(xymax, xymax, etamax);
285  SetSteps(dxy, dxy, deta);
286  JSINFO << "TRENTo set";
287 }
288 
290  return r1.mult > r2.mult;
291 }
292 
293 std::pair<double, double> TrentoInitial::GenCenTab(std::string proj,
294  std::string targ,
295  VarMap var_map, int cL,
296  int cH) {
297  // Terminate for nonsense
298  if (cL < 0 || cL > 100 || cH < 0 || cH > 100 || cH < cL) {
299  JSWARN << "Wrong centrality cuts! To be terminated.";
300  exit(-1);
301  }
302  // These are all the parameters that could change the shape of centrality tables
303  // Normalization prefactor parameter is factorized
304  // They form a table header
305  trento::Collider another_collider(var_map);
306  double beamE = var_map["beam-energy"].as<double>();
307  double xsection = var_map["cross-section"].as<double>();
308  double pvalue = var_map["reduced-thickness"].as<double>();
309  double fluct = var_map["fluctuation"].as<double>();
310  double nuclw = var_map["nucleon-width"].as<double>();
311  double dmin = var_map["nucleon-min-dist"].as<double>();
312  char buffer[512];
313  std::sprintf(buffer, "%s-%s-E-%1.0f-X-%1.2f-p-%1.2f-k-%1.2f-w-%1.2f-d-%1.2f",
314  proj.c_str(), targ.c_str(), beamE, xsection, pvalue, fluct,
315  nuclw, dmin);
316  std::string header(buffer);
317  JSINFO << "TRENTO centrality table header: " << header;
318  // Create headering string hash tage for these parameter combination
319  // Use this tag as a unique table filename for this specific parameter set
320  std::hash<std::string> hash_function;
321  size_t header_hash = hash_function(header);
322  JSINFO << "Hash tag for this header: " << header_hash;
323  // create dir incase it does not exist
324  std::system("mkdir -p ./trento_data");
325  char filename[512];
326  std::sprintf(filename, "./trento_data/%zu", header_hash);
327  // Step1: check it a table exist
328  std::ifstream infile(filename);
329  double Etab[101];
330  double buff1, buff2;
332  if (infile.good()) {
333  JSINFO << "The required centrality table exists. Load the table.";
334  int i = 0;
335  while (std::getline(infile, line)) {
336  if (line[0] != '#') {
337  std::istringstream iss(line);
338  iss >> buff1 >> buff2 >> Etab[i];
339  i++;
340  }
341  }
342  infile.close();
343  } else {
344  JSINFO << "TRENTo is generating new centrality table for this new "
345  "parameter set";
346  JSINFO << "It may take 10(s) to 1(min).";
347 
348  another_collider.run_events();
349  // Get all records and sort according to totoal energy
350  auto event_records = another_collider.all_records();
351  std::sort(event_records.begin(), event_records.end(), compare_E);
352  // write centrality table
353  int nstep = std::ceil(event_records.size() / 100);
354  std::ofstream fout(filename);
355  fout << "#\tproj\ttarj\tsqrts\tx\tp\tk\tw\td\n"
356  << "#\t" << proj << "\t" << targ << "\t" << beamE << "\t" << xsection
357  << "\t" << pvalue << "\t" << fluct << "\t" << nuclw << "\t" << dmin
358  << "\n"
359  << "#\tcen_L\tcen_H\tun-normalized total density\n";
360  Etab[0] = 1e10;
361  for (int i = 1; i < 100; i += 1) {
362  auto ee = event_records[i * nstep];
363  fout << i - 1 << "\t" << i << "\t" << ee.mult << std::endl;
364  Etab[i] = ee.mult;
365  }
366  auto ee = event_records.back();
367  fout << 99 << "\t" << 100 << "\t" << ee.mult << std::endl;
368  Etab[100] = ee.mult;
369  fout.close();
370  }
371  JSINFO << "#########" << Etab[cL] << " " << Etab[cH];
372  return std::make_pair(Etab[cL], Etab[cH]);
373 }
374 
376  JSINFO << " Exec TRENTo initial condition ";
377  TrentoGen_->run_events();
378 
379  JSINFO << " TRENTo event info: ";
380  auto tmp_event = TrentoGen_->expose_event();
381  info_.impact_parameter = TrentoGen_->all_records().back().b;
382  info_.num_participant = tmp_event.npart();
383  info_.num_binary_collisions = tmp_event.ncoll();
384  info_.total_entropy = tmp_event.multiplicity();
385  info_.ecc = tmp_event.eccentricity();
386  info_.psi = tmp_event.participant_plane();
387  info_.xmid =
388  -GetXMax() + tmp_event.mass_center_index().first * tmp_event.dxy();
389  info_.ymid =
390  -GetYMax() + tmp_event.mass_center_index().second * tmp_event.dxy();
391  JSINFO << "b\tnpart\tncoll\tET\t(x-com, y-com) (fm)";
392  JSINFO << info_.impact_parameter << "\t" << info_.num_participant << "\t"
393  << info_.num_binary_collisions << "\t" << info_.total_entropy << "\t"
394  << "(" << info_.xmid << ", " << info_.ymid << ")";
395 
396  JSINFO << " Load TRENTo density and ncoll density to JETSCAPE memory ";
397  auto density_field = tmp_event.density_grid();
398  auto ncoll_field = tmp_event.TAB_grid();
399  JSINFO << density_field.num_elements() << " density elements";
400  for (int i = 0; i < density_field.num_elements(); i++) {
401  entropy_density_distribution_.push_back(density_field.data()[i]);
402  }
403  JSINFO << ncoll_field.num_elements() << " ncoll elements";
404  for (int i = 0; i < ncoll_field.num_elements(); i++) {
405  num_of_binary_collisions_.push_back(ncoll_field.data()[i]);
406  }
407  JSINFO << " TRENTO event generated and loaded ";
408 }
409 
411  VERBOSE(2) << " : Finish creating initial condition ";
414 }
415 
416 } // end namespace Jetscape