Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
ptwXY_misc.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 <stdio.h>
11#include <stdlib.h>
12#include <math.h>
13#include <float.h>
14
15#include "ptwXY.h"
16
17static nfu_status ptwXY_createFromFunctionBisect( statusMessageReporting *smr, ptwXYPoints *ptwXY, double x1, double y1,
18 double x2, double y2, ptwXY_createFromFunction_callback func, void *argList, int level, int checkForRoots, double eps );
19static nfu_status ptwXY_createFromFunctionZeroCrossing( statusMessageReporting *smr, ptwXYPoints *ptwXY, double x1, double y1,
20 double x2, double y2, ptwXY_createFromFunction_callback func, void *argList, double eps );
21static nfu_status ptwXY_applyFunction2( statusMessageReporting *smr, ptwXYPoints *ptwXY1, double y1, double y2,
22 ptwXYPoint *p1, ptwXYPoint *p2, ptwXY_applyFunction_callback func, void *argList, int level, int checkForRoots );
23static nfu_status ptwXY_applyFunctionZeroCrossing( statusMessageReporting *smr, ptwXYPoints *ptwXY1, double y1, double y2,
24 ptwXYPoint *p1, ptwXYPoint *p2, ptwXY_applyFunction_callback func, void *argList );
25/*
26************************************************************
27*/
28double ptwXY_limitAccuracy( double accuracy ) {
29
30 if( accuracy < ptwXY_minAccuracy ) accuracy = ptwXY_minAccuracy;
31 if( accuracy > 1 ) accuracy = 1.;
32 return( accuracy );
33}
34/*
35************************************************************
36*/
37void ptwXY_update_biSectionMax( ptwXYPoints *ptwXY1, double oldLength ) {
38
39 ptwXY1->biSectionMax = ptwXY1->biSectionMax - 1.442695 * log( ptwXY1->length / oldLength ); /* 1.442695 = 1 / log( 2. ) */
40 if( ptwXY1->biSectionMax < 0 ) ptwXY1->biSectionMax = 0;
42}
43/*
44************************************************************
45*/
47 void *argList, double accuracy, int checkForRoots, int biSectionMax ) {
48
49 int64_t i;
50 double x1, y1, x2, y2, eps = ClosestAllowXFactor * DBL_EPSILON;
51 ptwXYPoints *ptwXY;
52 ptwXYPoint *p1, *p2;
53
54 if( n < 2 ) {
55 smr_setReportError2( smr, nfu_SMR_libraryID, nfu_tooFewPoints, "Too few point = %d.", (int) n );
56 return( NULL );
57 }
58 for( i = 1; i < n; i++ ) {
59 if( xs[i-1] >= xs[i] ) {
61 "Non-ascending domain values: xs[%d] = %.17e >= xs[%d] = %.17e.",
62 (int) (i-1), xs[i-1], (int) i, xs[i] );
63 return( NULL );
64 }
65 }
66
67 x1 = xs[0];
68 if( func( smr, x1, &y1, argList ) != nfu_Okay ) {
69 return( NULL );
70 }
71 if( ( ptwXY = ptwXY_new( smr, ptwXY_interpolationLinLin, NULL, biSectionMax, accuracy, 500, 50, 0 ) ) == NULL ) goto Err;
72 for( i = 1; i < n; i++ ) {
73 if( ptwXY_setValueAtX_overrideIfClose( smr, ptwXY, x1, y1, eps, 0 ) != nfu_Okay ) goto Err;
74 x2 = xs[i];
75 if( func( smr, x2, &y2, argList ) != nfu_Okay ) goto Err;
76 if( ptwXY_createFromFunctionBisect( smr, ptwXY, x1, y1, x2, y2, func, argList, 0, checkForRoots, eps ) != nfu_Okay ) goto Err;
77 x1 = x2;
78 y1 = y2;
79 }
80 if( ptwXY_setValueAtX_overrideIfClose( smr, ptwXY, x2, y2, eps, 1 ) != nfu_Okay ) goto Err;
81
82 if( checkForRoots ) {
83 if( ptwXY_simpleCoalescePoints( NULL, ptwXY ) != nfu_Okay ) goto Err;
84 for( i = ptwXY->length - 1, p2 = NULL; i >= 0; i--, p2 = p1 ) { /* Work backward so lower points are still valid if a new point is added. */
85 p1 = &(ptwXY->points[i]);
86 if( p2 != NULL ) {
87 if( ( p1->y * p2->y ) < 0. ) {
88 if( ptwXY_createFromFunctionZeroCrossing( smr, ptwXY, p1->x, p1->y, p2->x, p2->y, func, argList, eps ) != nfu_Okay ) goto Err;
89 }
90 }
91 }
92 }
93
94 return( ptwXY );
95
96Err:
98 if( ptwXY != NULL ) ptwXY_free( ptwXY );
99 return( NULL );
100}
101/*
102************************************************************
103*/
105 void *argList, double accuracy, int checkForRoots, int biSectionMax ) {
106
107 ptwXYPoints *ptwXY = ptwXY_createFromFunction( smr, (int) xs->length, xs->points, func, argList, accuracy,
108 checkForRoots, biSectionMax );
109
110 if( ptwXY == NULL ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
111 return( ptwXY );
112}
113/*
114************************************************************
115*/
116static nfu_status ptwXY_createFromFunctionBisect( statusMessageReporting *smr, ptwXYPoints *ptwXY, double x1, double y1,
117 double x2, double y2, ptwXY_createFromFunction_callback func, void *argList, int level, int checkForRoots, double eps ) {
118
119 nfu_status status;
120 double x, y, f;
121
122 if( ( x2 - x1 ) < ClosestAllowXFactor * DBL_EPSILON * ( fabs( x1 ) + fabs( x2 ) ) ) return( nfu_Okay );
123 if( level >= ptwXY->biSectionMax ) return( nfu_Okay );
124 x = 0.5 * ( x1 + x2 );
125 if( ( status = ptwXY_interpolatePoint( smr, ptwXY->interpolation, x, &y, x1, y1, x2, y2 ) ) != nfu_Okay ) {
127 return( status );
128 }
129 if( ( status = func( smr, x, &f, argList ) ) != nfu_Okay ) return( status );
130 if( fabs( f - y ) <= 0.8 * fabs( f * ptwXY->accuracy ) ) return( nfu_Okay );
131 if( ptwXY_createFromFunctionBisect( smr, ptwXY, x1, y1, x, f, func, argList, level + 1, checkForRoots, eps ) ) return( status );
132 if( ptwXY_setValueAtX_overrideIfClose( smr, ptwXY, x, f, eps, 0 ) != nfu_Okay ) return( status );
133 return( ptwXY_createFromFunctionBisect( smr, ptwXY, x, f, x2, y2, func, argList, level + 1, checkForRoots, eps ) );
134}
135/*
136************************************************************
137*/
138static nfu_status ptwXY_createFromFunctionZeroCrossing( statusMessageReporting *smr, ptwXYPoints *ptwXY, double x1, double y1,
139 double x2, double y2, ptwXY_createFromFunction_callback func, void *argList, double eps ) {
140
141 int i;
142 double x = 0, y; /* Initialize x so some compilers do not complain. */
143 nfu_status status;
144
145 for( i = 0; i < 16; i++ ) {
146 if( y2 == y1 ) break;
147 x = ( y2 * x1 - y1 * x2 ) / ( y2 - y1 );
148 if( x <= x1 ) x = x1 + 0.1 * ( x2 - x1 );
149 if( x >= x2 ) x = x2 - 0.1 * ( x2 - x1 );
150 if( ( status = func( smr, x, &y, argList ) ) != nfu_Okay ) return( status );
151 if( y == 0 ) break;
152 if( y1 * y < 0 ) {
153 x2 = x;
154 y2 = y; }
155 else {
156 x1 = x;
157 y1 = y;
158 }
159 }
160 return( ptwXY_setValueAtX_overrideIfClose( smr, ptwXY, x, 0., eps, 1 ) );
161}
162/*
163************************************************************
164*/
166 void *argList, int checkForRoots ) {
167
168 int64_t i, originalLength = ptwXY1->length, notFirstPass = 0;
169 double y1, y2 = 0;
170 nfu_status status;
171 ptwXYPoint p1, p2;
172
173 checkForRoots = checkForRoots && ptwXY1->biSectionMax;
174
175 if( ptwXY1->interpolation == ptwXY_interpolationOther ) {
176 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Other interpolation not allowed." );
177 return( ptwXY1->status = nfu_otherInterpolation );
178 }
179 if( ptwXY1->interpolation == ptwXY_interpolationFlat ) {
180 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_flatInterpolation, "Flat interpolation not allowed." );
181 return( ptwXY1->status = nfu_flatInterpolation );
182 }
183
184 if( ptwXY_simpleCoalescePoints( smr, ptwXY1 ) != nfu_Okay ) goto Err;
185 for( i = originalLength - 1; i >= 0; i-- ) {
186 y1 = ptwXY1->points[i].y;
187 if( ( status = func( smr, &(ptwXY1->points[i]), argList ) ) != nfu_Okay ) {
188 if( ptwXY1->status == nfu_Okay ) ptwXY1->status = status;
189 return( status );
190 }
191 p1 = ptwXY1->points[i];
192 if( notFirstPass ) {
193 if( ptwXY_applyFunction2( smr, ptwXY1, y1, y2, &p1, &p2, func, argList, 0, checkForRoots ) != nfu_Okay ) goto Err;
194 }
195 notFirstPass = 1;
196 p2 = p1;
197 y2 = y1;
198 }
199 ptwXY_update_biSectionMax( ptwXY1, (double) originalLength );
200 return( status );
201
202Err:
204 if( ptwXY1->status == nfu_Okay ) ptwXY1->status = nfu_Error;
205 return( nfu_Error );
206}
207/*
208************************************************************
209*/
210static nfu_status ptwXY_applyFunction2( statusMessageReporting *smr, ptwXYPoints *ptwXY1, double y1, double y2,
211 ptwXYPoint *p1, ptwXYPoint *p2, ptwXY_applyFunction_callback func, void *argList, int level, int checkForRoots ) {
212
213 double y;
214 ptwXYPoint p;
215 nfu_status status;
216
217 if( ( p2->x - p1->x ) < ClosestAllowXFactor * DBL_EPSILON * ( fabs( p1->x ) + fabs( p2->x ) ) ) return( nfu_Okay );
218 if( level >= ptwXY1->biSectionMax ) goto checkForZeroCrossing;
219 p.x = 0.5 * ( p1->x + p2->x );
220 if( ( status = ptwXY_interpolatePoint( smr, ptwXY1->interpolation, p.x, &y, p1->x, y1, p2->x, y2 ) ) != nfu_Okay ) {
222 return( status );
223 }
224 p.y = y;
225 if( ( status = func( smr, &p, argList ) ) != nfu_Okay ) return( status );
226 if( fabs( ( p.x - p1->x ) * ( p2->y - p1->y ) + ( p2->x - p1->x ) * ( p1->y - p.y ) ) <= 0.8 * fabs( ( p2->x - p1->x ) * p.y * ptwXY1->accuracy ) )
227 goto checkForZeroCrossing;
228 if( ( status = ptwXY_setValueAtX( smr, ptwXY1, p.x, p.y ) ) != nfu_Okay ) return( status );
229 if( ( status = ptwXY_applyFunction2( smr, ptwXY1, y1, y, p1, &p, func, argList, level + 1, checkForRoots ) ) ) return( status );
230 return( ptwXY_applyFunction2( smr, ptwXY1, y, y2, &p, p2, func, argList, level + 1, checkForRoots ) );
231
232checkForZeroCrossing:
233 if( checkForRoots && ( ( p1->y * p2->y ) < 0. ) )
234 return( ptwXY_applyFunctionZeroCrossing( smr, ptwXY1, y1, y2, p1, p2, func, argList ) );
235 return( nfu_Okay );
236}
237/*
238************************************************************
239*/
240static nfu_status ptwXY_applyFunctionZeroCrossing( statusMessageReporting *smr, ptwXYPoints *ptwXY1, double y1, double y2,
241 ptwXYPoint *p1, ptwXYPoint *p2, ptwXY_applyFunction_callback func, void *argList ) {
242
243 int i;
244 double y, x1 = p1->x, x2 = p2->x, nY1 = p1->y, nY2 = p2->y, refY = 0.5 * ( fabs( p1->y ) + fabs( p2->y ) );
245 ptwXYPoint p = { 0.5 * ( p1->x + p2->x ), 0.0 };
246 nfu_status status;
247
248 for( i = 0; i < 6; i++ ) {
249 if( nY2 == nY1 ) break;
250 p.x = ( nY2 * x1 - nY1 * x2 ) / ( nY2 - nY1 );
251 if( p.x <= x1 ) p.x = 0.5 * ( x1 + x2 );
252 if( p.x >= x2 ) p.x = 0.5 * ( x1 + x2 );
253 if( ( status = ptwXY_interpolatePoint( smr, ptwXY1->interpolation, p.x, &y, p1->x, y1, p2->x, y2 ) ) != nfu_Okay ) {
255 return( status );
256 }
257 p.y = y;
258 if( ( status = func( smr, &p, argList ) ) != nfu_Okay ) return( status );
259 if( p.y == 0 ) break;
260 if( 0.5 * refY < fabs( p.y ) ) break;
261 refY = fabs( p.y );
262 if( p1->y * p.y < 0 ) {
263 x2 = p.x;
264 nY2 = p.y; }
265 else {
266 x1 = p.x;
267 nY1 = p.y;
268 }
269 }
270 return( ptwXY_setValueAtX( smr, ptwXY1, p.x, 0. ) );
271}
272/*
273************************************************************
274*/
275ptwXYPoints *ptwXY_fromString( statusMessageReporting *smr, char const *str, char sep, ptwXY_interpolation interpolation,
276 char const *interpolationString, double biSectionMax, double accuracy, char **endCharacter, int useSystem_strtod ) {
277
278 int64_t numberConverted;
279 double *doublePtr;
280 ptwXYPoints *ptwXY = NULL;
281
282 if( ( doublePtr = nfu_stringToListOfDoubles( smr, str, sep, &numberConverted, endCharacter, useSystem_strtod ) ) == NULL ) {
284 return( NULL );
285 }
286 if( ( numberConverted % 2 ) == 0 ) {
287 ptwXY = ptwXY_create( smr, interpolation, interpolationString, biSectionMax, accuracy, numberConverted / 2, 10, numberConverted / 2, doublePtr, 0 ); }
288 else {
289 smr_setReportError2( smr, nfu_SMR_libraryID, nfu_oddNumberOfValues, "Odd number = %d of float for ptwXY.", (int) numberConverted );
290 }
291 smr_freeMemory2( doublePtr );
292 return( ptwXY );
293}
294/*
295************************************************************
296*/
297void ptwXY_showInteralStructure( ptwXYPoints *ptwXY, FILE *f, int printPointersAsNull ) {
298
299 int64_t i, n1;
300 ptwXYPoint *point = ptwXY->points;
301 ptwXYOverflowPoint *overflowPoint;
302
303 n1 = ptwXY_getNonOverflowLength( NULL, ptwXY );
304
305 fprintf( f, "status = %d interpolation = %d length = %d allocatedSize = %d\n",
306 (int) ptwXY->status, (int) ptwXY->interpolation, (int) ptwXY->length, (int) ptwXY->allocatedSize );
307 fprintf( f, "userFlag = %d biSectionMax = %.8e accuracy = %.2e minFractional_dx = %.6e\n",
308 ptwXY->userFlag, ptwXY->biSectionMax, ptwXY->accuracy, ptwXY->minFractional_dx );
309 fprintf( f, "interpolationString = %s\n", ptwXY->interpolationString );
310 fprintf( f, " overflowLength = %d overflowAllocatedSize = %d mallocFailedSize = %d\n",
311 (int) ptwXY->overflowLength, (int) ptwXY->overflowAllocatedSize, (int) ptwXY->mallocFailedSize );
312 fprintf( f, " Points data, points = %20p\n", ( printPointersAsNull ? NULL : ptwXY->points ) );
313 for( i = 0; i < n1; i++, point++ ) fprintf( f, " %14.7e %14.7e\n", point->x, point->y );
314 fprintf( f, " Overflow points data; %20p\n", ( printPointersAsNull ? NULL : &(ptwXY->overflowHeader) ) );
315 for( overflowPoint = ptwXY->overflowHeader.next; overflowPoint != &(ptwXY->overflowHeader); overflowPoint = overflowPoint->next ) {
316 fprintf( f, " %14.7e %14.7e %8d %20p %20p %20p\n", overflowPoint->point.x, overflowPoint->point.y, (int) overflowPoint->index,
317 ( printPointersAsNull ? NULL : overflowPoint ), ( printPointersAsNull ? NULL : overflowPoint->prior ),
318 ( printPointersAsNull ? NULL : overflowPoint->next ) );
319 }
320 fprintf( f, " Points in order\n" );
321 for( i = 0; i < ptwXY->length; i++ ) {
322 point = ptwXY_getPointAtIndex_Unsafely( ptwXY, i );
323 fprintf( f, " %14.7e %14.7e\n", point->x, point->y );
324 }
325}
326/*
327************************************************************
328*/
329void ptwXY_simpleWrite( ptwXYPoints *ptwXY, FILE *f, char const *format ) {
330
331 int64_t i;
332 ptwXYPoint *point;
333
334 for( i = 0; i < ptwXY->length; i++ ) {
335 point = ptwXY_getPointAtIndex_Unsafely( ptwXY, i );
336 fprintf( f, format, point->x, point->y );
337 }
338}
339/*
340************************************************************
341*/
342void ptwXY_simplePrint( ptwXYPoints *ptwXY, char const *format ) {
343
344 ptwXY_simpleWrite( ptwXY, stdout, format );
345}
double * nfu_stringToListOfDoubles(statusMessageReporting *smr, char const *str, char sep, int64_t *numberConverted, char **endCharacter, int useSystem_strtod)
@ nfu_XNotAscending
@ nfu_Okay
@ nfu_oddNumberOfValues
@ nfu_flatInterpolation
@ nfu_tooFewPoints
@ nfu_Error
@ nfu_otherInterpolation
enum nfu_status_e nfu_status
int nfu_SMR_libraryID
#define ptwXY_minAccuracy
Definition ptwXY.h:26
nfu_status ptwXY_setValueAtX(statusMessageReporting *smr, ptwXYPoints *ptwXY, double x, double y)
nfu_status(* ptwXY_createFromFunction_callback)(statusMessageReporting *smr, double x, double *y, void *argList)
Definition ptwXY.h:67
int64_t ptwXY_getNonOverflowLength(statusMessageReporting *smr, ptwXYPoints const *ptwXY)
Definition ptwXY_core.c:805
struct ptwXYOverflowPoint_s ptwXYOverflowPoint
nfu_status(* ptwXY_applyFunction_callback)(statusMessageReporting *smr, ptwXYPoint *point, void *argList)
Definition ptwXY.h:68
enum ptwXY_interpolation_e ptwXY_interpolation
@ ptwXY_interpolationFlat
Definition ptwXY.h:38
@ ptwXY_interpolationLinLin
Definition ptwXY.h:37
@ ptwXY_interpolationOther
Definition ptwXY.h:38
struct ptwXYPoints_s ptwXYPoints
#define ptwXY_maxBiSectionMax
Definition ptwXY.h:25
nfu_status ptwXY_interpolatePoint(statusMessageReporting *smr, ptwXY_interpolation interpolation, double x, double *y, double x1, double y1, double x2, double y2)
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
#define ClosestAllowXFactor
Definition ptwXY.h:28
struct ptwXYPoint_s ptwXYPoint
ptwXYPoints * ptwXY_free(ptwXYPoints *ptwXY)
Definition ptwXY_core.c:782
ptwXYPoint * ptwXY_getPointAtIndex_Unsafely(ptwXYPoints const *ptwXY, int64_t index)
ptwXYPoints * ptwXY_create(statusMessageReporting *smr, ptwXY_interpolation interpolation, char const *interpolationString, double biSectionMax, double accuracy, int64_t primarySize, int64_t secondarySize, int64_t length, double const *xy, int userFlag)
Definition ptwXY_core.c:110
nfu_status ptwXY_simpleCoalescePoints(statusMessageReporting *smr, ptwXYPoints *ptwXY)
Definition ptwXY_core.c:734
nfu_status ptwXY_setValueAtX_overrideIfClose(statusMessageReporting *smr, ptwXYPoints *ptwXY, double x, double y, double eps, int override)
double ptwXY_limitAccuracy(double accuracy)
Definition ptwXY_misc.c:28
void ptwXY_showInteralStructure(ptwXYPoints *ptwXY, FILE *f, int printPointersAsNull)
Definition ptwXY_misc.c:297
ptwXYPoints * ptwXY_createFromFunction(statusMessageReporting *smr, int n, double *xs, ptwXY_createFromFunction_callback func, void *argList, double accuracy, int checkForRoots, int biSectionMax)
Definition ptwXY_misc.c:46
void ptwXY_simplePrint(ptwXYPoints *ptwXY, char const *format)
Definition ptwXY_misc.c:342
ptwXYPoints * ptwXY_createFromFunction2(statusMessageReporting *smr, ptwXPoints *xs, ptwXY_createFromFunction_callback func, void *argList, double accuracy, int checkForRoots, int biSectionMax)
Definition ptwXY_misc.c:104
void ptwXY_simpleWrite(ptwXYPoints *ptwXY, FILE *f, char const *format)
Definition ptwXY_misc.c:329
void ptwXY_update_biSectionMax(ptwXYPoints *ptwXY1, double oldLength)
Definition ptwXY_misc.c:37
nfu_status ptwXY_applyFunction(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXY_applyFunction_callback func, void *argList, int checkForRoots)
Definition ptwXY_misc.c:165
ptwXYPoints * ptwXY_fromString(statusMessageReporting *smr, char const *str, char sep, ptwXY_interpolation interpolation, char const *interpolationString, double biSectionMax, double accuracy, char **endCharacter, int useSystem_strtod)
Definition ptwXY_misc.c:275
struct ptwXPoints_s ptwXPoints
#define smr_setReportError2(smr, libraryID, code, fmt,...)
#define smr_setReportError2p(smr, libraryID, code, fmt)
#define smr_freeMemory2(p)
int64_t length
Definition ptwX.h:29
double * points
Definition ptwX.h:32
struct ptwXYOverflowPoint_s * next
Definition ptwXY.h:73
ptwXYPoint point
Definition ptwXY.h:75
double y
Definition ptwXY.h:64
double x
Definition ptwXY.h:64
double minFractional_dx
Definition ptwXY.h:86
ptwXYOverflowPoint overflowHeader
Definition ptwXY.h:92
int userFlag
Definition ptwXY.h:83
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
int64_t overflowLength
Definition ptwXY.h:89
int64_t overflowAllocatedSize
Definition ptwXY.h:90
nfu_status status
Definition ptwXY.h:80
int64_t mallocFailedSize
Definition ptwXY.h:91
int64_t allocatedSize
Definition ptwXY.h:88
char const * interpolationString
Definition ptwXY.h:82
#define DBL_EPSILON
Definition templates.hh:66