Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
ptwXY_functions.cc
Go to the documentation of this file.
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"
13namespace GIDI {
14using namespace GIDI;
15#endif
16
17static nfu_status ptwXY_pow_callback( ptwXYPoint *point, void *argList );
18static nfu_status ptwXY_exp_s( ptwXYPoints *ptwXY, double x1, double y1, double z1, double x2, double y2, double z2, int level );
19static nfu_status ptwXY_convolution2( ptwXYPoints *f1, ptwXYPoints *f2, double y, double yMin, double *c );
20static nfu_status ptwXY_convolution3( ptwXYPoints *convolute, ptwXYPoints *f1, ptwXYPoints *f2, double y1, double c1, double y2, double c2, double yMin );
21/*
22************************************************************
23*/
24nfu_status ptwXY_pow( ptwXYPoints *ptwXY, double v ) {
25
26 return( ptwXY_applyFunction( ptwXY, ptwXY_pow_callback, (void *) &v, 0 ) );
27}
28/*
29************************************************************
30*/
31static 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*/
43nfu_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*/
71static 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*/
96ptwXYPoints *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
167Err:
168 ptwXY_free( convolute );
169 return( NULL );
170}
171/*
172************************************************************
173*/
174static 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*/
294static 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
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition G4Exp.hh:180
static G4Pow * GetInstance()
Definition G4Pow.cc:41
G4double powA(G4double A, G4double y) const
Definition G4Pow.hh:230
@ nfu_unsupportedInterpolation
@ nfu_invalidInterpolation
@ nfu_Okay
@ nfu_tooFewPoints
@ nfu_otherInterpolation
enum nfu_status_e nfu_status
nfu_status ptwXY_setValueAtX(ptwXYPoints *ptwXY, double x, double y)
ptwXYPoints * ptwXY_convolution(ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2, nfu_status *status, int mode)
enum ptwXY_lessEqualGreaterX_e ptwXY_lessEqualGreaterX
nfu_status ptwXY_simpleCoalescePoints(ptwXYPoints *ptwXY)
ptwXYPoints * ptwXY_new(ptwXY_interpolation interpolation, ptwXY_interpolationOtherInfo const *interpolationOtherInfo, double biSectionMax, double accuracy, int64_t primarySize, int64_t secondarySize, nfu_status *status, int userFlag)
Definition ptwXY_core.cc:29
@ ptwXY_interpolationFlat
Definition ptwXY.h:36
@ ptwXY_interpolationLinLin
Definition ptwXY.h:35
@ ptwXY_interpolationOther
Definition ptwXY.h:36
@ ptwXY_lessEqualGreaterX_equal
Definition ptwXY.h:57
@ ptwXY_lessEqualGreaterX_empty
Definition ptwXY.h:57
@ ptwXY_lessEqualGreaterX_between
Definition ptwXY.h:58
@ ptwXY_lessEqualGreaterX_lessThan
Definition ptwXY.h:57
@ ptwXY_lessEqualGreaterX_greater
Definition ptwXY.h:58
nfu_status ptwXY_pow(ptwXYPoints *ptwXY, double p)
nfu_status ptwXY_exp(ptwXYPoints *ptwXY, double a)
ptwXY_lessEqualGreaterX ptwXY_getPointsAroundX(ptwXYPoints *ptwXY, double x, ptwXYOverflowPoint *lessThanEqualXPoint, ptwXYOverflowPoint *greaterThanXPoint)
double ptwXY_getXMin(ptwXYPoints *ptwXY)
ptwXYPoints * ptwXY_free(ptwXYPoints *ptwXY)
nfu_status ptwXY_applyFunction(ptwXYPoints *ptwXY1, ptwXY_applyFunction_callback func, void *argList, int checkForRoots)
double ptwXY_getXMax(ptwXYPoints *ptwXY)
nfu_status ptwXY_interpolatePoint(ptwXY_interpolation interpolation, double x, double *y, double x1, double y1, double x2, double y2)
double y
Definition ptwXY.h:62
double x
Definition ptwXY.h:62
ptwXYPoint * points
Definition ptwXY.h:99
ptwXY_interpolation interpolation
Definition ptwXY.h:87
double biSectionMax
Definition ptwXY.h:90
double accuracy
Definition ptwXY.h:91
int64_t length
Definition ptwXY.h:93
nfu_status status
Definition ptwXY.h:85