ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ptwXY_functions.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ptwXY_functions.cc
1 /*
2 # <<BEGIN-copyright>>
3 # <<END-copyright>>
4 */
5 
6 #include <cmath>
7 
8 #include "ptwXY.h"
9 
10 #if defined __cplusplus
11 #include "G4Exp.hh"
12 #include "G4Pow.hh"
13 namespace GIDI {
14 using namespace GIDI;
15 #endif
16 
17 static nfu_status ptwXY_pow_callback( ptwXYPoint *point, void *argList );
18 static nfu_status ptwXY_exp_s( ptwXYPoints *ptwXY, double x1, double y1, double z1, double x2, double y2, double z2, int level );
19 static nfu_status ptwXY_convolution2( ptwXYPoints *f1, ptwXYPoints *f2, double y, double yMin, double *c );
20 static nfu_status ptwXY_convolution3( ptwXYPoints *convolute, ptwXYPoints *f1, ptwXYPoints *f2, double y1, double c1, double y2, double c2, double yMin );
21 /*
22 ************************************************************
23 */
24 nfu_status ptwXY_pow( ptwXYPoints *ptwXY, double v ) {
25 
26  return( ptwXY_applyFunction( ptwXY, ptwXY_pow_callback, (void *) &v, 0 ) );
27 }
28 /*
29 ************************************************************
30 */
31 static nfu_status ptwXY_pow_callback( ptwXYPoint *point, void *argList ) {
32 
33  nfu_status status = nfu_Okay;
34  double *v = (double *) argList;
35 
36  point->y = G4Pow::GetInstance()->powA( point->y, *v );
37  /* ???? Need to test for valid y-value. */
38  return( status );
39 }
40 /*
41 ************************************************************
42 */
43 nfu_status ptwXY_exp( ptwXYPoints *ptwXY, double a ) {
44 
45  int64_t i, length;
46  nfu_status status;
47  double x1, y1, z1, x2, y2, z2;
48 
49  length = ptwXY->length;
50  if( length < 1 ) return( ptwXY->status );
53 
54  if( ( status = ptwXY_simpleCoalescePoints( ptwXY ) ) != nfu_Okay ) return( status );
55  x2 = ptwXY->points[length-1].x;
56  y2 = a * ptwXY->points[length-1].y;
57  z2 = ptwXY->points[length-1].y = G4Exp( y2 );
58  for( i = length - 2; i >= 0; i-- ) {
59  x1 = ptwXY->points[i].x;
60  y1 = a * ptwXY->points[i].y;
61  z1 = ptwXY->points[i].y = G4Exp( y1 );
62  if( ( status = ptwXY_exp_s( ptwXY, x1, y1, z1, x2, y2, z2, 0 ) ) != nfu_Okay ) return( status );
63  x2 = x1;
64  y2 = y1;
65  }
66  return( status );
67 }
68 /*
69 ************************************************************
70 */
71 static nfu_status ptwXY_exp_s( ptwXYPoints *ptwXY, double x1, double y1, double z1, double x2, double y2, double z2, int level ) {
72 
73  nfu_status status;
74  double x, y, dx, dy, z, zp, s;
75 
76  if( ( x1 == x2 ) || ( y1 == y2 ) ) return( nfu_Okay );
77  if( level >= ptwXY->biSectionMax ) return( nfu_Okay );
78  level++;
79  dx = x2 - x1;
80  dy = y2 - y1;
81  s = dy / dx;
82  x = 1. / s + x2 - z2 * dx / ( z2 - z1 );
83  y = ( y1 * ( x2 - x ) + y2 * ( x - x1 ) ) / dx;
84  z = z1 * G4Exp( 1 - dy / ( G4Exp( dy ) - 1 ) );
85  zp = ( z2 - z1 ) / ( y2 - y1 );
86 
87  if( std::fabs( z - zp ) < std::fabs( z * ptwXY->accuracy ) ) return( nfu_Okay );
88  if( ( status = ptwXY_setValueAtX( ptwXY, x, z ) ) != nfu_Okay ) return( status );
89  if( ( status = ptwXY_exp_s( ptwXY, x, y, z, x2, y2, z2, level ) ) != nfu_Okay ) return( status );
90  if( ( status = ptwXY_exp_s( ptwXY, x1, y1, z1, x, y, z, level ) ) != nfu_Okay ) return( status );
91  return( status );
92 }
93 /*
94 ************************************************************
95 */
96 ptwXYPoints *ptwXY_convolution( ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2, nfu_status *status, int mode ) {
97 /*
98 * Currently, only supports linear-linear interpolation.
99 *
100 * This function calculates c(y) = integral dx f1(x) * f2(y-x)
101 *
102 */
103  int64_t i1, i2, n1, n2, n;
104  ptwXYPoints *f1 = ptwXY1, *f2 = ptwXY2, *convolute;
105  double accuracy = ptwXY1->accuracy, yMin, yMax, c, y, dy;
106 
107  if( ( *status = ptwXY_simpleCoalescePoints( ptwXY1 ) ) != nfu_Okay ) return( NULL );
108  if( ( *status = ptwXY_simpleCoalescePoints( ptwXY2 ) ) != nfu_Okay ) return( NULL );
109 
111  if( ( ptwXY1->interpolation != ptwXY_interpolationLinLin ) || ( ptwXY2->interpolation != ptwXY_interpolationLinLin ) ) return( NULL );
112  *status = nfu_Okay;
113 
114  n1 = f1->length;
115  n2 = f2->length;
116 
117  if( ( n1 == 0 ) || ( n2 == 0 ) ) {
118  convolute = ptwXY_new( ptwXY_interpolationLinLin, NULL, 1., accuracy, 0, 0, status, 0 );
119  return( convolute );
120  }
121 
122  if( ( n1 == 1 ) || ( n2 == 1 ) ) {
123  *status = nfu_tooFewPoints;
124  return( NULL );
125  }
126 
127  if( accuracy < ptwXY2->accuracy ) accuracy = ptwXY2->accuracy;
128  n = n1 * n2;
129  if( mode == 0 ) {
130  mode = 1;
131  if( n > 1000 ) mode = -1;
132  }
133  if( n > 100000 ) mode = -1;
134  if( ( convolute = ptwXY_new( ptwXY_interpolationLinLin, NULL, 1., accuracy, 400, 40, status, 0 ) ) == NULL ) return( NULL );
135 
136  yMin = f1->points[0].x + f2->points[0].x;
137  yMax = f1->points[n1 - 1].x + f2->points[n2 - 1].x;
138 
139  if( ( *status = ptwXY_setValueAtX( convolute, yMin, 0. ) ) != nfu_Okay ) goto Err;
140 
141  if( mode < 0 ) {
142  dy = ( yMax - yMin ) / 400;
143  for( y = yMin + dy; y < yMax; y += dy ) {
144  if( ( *status = ptwXY_convolution2( f1, f2, y, yMin, &c ) ) != nfu_Okay ) goto Err;
145  if( ( *status = ptwXY_setValueAtX( convolute, y, c ) ) != nfu_Okay ) goto Err;
146  } }
147  else {
148  for( i1 = 0; i1 < n1; i1++ ) {
149  for( i2 = 0; i2 < n2; i2++ ) {
150  y = yMin + ( f1->points[i1].x - f1->points[0].x ) + ( f2->points[i2].x - f2->points[0].x );
151  if( y <= yMin ) continue;
152  if( y >= yMax ) continue;
153  if( ( *status = ptwXY_convolution2( f1, f2, y, yMin, &c ) ) != nfu_Okay ) goto Err;
154  if( ( *status = ptwXY_setValueAtX( convolute, y, c ) ) != nfu_Okay ) goto Err;
155  }
156  }
157  }
158  if( ( *status = ptwXY_setValueAtX( convolute, yMax, 0. ) ) != nfu_Okay ) goto Err;
159  if( ( *status = ptwXY_simpleCoalescePoints( convolute ) ) != nfu_Okay ) goto Err;
160  for( i1 = convolute->length - 1; i1 > 0; i1-- ) {
161  if( ( *status = ptwXY_convolution3( convolute, f1, f2, convolute->points[i1 - 1].x, convolute->points[i1 - 1].y,
162  convolute->points[i1].x, convolute->points[i1].y, yMin ) ) != nfu_Okay ) goto Err;
163  }
164 
165  return( convolute );
166 
167 Err:
168  ptwXY_free( convolute );
169  return( NULL );
170 }
171 /*
172 ************************************************************
173 */
174 static nfu_status ptwXY_convolution2( ptwXYPoints *f1, ptwXYPoints *f2, double y, double yMin, double *c ) {
175 
176  int64_t i1 = 0, i2 = 0, n1 = f1->length, n2 = f2->length, mode;
177  double dx1, dx2, x1MinP, x1Min, x2Max;
178  double f1x1 = 0, f1y1 = 0, f1x2 = 0, f1y2 = 0, f2x1 = 0, f2y1 = 0, f2x2 = 0, f2y2 = 0;
179  double f1x1p, f1y1p, f1x2p, f1y2p, f2x1p, f2y1p, f2x2p, f2y2p;
181  ptwXYOverflowPoint lessThanEqualXPoint, greaterThanXPoint;
182  nfu_status status;
183 
184  x2Max = f2->points[0].x + ( y - yMin );
185  if( x2Max > f2->points[n2 - 1].x ) x2Max = f2->points[n2 - 1].x;
186  x1Min = f1->points[0].x;
187  x1MinP = y - f2->points[n2 - 1].x;
188  if( x1Min < x1MinP ) x1Min = x1MinP;
189  *c = 0.;
190 
191  switch( legx = ptwXY_getPointsAroundX( f1, x1Min, &lessThanEqualXPoint, &greaterThanXPoint ) ) {
192  case ptwXY_lessEqualGreaterX_empty : /* These three should not happen. */
195  return( nfu_Okay );
198  i1 = lessThanEqualXPoint.index;
199  f1x1 = f1->points[i1].x;
200  f1y1p = f1y1 = f1->points[i1].y;
201  i1++;
202  if( i1 == n1 ) return( nfu_Okay );
203  f1x2 = f1->points[i1].x;
204  f1y2 = f1->points[i1].y;
205  if( legx == ptwXY_lessEqualGreaterX_between ) {
206  if( ( status = ptwXY_interpolatePoint( f1->interpolation, x1Min, &f1y1p, f1x1, f1y1, f1x2, f1y2 ) ) != nfu_Okay ) return( status );
207  }
208  break;
209  }
210 
211  switch( legx = ptwXY_getPointsAroundX( f2, x2Max, &lessThanEqualXPoint, &greaterThanXPoint ) ) {
212  case ptwXY_lessEqualGreaterX_empty : /* These three should not happen. */
215  return( nfu_Okay );
218  i2 = lessThanEqualXPoint.index;
219  if( i2 < f2->length - 1 ) i2++;
220  f2x2 = f2->points[i2].x;
221  f2y2p = f2y2 = f2->points[i2].y;
222  i2--;
223  f2x1 = f2->points[i2].x;
224  f2y1 = f2->points[i2].y;
225  if( legx == ptwXY_lessEqualGreaterX_between ) {
226  if( ( status = ptwXY_interpolatePoint( f2->interpolation, x2Max, &f2y2p, f2x1, f2y1, f2x2, f2y2 ) ) != nfu_Okay ) return( status );
227  }
228  break;
229  }
230 
231  f1x1p = x1Min;
232  f2x2p = x2Max;
233  f1y2p = f1y2;
234  f2y1p = f2y1;
235  while( ( i1 < n1 ) && ( i2 >= 0 ) ) { // Loop checking, 11.06.2015, T. Koi
236  dx1 = f1x2 - f1x1p;
237  dx2 = f2x2p - f2x1;
238  mode = 2;
239  if( i1 < n1 ) {
240  if( dx1 < dx2 ) mode = 1;
241  }
242  if( mode == 1 ) { /* Point in f1 is limiting dx step size. */
243  f2x1p = f2x2p - dx1;
244  if( f2x1p < f2->points[i2].x ) { /* Round off issue may cause this. */
245  f2x1p = f2x2;
246  f2y1p = f2y2; }
247  else {
248  if( ( status = ptwXY_interpolatePoint( f2->interpolation, f2x1p, &f2y1p, f2x1, f2y1, f2x2, f2y2 ) ) != nfu_Okay ) return( status );
249  }
250  *c += ( ( f1y1p + f1y2p ) * ( f2y1p + f2y2p ) + f1y1p * f2y2p + f1y2p * f2y1p ) * dx1; /* Note the reversing of f2y1p and f2y2p. */
251  i1++;
252  if( i1 == n1 ) break;
253  f1x1p = f1x1 = f1x2;
254  f1y1p = f1y1 = f1y2;
255  f1x2 = f1->points[i1].x;
256  f1y2p = f1y2 = f1->points[i1].y;
257  f2x2p = f2x1p;
258  f2y2p = f2y1p;
259  f2y1p = f2y1; }
260  else {
261  f1x2p = f1x1p + dx2;
262  if( ( f1x2p > f1->points[i1].x ) || ( dx1 == dx2 ) ) { /* Round off issue may cause first test to trip. */
263  f1x2p = f1x2;
264  f1y2p = f1y2; }
265  else {
266  if( ( status = ptwXY_interpolatePoint( f1->interpolation, f1x2p, &f1y2p, f1x1, f1y1, f1x2, f1y2 ) ) != nfu_Okay ) return( status );
267  }
268  *c += ( ( f1y1p + f1y2p ) * ( f2y1p + f2y2p ) + f1y1p * f2y2p + f1y2p * f2y1p ) * dx2; /* Note the reversing of f2y1p and f2y2p. */
269  if( i2 == 0 ) break;
270  i2--;
271  f2x2p = f2x2 = f2x1;
272  f2y2p = f2y2 = f2y1;
273  f2x1 = f2->points[i2].x;
274  f2y1p = f2y1 = f2->points[i2].y;
275  f1x1p = f1x2p;
276  if( dx1 == dx2 ) {
277  f1x1p = f1x1 = f1x2;
278  f1y1p = f1y1 = f1y2;
279  i1++;
280  f1x2 = f1->points[i1].x;
281  f1y2p = f1y2 = f1->points[i1].y; }
282  else {
283  f1y1p = f1y2p;
284  f1y2p = f1->points[i1].y;
285  }
286  }
287  }
288  *c /= 6.;
289  return( nfu_Okay );
290 }
291 /*
292 ************************************************************
293 */
294 static nfu_status ptwXY_convolution3( ptwXYPoints *convolute, ptwXYPoints *f1, ptwXYPoints *f2, double y1, double c1, double y2, double c2, double yMin ) {
295 
296  nfu_status status;
297  double yMid = 0.5 * ( y1 + y2 ), cMid = 0.5 * ( c1 + c2 ), c;
298 
299  if( ( y2 - yMid ) <= 1e-5 * ( ptwXY_getXMax( convolute ) - ptwXY_getXMin( convolute ) ) ) return( nfu_Okay );
300  if( ( status = ptwXY_convolution2( f1, f2, yMid, yMin, &c ) ) != nfu_Okay ) return( status );
301  if( std::fabs( c - cMid ) <= convolute->accuracy * 0.5 * ( std::fabs( c ) + std::fabs( cMid ) ) ) return( nfu_Okay );
302  if( ( status = ptwXY_setValueAtX( convolute, yMid, c ) ) != nfu_Okay ) return( status );
303  if( ( status = ptwXY_convolution3( convolute, f1, f2, y1, c1, yMid, c, yMin ) ) != nfu_Okay ) return( status );
304  return( ptwXY_convolution3( convolute, f1, f2, yMid, c, y2, c2, yMin ) );
305 }
306 
307 #if defined __cplusplus
308 }
309 #endif