ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4FastPathHadronicCrossSection.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4FastPathHadronicCrossSection.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
27 #include "G4ios.hh"
28 #include "G4DynamicParticle.hh"
29 #include "G4Material.hh"
31 #include <vector>
32 #if defined(WIN32)
33  //Needed for M_LN10
34  #define _USE_MATH_DEFINES // for C++
35  #include <math.h>
36 #endif
37 #include <cmath>
38 #include <array>
39 
40 #ifdef FPDEBUG
41 #define DBG( msg ) G4cout<< msg <<G4endl;
42 #define DUMP() G4cout<< <<G4endl;
43 #else
44 #define DBG(msg)
45 #define DUMP()
46 #endif
47 
48 using namespace G4FastPathHadronicCrossSection;
49 
50 //Utility functions used to perform fast-path calculations.
51 //See later for details
52 namespace {
53  struct Point_t {
54  double e;
55  double xs;
56  };
57  int simplify_function(G4double tolerance,
58  std::vector<Point_t> & raw_data,
59  std::vector<Point_t> & simplified_data);
60  void RemoveBias( std::vector <Point_t> &,
61  std::vector <Point_t> &,
62  std::vector <Point_t> &);
63 }
64 
66  particle(part),material(mat),min_cutoff(min),physicsVector(nullptr)
67  {
68  DBG("Initializing a fastPathEntry");
69 #ifdef FPDEBUG
70  count = 0;
71  slowpath_sum=0.;
72  max_delta=0.;
73  min_delta=0.;
74  sum_delta=0.;
75  sum_delta_square=0.;
76 #endif
77 }
78 
80 {
81  DBG("Deleting fastPathEntry");
82  DBG("Dumping status for: "<<(particle?particle->GetParticleName():"PART_NONE")<<" "\
83  <<(material?material->GetName():"MAT_NONE")<<" min_cutoff:"<<min_cutoff<<" "\
84  <<" count:"<<count<<" slowpath_sum:"<<slowpath_sum<<" max_delta:"<<max_delta\
85  <<" min_delta"<<min_delta<<" sum_delta"<<sum_delta<<" sum_delta_squared:"<<sum_delta_square);
86  delete physicsVector;
87 }
88 
89 //namespace {
90 // static inline G4double exp10(G4double x) {
91 // return std::exp( M_LN10*x);
92 // }
93 //}
94 
96 {
97  //Check this method is called when G4CrossSectionDataStore is in the correct state:
98  // FastPath is enabled and we are indeed initializing
101  using std::log10;
102  std::vector<Point_t> data_in;
103  const fastPathParameters& params = xsds->GetFastPathParameters();
104  G4double xs;
105 
106  //G4double max_query = params.queryMax;
107  //G4int count = sampleCount;
108  //G4double tol = dpTol;
109 
110  //Shift so max and min are >= 1.
111  //Don't forget to shift back before computing XS
112  G4double min = params.sampleMin;
113  G4double max = params.sampleMax;
114  G4double shift = 0.0;
115  if(min < 1.0){
116  shift = 1.0 - min;
117  }
118  min += shift;
119  max += shift;
120 
121  G4double log_max = std::log10(params.sampleMax);
122  G4double log_min = std::log10(params.sampleMin);
123  G4double log_step = (log_max-log_min)/(1.0*params.sampleCount);
124 
125  G4double max_xs = 0.0;
126 
127  //Utility particle to calculate XS, with 0 kin energy by default
128  static const G4ThreeVector constDirection(0.,0.,1.);
129  G4DynamicParticle* probingParticle = new G4DynamicParticle( particle , constDirection , 0 );
130 
131  //add the cutoff energy
132  probingParticle->SetKineticEnergy(min_cutoff);
133  //Sample cross-section
134  xs = xsds->GetCrossSection(probingParticle,material);
135  data_in.push_back({min_cutoff,xs});
136 
137  G4double currEnergy = 0.0;
138  //log results
139  auto exp10 = [](G4double x){ return std::exp( M_LN10*x); };
140  for(G4double log_currEnergy = log_min; log_currEnergy < log_max; log_currEnergy += log_step){
141  currEnergy = exp10(log_currEnergy) - shift;
142  if (currEnergy < min_cutoff) continue;
143  probingParticle->SetKineticEnergy(currEnergy);
144  xs=xsds->GetCrossSection(probingParticle,material);
145  //G4cout << "PRUTH: energy value " << currEnergy << ", XS value " << xs << G4endl;
146  if (xs > max_xs) max_xs = xs;
147  data_in.push_back({currEnergy,xs});
148  } // --- end of loop i
149  probingParticle->SetKineticEnergy(max-shift);
150  xs = xsds->GetCrossSection(probingParticle,material);
151  data_in.push_back({max-shift,xs});
152 
153  G4double tol = max_xs * 0.01;
154  std::vector<Point_t> decimated_data;
155  simplify_function(tol, data_in, decimated_data);
156  std::vector<Point_t> debiased_data;
157  RemoveBias( data_in, decimated_data, debiased_data);
158  if ( physicsVector != nullptr ) delete physicsVector;
159  physicsVector = new XSParam(decimated_data.size());
160  G4int physicsVectorIndex = 0;
161  for(size_t i = 0; i < decimated_data.size(); i++){
162  physicsVector->PutValue(physicsVectorIndex++, decimated_data[i].e, decimated_data[i].xs);
163  }
164  //xsds->DumpFastPath(particle,material,G4cout);
165 }
166 
168  particle(pname),material(mat),fastPath(nullptr),
169  energy(-1.),crossSection(-1.)
170 {
171  DBG("Initializing cache entry");
172 #ifdef FPDEBUG
173  cacheHitCount = 0;
174  initCyclesFastPath=0;
175  invocationCountSlowPath=0;
176  totalCyclesSlowPath=0;
177  invocationCountFastPath=0;
178  totalCyclesFastPath=0;
179  invocationCountTriedOneLineCache=0;
180  invocationCountOneLineCache=0;
181 #endif
182 }
183 
185 {
186  DBG("Deleting cache entry");
187  DBG(particle<<" "<<material<<" ("<<(material?material->GetName():"MAT_NONE")<<") "<<" "\
188  <<"fast path pointer:"<<fastPath<<" stored:"<<energy<<" "<<crossSection<<" "\
189  <<cacheHitCount<<" "<<initCyclesFastPath<<" "<<invocationCountSlowPath<<" "\
190  <<totalCyclesSlowPath<<" "<<invocationCountFastPath<<" "<<totalCyclesFastPath<<" "\
191  <<invocationCountTriedOneLineCache<<" "<<invocationCountOneLineCache);
192 }
193 
194 #ifdef FPDEBUG
195 namespace {
196  static inline unsigned long long rdtsc() {
197  unsigned hi=0,lo=0;
198 #if defined(__GNUC__) &&( defined(__i386__)|| defined(__x86_64__) )
199  __asm__ __volatile__ ("rdtsc":"=a"(lo),"=d"(hi));
200 #endif
201  return ((unsigned long long)lo) | ((unsigned long long)hi<<32 );
202  }
203 }
205 {
206  tm.rdtsc_start=rdtsc();
207 }
209 {
210  tm.rdtsc_stop=rdtsc();
211 }
212 #endif
214 #ifdef FPDEBUG
215  methodCalled = 0;
216  hitOneLineCache=0;
217  fastPath=0;
218  slowPath=0;
219  sampleZandA = 0;
220 #endif
221 }
222 
223 namespace {
224 // Rob Fowler's simplify code
225 
226 // This is a curve simplification routine based on the Douglas-Peucker
227 // algorithm.
228 // Simplifying assumptions are that the input polyline is a piecewise
229 // function with the x values monotonically increasing, that the function
230 // reaches an asymptote at the right (high energy) end.
231 // Also, the correct error measure is the difference in y between the original
232 // curve and the result.
233 // In GEANT4 use, the assumption is that the calling program has identified
234 // low- and high-energy cutoffs and that the vector passed in is restricted
235 // to the region between the cutoffs.
236 
237 
238 // The raw_data vector comes in ordered left to right (small energy to large).
239 // The simplified_data vector is initially empty.
240 
241 //A.Dotti ( 16-July-2015): transform variable size C-array and use of size_t
242 // to remove compilation warnings
243 
244 int simplify_function(G4double tolerance,
245  std::vector<Point_t> & raw_data,
246  std::vector<Point_t> & simplified_data)
247 {
248 
249  int gap_left, gap_right; // indices of the current region
250 
251  G4double tolsq = tolerance*tolerance; // Alternative to working with absolute values.
252 
253  std::vector<int> working_stack;
254  //A stack of the points to the right of the current interval that
255  // are known to be selected.
256 
257  gap_right = raw_data.size() - 1; // index of the last element.
258 
259  gap_left = 0;
260 
261  DBG("First and last elements " << gap_left <<" " <<gap_right);
262 
263  simplified_data.push_back(raw_data[0]); //copy first element over.
264 
265  DBG("first point ( 0 "
266  <<simplified_data[0].e <<", "<<simplified_data[0].xs <<" )");
267 
268  working_stack.push_back(gap_right); // 0th element on the stack.
269 
270  while ( !working_stack.empty() )
271  { G4double a, slope, delta;
272  G4double deltasq_max= tolsq;
273  int i_max;
274 
275  gap_right = working_stack.back(); //get current TOS
276  i_max = gap_right;
277 
278 
279  if ( (gap_left +1) < gap_right ) // At least three points in the range.
280  {
281  // co-efficients for the left to right affine line segment
282  slope = (raw_data[gap_right].xs - raw_data[gap_left].xs) /
283  (raw_data[gap_right].e - raw_data[gap_left].e);
284  a = raw_data[gap_left].xs - slope * raw_data[gap_left].e;
285 
286  for ( int i = gap_left +1; i <gap_right; i++) {
287  delta = raw_data[i].xs - a - slope * raw_data[i].e;
288  if ( delta * delta > deltasq_max){
289  deltasq_max = delta * delta;
290  i_max = i;
291  }
292  }
293  } else {
294  DBG(" Less than 3 point interval at [ "<< gap_left <<", " <<gap_right<< " ]");
295  }
296 
297  if(i_max < gap_right) { // Found a new point, push it on the stack
298  working_stack.push_back(i_max);
299  DBG(" pushing point " << i_max);
300  gap_right = i_max;
301  }
302  else { // didn't find a new point betweek gap_left and gap_right.
303  simplified_data.push_back(raw_data[gap_right]);
304  DBG("inserting point ("
305  <<gap_right <<", "<<raw_data[gap_right].e <<", "
306  << raw_data[gap_right].xs <<" )");
307  gap_left = gap_right;
308  working_stack.pop_back();
309  gap_right = working_stack.back();
310  DBG(" new gap_right " << gap_right);
311  }
312 
313  }
314  DBG("Simplified curve size "<< simplified_data.size());
315  return (simplified_data.size());
316 }
317 
318 // Rob Fowler's debias code
319 
320 // This is a de-biasing routine applied after using a curve simplification
321 // routine based on the Douglas-Peucker
322 // algorithm.
323 // Simplifying assumptions are that the input polyline is a piecewise
324 // function with the x values monotonically increasing, and
325 // The right error measure is the difference in y between the original
326 // curve and the result.
327 
328 
329 
330 void RemoveBias(std::vector<Point_t> & original, std::vector<Point_t> & simplified,
331  std::vector<Point_t> & result){
332 
333 
334  const size_t originalSize = original.size();
335  const size_t simplifiedSize = simplified.size();
336 
337  //Create index mapping array
338  std::vector<G4int> xindex(simplifiedSize,0);
339  //G4int xindex[simplifiedSize];
340  G4int lastmatch = 0;
341  G4int j = 0;
342 
343  DBG(" original and simplified vector sizes " << originalSize <<" "<<simplifiedSize);
344 
345  for (size_t k = 0; k <simplifiedSize; k++) {
346  for (size_t i = lastmatch; i < originalSize; i++) {
347  if (original[i].e == simplified[k].e) {
348  xindex[j++] = i;
349  lastmatch = i;
350  }
351  }
352  }
353 
354  DBG("Matched " << j << " values of the simplified vector");
355  // Use short names here.
356  G4int m = simplifiedSize;
357 
358  std::vector<G4double> GArea(m-1,0);
359  //G4double GArea [m-1];
360  G4double GAreatotal = 0;
361 
362  //Area of original simplified curve
363  for(int i = 0; i < m-1; i++){
364  G4double GAreatemp = 0;
365 
366  for(j = xindex[i]; j< xindex[i+1]; j++){
367  G4double trap = (original[j+1].xs + original[j].xs) * (original[j+1].e - original[j].e)/2.0;
368  GAreatemp = GAreatemp + trap;
369  }
370  GArea[i] = GAreatemp;
371  GAreatotal = GAreatotal + GAreatemp;
372  }
373 
374  DBG(" Area under the original curve " << GAreatotal);
375 
376  //aleph Why is this not alpha?
377 
378 
379  std::vector<G4double> aleph(m-1,0);
380  //G4double aleph [m-1];
381  for(int i = 0; i< m-1; i++){
382  aleph[i] = (simplified[i+1].e - simplified[i].e)/2.0;
383  }
384 
385  //solve for f
386  std::vector<G4double> adjustedy(m-1,0);
387  //G4double adjustedy [m];
388  adjustedy[m-1] = simplified[m-1].xs;
389  for(int i = 2; i < m+1; i++) {
390  adjustedy[m-i] = (GArea[m-i]/aleph[m-i]) - adjustedy[m-i+1];
391  if (adjustedy[m-i] <0.0) {
392  adjustedy[m-i] = 0.0;
393  DBG(" Fixing negative cross section at index " << (m-i));
394  }
395  }
396 
397  //error and difference tracking
398  std::vector<G4double> difference(m,0.);
399  //G4double difference [m];
400  G4double maxdiff = 0;
401  G4double adjustedarea = 0;
402  G4double simplifiedarea = 0;
403  for(int i = 0; i < m-1; i++){
404  G4double trap;
405  trap = (adjustedy[i+1]+adjustedy[i])*(simplified[i+1].e-simplified[i].e)/2.0;
406  adjustedarea = adjustedarea+trap;
407  trap = (simplified[i+1].xs+simplified[i].xs)*(simplified[i+1].e-simplified[i].e)/2.0;
408  simplifiedarea = simplifiedarea + trap;
409  }
410 
411  DBG(" Area: Simplified curve = " <<simplifiedarea);
412  DBG(" Area: Debiased curve = " << adjustedarea);
413 
414  for(int i = 0; i <m; i++) {
415  difference[i] = simplified[i].xs-adjustedy[i];
416  }
417  for(int i = 0; i <m; i++){
418  if(std::fabs(difference[i]) > maxdiff) {
419  maxdiff = std::fabs(difference[i]);
420  }
421  }
422  // what is the significance of the loops above ?
423 
424  for(size_t i = 0; i < simplifiedSize; i++){
425  result.push_back( {simplified[i].e , adjustedy[i] } );
426  }
427 
428 }
429 
430 
431 }