Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
ptwXY_functions.c
Go to the documentation of this file.
1/*
2# <<BEGIN-copyright>>
3# Copyright 2019, Lawrence Livermore National Security, LLC.
4# This file is part of the gidiplus package (https://github.com/LLNL/gidiplus).
5# gidiplus is licensed under the MIT license (see https://opensource.org/licenses/MIT).
6# SPDX-License-Identifier: MIT
7# <<END-copyright>>
8*/
9
10#include <math.h>
11
12#include "ptwXY.h"
13
14static nfu_status ptwXY_pow_callback( statusMessageReporting *smr, ptwXYPoint *point, void *argList );
15static nfu_status ptwXY_exp_s( statusMessageReporting *smr, ptwXYPoints *ptwXY, double x1, double y1, double z1,
16 double x2, double y2, double z2, int level );
17static nfu_status ptwXY_convolution2( statusMessageReporting *smr, ptwXYPoints *f1, ptwXYPoints *f2, double y,
18 double rangeMin, double *c );
19static nfu_status ptwXY_convolution3( statusMessageReporting *smr, ptwXYPoints *convolute, ptwXYPoints *f1, ptwXYPoints *f2,
20 double y1, double c1, double y2, double c2, double rangeMin );
21/*
22************************************************************
23*/
25
26 nfu_status status = ptwXY_applyFunction( smr, ptwXY, ptwXY_pow_callback, (void *) &v, 0 );
27
28 if( status != nfu_Okay ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
29 return( status );
30}
31/*
32************************************************************
33*/
34static nfu_status ptwXY_pow_callback( statusMessageReporting *smr, ptwXYPoint *point, void *argList ) {
35
36 nfu_status status = nfu_Okay;
37 double *v = (double *) argList;
38
39 point->y = pow( point->y, *v );
40 /* ???? Need to test for valid y-value. */
41 return( status );
42}
43/*
44************************************************************
45*/
47
48 int64_t i, length;
49 nfu_status status;
50 double x1, y1, z1, x2, y2, z2;
51
52 length = ptwXY->length;
53 if( length < 1 ) return( ptwXY->status );
54
56 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Other interpolation not allowed." );
57 return( ptwXY->status = nfu_otherInterpolation );
58 }
60 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_flatInterpolation, "Flat interpolation not allowed." );
61 return( ptwXY->status = nfu_flatInterpolation );
62 }
63
64 if( ( status = ptwXY_simpleCoalescePoints( smr, ptwXY ) ) != nfu_Okay ) goto Err;
65 x2 = ptwXY->points[length-1].x;
66 y2 = a * ptwXY->points[length-1].y;
67 z2 = ptwXY->points[length-1].y = exp( y2 );
68 for( i = length - 2; i >= 0; i-- ) {
69 x1 = ptwXY->points[i].x;
70 y1 = a * ptwXY->points[i].y;
71 z1 = ptwXY->points[i].y = exp( y1 );
72 if( ( status = ptwXY_exp_s( smr, ptwXY, x1, y1, z1, x2, y2, z2, 0 ) ) != nfu_Okay ) goto Err;
73 x2 = x1;
74 y2 = y1;
75 }
76 return( status );
77
78Err:
79 if( status != nfu_Okay ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
80 if( ptwXY->status != nfu_Okay ) ptwXY->status = status;
81 return( status );
82}
83/*
84************************************************************
85*/
86static nfu_status ptwXY_exp_s( statusMessageReporting *smr, ptwXYPoints *ptwXY, double x1, double y1, double z1,
87 double x2, double y2, double z2, int level ) {
88
89 nfu_status status;
90 double x, y, dx, dy, z, zp, s;
91
92 if( ( x1 == x2 ) || ( y1 == y2 ) ) return( nfu_Okay );
93 if( level >= ptwXY->biSectionMax ) return( nfu_Okay );
94 level++;
95 dx = x2 - x1;
96 dy = y2 - y1;
97 s = dy / dx;
98 x = 1. / s + x2 - z2 * dx / ( z2 - z1 );
99 y = ( y1 * ( x2 - x ) + y2 * ( x - x1 ) ) / dx;
100 z = z1 * exp( 1 - dy / ( exp( dy ) - 1 ) );
101 zp = ( z2 - z1 ) / ( y2 - y1 );
102
103 if( fabs( z - zp ) < fabs( z * ptwXY->accuracy ) ) return( nfu_Okay );
104 if( ( status = ptwXY_setValueAtX( smr, ptwXY, x, z ) ) != nfu_Okay ) return( status );
105 if( ( status = ptwXY_exp_s( smr, ptwXY, x, y, z, x2, y2, z2, level ) ) != nfu_Okay ) return( status );
106 return( ptwXY_exp_s( smr, ptwXY, x1, y1, z1, x, y, z, level ) );
107}
108/*
109************************************************************
110*/
112/*
113* Currently, only supports linear-linear interpolation.
114*
115* This function calculates c(y) = integral dx f1(x) * f2(y-x)
116*
117*/
118 int64_t i1, i2, n1, n2, n;
119 ptwXYPoints *f1 = ptwXY1, *f2 = ptwXY2, *convolute;
120 double accuracy = ptwXY1->accuracy, rangeMin, rangeMax, c, y, dy;
121
122 if( ptwXY_simpleCoalescePoints( smr, ptwXY1 ) != nfu_Okay ) {
123 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via (source1)." );
124 return( NULL );
125 }
126 if( ptwXY_simpleCoalescePoints( smr, ptwXY2 ) != nfu_Okay ) {
127 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via (source2)." );
128 return( NULL );
129 }
130
133 "Source1: unsupported interpolation = '%s'", ptwXY1->interpolationString );
134 return( NULL );
135 }
138 "Source2: unsupported interpolation = '%s'", ptwXY2->interpolationString );
139 return( NULL );
140 }
141
142 n1 = f1->length;
143 n2 = f2->length;
144
145 if( ( n1 == 0 ) || ( n2 == 0 ) ) {
146 convolute = ptwXY_new( smr, ptwXY_interpolationLinLin, NULL, 1., accuracy, 0, 0, 0 );
147 if( convolute == NULL ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
148 return( convolute );
149 }
150
151 if( ( n1 == 1 ) || ( n2 == 1 ) ) {
153 "Too few points: len( source1 ) = %d, len( source1 ) = %d.", (int) n1, (int) n2 );
154 return( NULL );
155 }
156
157 if( accuracy < ptwXY2->accuracy ) accuracy = ptwXY2->accuracy;
158 n = n1 * n2;
159 if( mode == 0 ) {
160 mode = 1;
161 if( n > 10000 ) mode = -1;
162 }
163 if( n > 100000 ) mode = -1;
164 if( ( convolute = ptwXY_new( smr, ptwXY_interpolationLinLin, NULL, 1., accuracy, 400, 40, 0 ) ) == NULL ) {
166 return( NULL );
167 }
168
169 rangeMin = f1->points[0].x + f2->points[0].x;
170 rangeMax = f1->points[n1 - 1].x + f2->points[n2 - 1].x;
171
172 if( ptwXY_setValueAtX( smr, convolute, rangeMin, 0. ) != nfu_Okay ) goto Err;
173
174 if( mode < 0 ) {
175 dy = ( rangeMax - rangeMin ) / 2000;
176 for( y = rangeMin + dy; y < rangeMax; y += dy ) {
177 if( ptwXY_convolution2( smr, f1, f2, y, rangeMin, &c ) != nfu_Okay ) goto Err;
178 if( ptwXY_setValueAtX( smr, convolute, y, c ) != nfu_Okay ) goto Err;
179 } }
180 else {
181 for( i1 = 0; i1 < n1; i1++ ) {
182 for( i2 = 0; i2 < n2; i2++ ) {
183 y = rangeMin + ( f1->points[i1].x - f1->points[0].x ) + ( f2->points[i2].x - f2->points[0].x );
184 if( y <= rangeMin ) continue;
185 if( y >= rangeMax ) continue;
186 if( ptwXY_convolution2( smr, f1, f2, y, rangeMin, &c ) != nfu_Okay ) goto Err;
187 if( ptwXY_setValueAtX( smr, convolute, y, c ) != nfu_Okay ) goto Err;
188 }
189 }
190 }
191 if( ptwXY_setValueAtX( smr, convolute, rangeMax, 0. ) != nfu_Okay ) goto Err;
192 if( ptwXY_simpleCoalescePoints( smr, convolute ) != nfu_Okay ) goto Err;
193 for( i1 = convolute->length - 1; i1 > 0; i1-- ) {
194 if( ptwXY_convolution3( smr, convolute, f1, f2, convolute->points[i1 - 1].x, convolute->points[i1 - 1].y,
195 convolute->points[i1].x, convolute->points[i1].y, rangeMin ) != nfu_Okay ) goto Err;
196 }
197
198 return( convolute );
199
200Err:
201 ptwXY_free( convolute );
203 return( NULL );
204}
205/*
206************************************************************
207*/
208static nfu_status ptwXY_convolution2( statusMessageReporting *smr, ptwXYPoints *f1, ptwXYPoints *f2, double y, double rangeMin, double *c ) {
209
210 int64_t i1 = 0, i2 = 0, n1 = f1->length, n2 = f2->length, mode;
211 double dx1, dx2, x1MinP, x1Min, x2Max;
212 double f1x1 = 0, f1y1 = 0, f1x2 = 0, f1y2 = 0, f2x1 = 0, f2y1 = 0, f2x2 = 0, f2y2 = 0;
213 double f1x1p, f1y1p, f1x2p, f1y2p, f2x1p, f2y1p, f2x2p, f2y2p;
215 ptwXYOverflowPoint lessThanEqualXPoint, greaterThanXPoint;
216 nfu_status status;
217
218 x2Max = f2->points[0].x + ( y - rangeMin );
219 if( x2Max > f2->points[n2 - 1].x ) x2Max = f2->points[n2 - 1].x;
220 x1Min = f1->points[0].x;
221 x1MinP = y - f2->points[n2 - 1].x;
222 if( x1Min < x1MinP ) x1Min = x1MinP;
223 *c = 0.;
224
225 switch( legx = ptwXY_getPointsAroundX( smr, f1, x1Min, &lessThanEqualXPoint, &greaterThanXPoint ) ) {
227 return( nfu_Error );
228 case ptwXY_lessEqualGreaterX_empty : /* These three should not happen. */
231 return( nfu_Okay );
234 i1 = lessThanEqualXPoint.index;
235 f1x1 = f1->points[i1].x;
236 f1y1p = f1y1 = f1->points[i1].y;
237 i1++;
238 if( i1 == n1 ) return( nfu_Okay );
239 f1x2 = f1->points[i1].x;
240 f1y2 = f1->points[i1].y;
241 if( legx == ptwXY_lessEqualGreaterX_between ) {
242 if( ( status = ptwXY_interpolatePoint( smr, f1->interpolation, x1Min, &f1y1p, f1x1, f1y1, f1x2, f1y2 ) ) != nfu_Okay )
243 return( status );
244 }
245 break;
246 }
247
248 switch( legx = ptwXY_getPointsAroundX( smr, f2, x2Max, &lessThanEqualXPoint, &greaterThanXPoint ) ) {
250 return( nfu_Error );
251 case ptwXY_lessEqualGreaterX_empty : /* These three should not happen. */
254 return( nfu_Okay );
257 i2 = lessThanEqualXPoint.index;
258 if( i2 < f2->length - 1 ) i2++;
259 f2x2 = f2->points[i2].x;
260 f2y2p = f2y2 = f2->points[i2].y;
261 i2--;
262 f2x1 = f2->points[i2].x;
263 f2y1 = f2->points[i2].y;
264 if( legx == ptwXY_lessEqualGreaterX_between ) {
265 if( ( status = ptwXY_interpolatePoint( smr, f2->interpolation, x2Max, &f2y2p, f2x1, f2y1, f2x2, f2y2 ) ) != nfu_Okay )
266 return( status );
267 }
268 break;
269 }
270
271 f1x1p = x1Min;
272 f2x2p = x2Max;
273 f1y2p = f1y2;
274 f2y1p = f2y1;
275 while( ( i1 < n1 ) && ( i2 >= 0 ) ) {
276 dx1 = f1x2 - f1x1p;
277 dx2 = f2x2p - f2x1;
278 mode = 2;
279 if( i1 < n1 ) {
280 if( dx1 < dx2 ) mode = 1;
281 }
282 if( mode == 1 ) { /* Point in f1 is limiting dx step size. */
283 f2x1p = f2x2p - dx1;
284 if( f2x1p < f2->points[i2].x ) { /* Round off issue may cause this. */
285 f2x1p = f2x2;
286 f2y1p = f2y2; }
287 else {
288 if( ( status = ptwXY_interpolatePoint( smr, f2->interpolation, f2x1p, &f2y1p, f2x1, f2y1, f2x2, f2y2 ) ) != nfu_Okay )
289 return( status );
290 }
291 *c += ( ( f1y1p + f1y2p ) * ( f2y1p + f2y2p ) + f1y1p * f2y2p + f1y2p * f2y1p ) * dx1; /* Note the reversing of f2y1p and f2y2p. */
292 i1++;
293 if( i1 == n1 ) break;
294 f1x1p = f1x1 = f1x2;
295 f1y1p = f1y1 = f1y2;
296 f1x2 = f1->points[i1].x;
297 f1y2p = f1y2 = f1->points[i1].y;
298 f2x2p = f2x1p;
299 f2y2p = f2y1p;
300 f2y1p = f2y1; }
301 else {
302 f1x2p = f1x1p + dx2;
303 if( ( f1x2p > f1->points[i1].x ) || ( dx1 == dx2 ) ) { /* Round off issue may cause first test to trip. */
304 f1x2p = f1x2;
305 f1y2p = f1y2; }
306 else {
307 if( ( status = ptwXY_interpolatePoint( smr, f1->interpolation, f1x2p, &f1y2p, f1x1, f1y1, f1x2, f1y2 ) ) != nfu_Okay )
308 return( status );
309 }
310 *c += ( ( f1y1p + f1y2p ) * ( f2y1p + f2y2p ) + f1y1p * f2y2p + f1y2p * f2y1p ) * dx2; /* Note the reversing of f2y1p and f2y2p. */
311 if( i2 == 0 ) break;
312 i2--;
313 f2x2p = f2x2 = f2x1;
314 f2y2p = f2y2 = f2y1;
315 f2x1 = f2->points[i2].x;
316 f2y1p = f2y1 = f2->points[i2].y;
317 f1x1p = f1x2p;
318 if( dx1 == dx2 ) {
319 f1x1p = f1x1 = f1x2;
320 f1y1p = f1y1 = f1y2;
321 i1++;
322 f1x2 = f1->points[i1].x;
323 f1y2p = f1y2 = f1->points[i1].y; }
324 else {
325 f1y1p = f1y2p;
326 f1y2p = f1->points[i1].y;
327 }
328 }
329 }
330 *c /= 6.;
331 return( nfu_Okay );
332}
333/*
334************************************************************
335*/
336static nfu_status ptwXY_convolution3( statusMessageReporting *smr, ptwXYPoints *convolute, ptwXYPoints *f1, ptwXYPoints *f2,
337 double y1, double c1, double y2, double c2, double rangeMin ) {
338
339 nfu_status status;
340 double rangeMid = 0.5 * ( y1 + y2 ), cMid = 0.5 * ( c1 + c2 ), c;
341 double domainMin, domainMax;
342
343 if( ptwXY_domainMin( smr, convolute, &domainMin ) != nfu_Okay ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
344 if( ptwXY_domainMax( smr, convolute, &domainMax ) != nfu_Okay ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
345
346 if( ( y2 - rangeMid ) <= 1e-5 * ( domainMax - domainMin ) ) return( nfu_Okay );
347 if( ( status = ptwXY_convolution2( smr, f1, f2, rangeMid, rangeMin, &c ) ) != nfu_Okay ) return( status );
348 if( fabs( c - cMid ) <= convolute->accuracy * 0.5 * ( fabs( c ) + fabs( cMid ) ) ) return( nfu_Okay );
349 if( ( status = ptwXY_setValueAtX( smr, convolute, rangeMid, c ) ) != nfu_Okay ) return( status );
350 if( ( status = ptwXY_convolution3( smr, convolute, f1, f2, y1, c1, rangeMid, c, rangeMin ) ) != nfu_Okay ) return( status );
351 return( ptwXY_convolution3( smr, convolute, f1, f2, rangeMid, c, y2, c2, rangeMin ) );
352}
353/*
354************************************************************
355*/
357
358 int64_t length;
359 ptwXY_interpolation interpolation;
360 ptwXYPoints *ptwXYInverse;
361
362 length = ptwXY_length( NULL, ptwXY );
363
364 if( ptwXY->interpolation == ptwXY_interpolationFlat ) {
365 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_flatInterpolation, "flat interpolation not allowed." );
366 return( NULL );
367 }
368
370 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Other interpolation not allowed." );
371 return( NULL );
372 }
373
374 if( ptwXY_simpleCoalescePoints( smr, ptwXY ) != nfu_Okay ) {
376 return( NULL );
377 }
378
379 switch( ptwXY->interpolation ) {
381 interpolation = ptwXY_interpolationLinLog;
382 break;
384 interpolation = ptwXY_interpolationLogLin;
385 break;
386 default :
387 interpolation = ptwXY->interpolation;
388 break;
389 }
390
391 if( ( ptwXYInverse = ptwXY_new( smr, interpolation, NULL, ptwXY_getBiSectionMax( ptwXY ), ptwXY_getAccuracy( ptwXY ),
392 length, 10, 0 ) ) == NULL ) {
394 return( NULL );
395 }
396
397 if( length == 1 ) {
398 ptwXYInverse->points[0].x = ptwXY->points[0].y;
399 ptwXYInverse->points[0].y = ptwXY->points[0].x; }
400 else if( length > 1 ) {
401 int64_t i1, start = 0, order = 1;
402
403 if( ptwXY->points[0].y > ptwXY->points[1].y ) {
404 start = length - 1;
405 order = -1;
406 }
407 ptwXYInverse->points[0].x = ptwXY->points[start].y;
408 ptwXYInverse->points[0].y = ptwXY->points[start].x;
409 for( i1 = 1, start += order; i1 < length; ++i1, start += order ) {
410 ptwXYInverse->points[i1].x = ptwXY->points[start].y;
411 ptwXYInverse->points[i1].y = ptwXY->points[start].x;
412 if( ptwXYInverse->points[i1-1].x >= ptwXYInverse->points[i1].x ) {
414 "Non-ascending domain values: x[%d] = %.17e >= x[%d] = %.17e.",
415 (int) (i1-1), ptwXYInverse->points[i1-1].x, (int) i1, ptwXYInverse->points[i1].x );
416 ptwXY_free( ptwXYInverse );
417 return( NULL );
418 }
419 }
420 }
421 ptwXYInverse->length = length;
422 return( ptwXYInverse );
423}
@ nfu_unsupportedInterpolation
@ nfu_XNotAscending
@ nfu_Okay
@ nfu_flatInterpolation
@ nfu_tooFewPoints
@ nfu_Error
@ nfu_otherInterpolation
enum nfu_status_e nfu_status
int nfu_SMR_libraryID
double ptwXY_getAccuracy(ptwXYPoints *ptwXY)
Definition ptwXY_core.c:566
nfu_status ptwXY_setValueAtX(statusMessageReporting *smr, ptwXYPoints *ptwXY, double x, double y)
enum ptwXY_lessEqualGreaterX_e ptwXY_lessEqualGreaterX
struct ptwXYOverflowPoint_s ptwXYOverflowPoint
ptwXY_lessEqualGreaterX ptwXY_getPointsAroundX(statusMessageReporting *smr, ptwXYPoints *ptwXY, double x, ptwXYOverflowPoint *lessThanEqualXPoint, ptwXYOverflowPoint *greaterThanXPoint)
enum ptwXY_interpolation_e ptwXY_interpolation
@ ptwXY_interpolationFlat
Definition ptwXY.h:38
@ ptwXY_interpolationLinLog
Definition ptwXY.h:37
@ ptwXY_interpolationLinLin
Definition ptwXY.h:37
@ ptwXY_interpolationOther
Definition ptwXY.h:38
@ ptwXY_interpolationLogLin
Definition ptwXY.h:37
struct ptwXYPoints_s ptwXYPoints
double ptwXY_getBiSectionMax(ptwXYPoints *ptwXY)
Definition ptwXY_core.c:582
nfu_status ptwXY_interpolatePoint(statusMessageReporting *smr, ptwXY_interpolation interpolation, double x, double *y, double x1, double y1, double x2, double y2)
@ ptwXY_lessEqualGreaterX_equal
Definition ptwXY.h:59
@ ptwXY_lessEqualGreaterX_Error
Definition ptwXY.h:60
@ ptwXY_lessEqualGreaterX_empty
Definition ptwXY.h:59
@ ptwXY_lessEqualGreaterX_between
Definition ptwXY.h:60
@ ptwXY_lessEqualGreaterX_lessThan
Definition ptwXY.h:59
@ ptwXY_lessEqualGreaterX_greater
Definition ptwXY.h:60
ptwXYPoints * ptwXY_new(statusMessageReporting *smr, ptwXY_interpolation interpolation, char const *interpolationString, double biSectionMax, double accuracy, int64_t primarySize, int64_t secondarySize, int userFlag)
Definition ptwXY_core.c:28
int64_t ptwXY_length(statusMessageReporting *smr, ptwXYPoints *ptwXY)
Definition ptwXY_core.c:793
nfu_status ptwXY_applyFunction(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXY_applyFunction_callback func, void *argList, int checkForRoots)
Definition ptwXY_misc.c:165
struct ptwXYPoint_s ptwXYPoint
ptwXYPoints * ptwXY_free(ptwXYPoints *ptwXY)
Definition ptwXY_core.c:782
nfu_status ptwXY_domainMax(statusMessageReporting *smr, ptwXYPoints *ptwXY, double *value)
nfu_status ptwXY_simpleCoalescePoints(statusMessageReporting *smr, ptwXYPoints *ptwXY)
Definition ptwXY_core.c:734
nfu_status ptwXY_domainMin(statusMessageReporting *smr, ptwXYPoints *ptwXY, double *value)
ptwXYPoints * ptwXY_convolution(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2, int mode)
nfu_status ptwXY_exp(statusMessageReporting *smr, ptwXYPoints *ptwXY, double a)
nfu_status ptwXY_pow(statusMessageReporting *smr, ptwXYPoints *ptwXY, double v)
ptwXYPoints * ptwXY_inverse(statusMessageReporting *smr, ptwXYPoints *ptwXY)
#define smr_setReportError2(smr, libraryID, code, fmt,...)
#define smr_setReportError2p(smr, libraryID, code, fmt)
double y
Definition ptwXY.h:64
double x
Definition ptwXY.h:64
ptwXYPoint * points
Definition ptwXY.h:93
ptwXY_interpolation interpolation
Definition ptwXY.h:81
double biSectionMax
Definition ptwXY.h:84
double accuracy
Definition ptwXY.h:85
int64_t length
Definition ptwXY.h:87
nfu_status status
Definition ptwXY.h:80
char const * interpolationString
Definition ptwXY.h:82