Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
clideal.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file clideal.cc
1 /*******************************************************************************
2  * Copyright (c) 2018-2019 LongGang Pang, lgpang@qq.com
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and/or associated documentation files (the
6  * "Materials"), to deal in the Materials without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Materials, and to
9  * permit persons to whom the Materials are furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Materials.
14  *
15  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
22  ******************************************************************************/
23 
24 #include <cmath>
25 #include <cstring>
26 #include <ctime>
27 #include <cstdlib>
28 #include <algorithm>
29 #include "include/clideal.h"
30 #include "include/error_msgs.h"
31 
32 namespace clvisc {
33 // number of blocks for reduction on gpus
34 const int REDUCTION_BLOCKS = 64;
35 
36 CLIdeal::CLIdeal(const Config & cfg, std::string device_type,
37  int device_id):cfg_(cfg),
38  backend_(OpenclBackend(device_type, device_id))
39 {
40  tau0_ = cfg.tau0;
41 
42  // set current time to initial time
43  tau_ = tau0_;
44 
45  CompileOption opts_;
46  opts_.KernelIncludePath("clvisc_kernel/");
47  //opts_.Define("EOSI");
48  opts_.Define("EOS_TABLE");
49  opts_.SetFloatConst("TAU0", cfg_.tau0);
50  opts_.SetFloatConst("DT", cfg_.dt);
51  opts_.SetFloatConst("DX", cfg_.dx);
52  opts_.SetFloatConst("DY", cfg_.dy);
53  opts_.SetFloatConst("DZ", cfg_.dz);
54  opts_.SetFloatConst("ETAOS_XMIN", cfg_.etaos_xmin);
55  opts_.SetFloatConst("ETAOS_YMIN", cfg_.etaos_ymin);
56  opts_.SetFloatConst("ETAOS_LEFT_SLOP", cfg_.etaos_left_slop);
57  opts_.SetFloatConst("ETAOS_RIGHT_SLOP", cfg_.etaos_right_slop);
58  cl_real lambda1 = -10.0; // one parameters used for analytical solution checking
59  opts_.SetFloatConst("LAM1", lambda1);
60  opts_.SetIntConst("NX", cfg_.nx);
61  opts_.SetIntConst("NY", cfg_.ny);
62  opts_.SetIntConst("NZ", cfg_.nz);
63  opts_.SetIntConst("NXSKIP", cfg_.nxskip);
64  opts_.SetIntConst("NYSKIP", cfg_.nyskip);
65  opts_.SetIntConst("NZSKIP", cfg_.nzskip);
66  opts_.SetIntConst("BSZ", cfg.block_size);
67 
68  if (backend_.DeviceType() == CL_DEVICE_TYPE_CPU) {
69  opts_.SetIntConst("REDUCTION_BSZ", 1);
70  } else {
71  opts_.SetIntConst("REDUCTION_BSZ", 256);
72  }
73 
74  int SIZE = cfg_.nx * cfg_.ny * cfg_.nz;
75  opts_.SetIntConst("SIZE", SIZE);
76 #ifdef USE_SINGLE_PRECISION
77  opts_.Define("USE_SINGLE_PRECISION");
78 #endif
79  read_eos_table_("data_table/s95_pce165.dat", opts_);
80  compile_option_ = opts_.str();
81  try {
82  // build kernels for hydrodynamic evolution
83  auto prg = backend_.BuildProgram("clvisc_kernel/kernel_ideal.cl", compile_option_);
84  kernel_kt_src_christoffel_ = cl::Kernel(prg, "kt_src_christoffel");
85  kernel_kt_src_alongx_ = cl::Kernel(prg, "kt_src_alongx");
86  kernel_kt_src_alongy_ = cl::Kernel(prg, "kt_src_alongy");
87  kernel_kt_src_alongz_ = cl::Kernel(prg, "kt_src_alongz");
88  kernel_update_ev_ = cl::Kernel(prg, "update_ev");
89  // build kernels to look for maximum energy density
90  auto prg2 = backend_.BuildProgram("clvisc_kernel/kernel_reduction.cl",
92  kernel_reduction_ = cl::Kernel(prg2, "reduction_stage1");
93  } catch (cl::Error & err ){
94  std::cerr<<"Error:"<<err.what()<<"("<<err.err()<<")\n";
95  std::cerr<<"@" << __FILE__ << ":line " << __LINE__ << std::endl;
96  std::cerr<<ErrorMessage(err.err())<<std::endl;
97  throw(err);
98  }
99 }
100 
101 
103  // eos_table stored in fname has the following format:
104  // cs2, ed [GeV/fm^3], pr[GeV/fm^3], T[GeV]
105  std::vector<cl_float4> host_eos_table;
106  std::ifstream fin(fname);
107  cl_float speed_of_sound_square;
108  cl_float pressure;
109  cl_float temperature;
110  cl_float entropy_density;
111  char comments[256];
112  if (fin.is_open()) {
113  fin.getline(comments, 256);
114  while (fin.good()) {
115  fin >> speed_of_sound_square >> pressure >> temperature >> entropy_density;
116  if (fin.eof()) break; // eof() repeat the last line
117  host_eos_table.push_back((cl_float4){{speed_of_sound_square,
118  pressure, temperature, entropy_density}});
119  }
120  } else {
121  std::cerr<<"@" << __FILE__ << ":line " << __LINE__ << std::endl;
122  throw std::runtime_error("Failed to open equation of state table" + fname);
123  }
124 
125  bool read_only = true;
126  size_t width = 1555;
127  size_t height = 100;
128 
130  width, height, read_only);
131  opts_.SetFloatConst("EOS_ED_START", 0.0);
132  opts_.SetFloatConst("EOS_ED_STEP", 0.002);
133  opts_.SetIntConst("EOS_NUM_ED", 155500);
134  opts_.SetIntConst("EOS_NUM_OF_ROWS", height);
135  opts_.SetIntConst("EOS_NUM_OF_COLS", width);
136 }
137 
139  bool read_only_option = false;
140  for (int i = 0; i < 3; i++) {
141  d_ev_[i] = backend_.CreateBufferByCopyVector(h_ev_, read_only_option);
142  }
143  d_src_ = backend_.CreateBufferByCopyVector(h_ev_, read_only_option);
144 
146 }
147 
148 // read initial energy density from external vector
149 template <typename ValueType>
150 void CLIdeal::read_ini(const std::vector<ValueType> & ed) {
151  h_ev_.clear();
152  for (size_t idx = 0; idx < ed.size(); idx++) {
153  h_ev_.push_back((cl_real4){{static_cast<cl_real>(ed.at(idx)), 0.0f, 0.0f, 0.0f}});
154  }
156 }
157 
158 // read initial ed, vx, vy, vz vector
159 template <typename ValueType>
160 void CLIdeal::read_ini(const std::vector<ValueType> & ed,
161  const std::vector<ValueType> & vx,
162  const std::vector<ValueType> & vy,
163  const std::vector<ValueType> & vz)
164 {
165  h_ev_.clear();
166  for (size_t idx = 0; idx < ed.size(); idx++) {
167  h_ev_.push_back((cl_real4){{static_cast<cl_real>(ed.at(idx)), \
168  static_cast<cl_real>(vx.at(idx)), \
169  static_cast<cl_real>(vy.at(idx)), \
170  static_cast<cl_real>(vz.at(idx))}});
171  }
173 }
174 
175 
176 // step update for Runge-Kutta method, step = {1, 2}
178  auto size = cfg_.nx * cfg_.ny * cfg_.nz;
182  // notice: it is important to cast tau_ from double to float explicitly
183  // otherwise the program will produce wrong results
184  kernel_kt_src_christoffel_.setArg(3, static_cast<cl_real>(tau_));
187  cl::NDRange(size), // global size
188  cl::NullRange); // local size
189 
190  // update along x direction
194  kernel_kt_src_alongx_.setArg(3, static_cast<cl_real>(tau_));
196  cl::NDRange(cfg_.block_size, cfg_.ny, cfg_.nz), // global size
197  cl::NDRange(cfg_.block_size, 1, 1)); // local size
198 
199  // update along y direction
203  kernel_kt_src_alongy_.setArg(3, static_cast<cl_real>(tau_));
205  cl::NDRange(cfg_.nx, cfg_.block_size, cfg_.nz), // global size
206  cl::NDRange(1, cfg_.block_size, 1)); // local size
207 
208  if (cfg_.nz != 1) {
209  // update along spacetime-rapidity direction
213  kernel_kt_src_alongz_.setArg(3, static_cast<cl_real>(tau_));
215  cl::NDRange(cfg_.nx, cfg_.ny, cfg_.block_size), // global size
216  cl::NDRange(1, 1, cfg_.block_size)); // local size
217  }
218 
220  kernel_update_ev_.setArg(0, d_ev_[3-step]);
224  kernel_update_ev_.setArg(4, static_cast<cl_real>(tau_));
225  kernel_update_ev_.setArg(5, step);
227  cl::NDRange(size), // global size
228  cl::NullRange); // local size
229 
230  //backend_.enqueue_copy(d_src_, h_ev_);
231  //std::cout << h_ev_.at(0).s[0] << " ";
232  //std::cout << std::endl;
233 }
234 
235 // return the maximum energy density of the QGP
236 // will be used to stop hydro
238  int size = cfg_.nx * cfg_.ny * cfg_.nz;
241  kernel_reduction_.setArg(2, size);
242  auto global_size = cl::NDRange(256*REDUCTION_BLOCKS);
243  auto local_size = cl::NDRange(256);
244 
245  if (backend_.DeviceType() == CL_DEVICE_TYPE_CPU) {
246  global_size = cl::NDRange(REDUCTION_BLOCKS);
247  local_size = cl::NDRange(1);
248  }
249 
250  backend_.enqueue_run(kernel_reduction_, global_size, local_size);
251 
252  std::vector<cl_real> h_submax(REDUCTION_BLOCKS);
253  backend_.enqueue_copy(d_submax_, h_submax);
254  return *std::max_element(h_submax.begin(), h_submax.end());
255 }
256 
257 // run hydrodynamic evolution for one time step
258 // return the excution time on device
260  half_step_(1);
261  tau_ += cfg_.dt;
262  half_step_(2);
263 }
264 
265 // predict the first half step; usful to get initial fluid velocity
266 // for viscous hydrodynamics
268  half_step_(1);
269 }
270 
272  int max_loops = 2000;
273  float total_exec_time = 0.0;
274  try {
275  double total_exec_time = 0.0;
276  std::time_t timer1, timer2;
277  std::time(&timer1);
278  for (int step=0; step < max_loops; step++) {
279  one_step();
280  if (step % cfg_.ntskip == 0) {
281  float max_ed = max_energy_density();
282  std::time(&timer2);
283  float time_diff = std::difftime(timer2, timer1);
284  std::cout << "tau = " << tau_ << " fm; ";
285  std::cout << "max_ed = " << max_ed << " ";
286  std::cout << "Total computing time: " << time_diff << " s; ";
287  std::cout << std::endl;
288  if ( max_ed < 0.5 ) break;
289  }
290  }
291  std::cout << "Total computing time: " << total_exec_time << " s; ";
292  } catch (cl::Error & err) {
293  std::cout << err.what() << " " << err.err() << std::endl;
294  std::cerr<<"@" << __FILE__ << ":line " << __LINE__ << std::endl;
295  std::cerr<<ErrorMessage(err.err())<<std::endl;
296  throw(err);
297  }
298 }
299 
301  return backend_;
302 }
303 
305  return compile_option_;
306 }
307 
308 
310 }
311 
312 
313 
314 template void CLIdeal::read_ini(const std::vector<float> & ed);
315 template void CLIdeal::read_ini(const std::vector<double> & ed);
316 
317 template void CLIdeal::read_ini(const std::vector<float> & ed,
318  const std::vector<float> & vx,
319  const std::vector<float> & vy,
320  const std::vector<float> & vz);
321 
322 template void CLIdeal::read_ini(const std::vector<double> & ed,
323  const std::vector<double> & vx,
324  const std::vector<double> & vy,
325  const std::vector<double> & vz);
326 
327 
328 } // end namespace clvisc