Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
ptwXY_binaryOperators.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#include <float.h>
12
13#include "ptwXY.h"
14
15static double ptwXY_mod2( double v, double m, int pythonMod );
16static nfu_status ptwXY_mul2_s_ptwXY( statusMessageReporting *smr, ptwXYPoints *div, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2,
17 double x1, double y1, double x2, double y2, int level );
18static nfu_status ptwXY_div_s_ptwXY( statusMessageReporting *smr, ptwXYPoints *div, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2,
19 double x1, double y1, double x2, double y2, int level, int isNAN1, int isNAN2 );
20static ptwXYPoints *ptwXY_div_ptwXY_forFlats( statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2, int safeDivide );
21static nfu_status ptwXY_getValueAtX_ignore_XOutsideDomainError( statusMessageReporting *smr, ptwXYPoints *ptwXY1, double x, double *y );
22static nfu_status ptwXY_getValueAtX_signal_XOutsideDomainError( statusMessageReporting *smr, int line,
23 char const *function, ptwXYPoints *ptwXY1, double x, double *y );
24/*
25************************************************************
26*/
28
29 int64_t i, nonOverflowLength;
30 ptwXYPoint *p;
31 ptwXYOverflowPoint *o, *overflowHeader = &(ptwXY->overflowHeader);
32
33 if( ( nonOverflowLength = ptwXY_getNonOverflowLength( smr, ptwXY ) ) < 0 ) {
35 return( ptwXY->status );
36 }
37
38 for( i = 0, p = ptwXY->points; i < nonOverflowLength; i++, p++ ) p->y = slope * p->y + offset;
39 for( o = overflowHeader->next; o != overflowHeader; o = o->next ) o->point.y = slope * o->point.y + offset;
40 return( ptwXY->status );
41}
42/*
43************************************************************
44*/
46
47 if( ptwXY_slopeOffset( smr, ptwXY, 1., value ) != nfu_Okay )
49 return( ptwXY->status );
50}
51/*
52************************************************************
53*/
55
56 if( ptwXY_slopeOffset( smr, ptwXY, 1., -value ) != nfu_Okay )
58 return( ptwXY->status );
59}
60/*
61************************************************************
62*/
64
65 if( ptwXY_slopeOffset( smr, ptwXY, -1., value ) != nfu_Okay )
67 return( ptwXY->status );
68}
69/*
70************************************************************
71*/
73
74 if( ptwXY_slopeOffset( smr, ptwXY, value, 0. ) != nfu_Okay )
76 return( ptwXY->status );
77}
78/*
79************************************************************
80*/
82
83 if( value == 0. ) {
85 ptwXY->status = nfu_divByZero; }
86 else {
87 if( ptwXY_slopeOffset( smr, ptwXY, 1. / value, 0. ) != nfu_Okay )
89 }
90 return( ptwXY->status );
91}
92/*
93************************************************************
94*/
96/*
97* This does not do any infilling and it should?????????
98*/
99
100 int64_t i, nonOverflowLength;
101 ptwXYPoint *p;
102 ptwXYOverflowPoint *o, *overflowHeader = &(ptwXY->overflowHeader);
103
104 if( ( nonOverflowLength = ptwXY_getNonOverflowLength( smr, ptwXY ) ) < 0 ) {
106 return( ptwXY->status );
107 }
109 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Other interpolation not allowed." );
110 return( nfu_otherInterpolation );
111 }
112
113 for( i = 0, p = ptwXY->points; i < nonOverflowLength; i++, p++ ) if( p->y == 0. ) ptwXY->status = nfu_divByZero;
114 for( o = overflowHeader->next; o != overflowHeader; o = o->next ) if( o->point.y == 0. ) ptwXY->status = nfu_divByZero;
115 if( ptwXY->status == nfu_divByZero ) {
116 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_divByZero, "Divide by 0." ); }
117 else {
118 for( i = 0, p = ptwXY->points; i < nonOverflowLength; i++, p++ ) p->y = value / p->y;
119 for( o = overflowHeader->next; o != overflowHeader; o = o->next ) o->point.y = value / o->point.y;
120 }
121 return( ptwXY->status );
122}
123/*
124************************************************************
125*/
126nfu_status ptwXY_mod( statusMessageReporting *smr, ptwXYPoints *ptwXY, double m, int pythonMod ) {
127
128 int64_t i, nonOverflowLength;
129 ptwXYPoint *p;
130 ptwXYOverflowPoint *o, *overflowHeader = &(ptwXY->overflowHeader);
131
132 if( ( nonOverflowLength = ptwXY_getNonOverflowLength( smr, ptwXY ) ) < 0 ) {
134 return( ptwXY->status );
135 }
136
137 if( m == 0 ) {
139 ptwXY->status = nfu_divByZero;
140 }
141
142 for( i = 0, p = ptwXY->points; i < nonOverflowLength; i++, p++ ) p->y = ptwXY_mod2( p->y, m, pythonMod );
143 for( o = overflowHeader->next; o != overflowHeader; o = o->next ) o->point.y = ptwXY_mod2( o->point.y, m, pythonMod );
144 return( ptwXY->status );
145}
146/*
147************************************************************
148*/
149static double ptwXY_mod2( double v, double m, int pythonMod ) {
150
151 double r = fmod( fabs( v ), fabs( m ) );
152
153 if( pythonMod ) {
154 if( ( v * m ) < 0. ) r = fabs( m ) - fabs( r );
155 if( m < 0. ) r *= -1.; }
156 else {
157 if( v < 0. ) r *= -1.;
158 }
159
160 return( r );
161}
162/*
163************************************************************
164*/
166 double v1, double v2, double v1v2 ) {
167
168 int64_t i;
170 double y;
171 ptwXYPoints *ptwXYNew;
172 ptwXYPoint *p;
173
174 if( ptwXY1->interpolation == ptwXY_interpolationOther ) {
175 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Source1: Other interpolation not allowed." );
176 return( NULL );
177 }
178 if( ptwXY2->interpolation == ptwXY_interpolationOther ) {
179 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Source2: Other interpolation not allowed." );
180 return( NULL );
181 }
182
183 if( ptwXY1->interpolation != ptwXY2->interpolation ) {
185 "Source1 interpolation '%s' not same as Source2 interpolation '%s'.",
186 ptwXY1->interpolationString, ptwXY2->interpolationString );
187 return( NULL );
188 }
189
191 ( ptwXY1->interpolation != ptwXY_interpolationFlat ) ) {
193 "Only '%s' and '%s' interpolation supported, not '%s' interpolation.", ptwXY_interpolationToString( ptwXY_interpolationLinLin ),
195 return( NULL );
196 }
197
198 if( ptwXY_areDomainsMutual( smr, ptwXY1, ptwXY2 ) != nfu_Okay ) {
199 double domainMin1, domainMax1, domainMin2, domainMax2;
200
201 ptwXY_domainMin( NULL, ptwXY1, &domainMin1 );
202 ptwXY_domainMax( NULL, ptwXY1, &domainMax1 );
203 ptwXY_domainMin( NULL, ptwXY2, &domainMin2 );
204 ptwXY_domainMax( NULL, ptwXY2, &domainMax2 );
205
206 smr_setReportError2( smr, nfu_SMR_libraryID, nfu_domainsNotMutual, "Domains not mutual (%.17e, %.17e) vs (%.17e, %.17e).",
207 domainMin1, domainMax1, domainMin2, domainMax2 );
208 return( NULL );
209 }
210
211 if( ( ptwXYNew = ptwXY_union( smr, ptwXY1, ptwXY2, unionOptions ) ) == NULL ) {
213 else {
214 for( i = 0, p = ptwXYNew->points; i < ptwXYNew->length; i++, p++ ) {
215 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY2, p->x, &y ) != nfu_Okay ) goto Err;
216 p->y = v1 * p->y + v2 * y + v1v2 * y * p->y;
217 }
218 }
219 return( ptwXYNew );
220Err:
222 if( ptwXYNew ) ptwXY_free( ptwXYNew );
223 return( NULL );
224}
225/*
226************************************************************
227*/
229
230 ptwXYPoints *sum;
231
232 if( ptwXY1->length == 0 ) {
233 sum = ptwXY_clone( smr, ptwXY2 ); }
234 else if( ptwXY2->length == 0 ) {
235 sum = ptwXY_clone( smr, ptwXY1 ); }
236 else {
237 sum = ptwXY_binary_ptwXY( smr, ptwXY1, ptwXY2, 1., 1., 0. );
238 }
239 if( sum == NULL ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
240 return( sum );
241}
242/*
243************************************************************
244*/
246
247 ptwXYPoints *diff = NULL;
248
249 if( ptwXY1->length == 0 ) {
250 diff = ptwXY_clone( smr, ptwXY2 );
251 if( diff != NULL ) {
252 if( ptwXY_neg( smr, diff ) != nfu_Okay ) diff = ptwXY_free( diff );
253 } }
254 else if( ptwXY2->length == 0 ) {
255 diff = ptwXY_clone( smr, ptwXY1 ); }
256 else {
257 diff = ptwXY_binary_ptwXY( smr, ptwXY1, ptwXY2, 1., -1., 0. );
258 }
259 if( diff == NULL ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
260 return( diff );
261}
262/*
263************************************************************
264*/
266
267 ptwXYPoints *mul;
268
269 if( ptwXY1->length == 0 ) {
270 mul = ptwXY_clone( smr, ptwXY1 ); }
271 else if( ptwXY2->length == 0 ) {
272 mul = ptwXY_clone( smr, ptwXY2 ); }
273 else {
274 mul = ptwXY_binary_ptwXY( smr, ptwXY1, ptwXY2, 0., 0., 1. );
275 }
276 if( mul == NULL ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
277 return( mul );
278}
279/*
280************************************************************
281*/
283
284 int64_t i, length;
285 ptwXYPoints *mul = NULL;
286 int found;
287 double x1, y1, x2, y2, u1, u2, v1, v2, xz1 = 0, xz2 = 0, x;
288
289 if( ( mul = ptwXY_mul_ptwXY( smr, ptwXY1, ptwXY2 ) ) == NULL ) {
291 return( NULL );
292 }
293 if( mul->length == 0 ) return( mul );
294 if( ptwXY1->interpolation == ptwXY_interpolationFlat ) return( mul );
295 if( ptwXY2->interpolation == ptwXY_interpolationFlat ) return( mul );
296
297 length = mul->length - 1;
298 if( length > 0 ) {
299 x2 = mul->points[length].x;
300 for( i = length - 1; i >= 0; i-- ) { /* Find and add y zeros not currently in mul's. */
301 x1 = mul->points[i].x;
302 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x1, &u1 ) != nfu_Okay ) goto Err;
303 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x2, &u2 ) != nfu_Okay ) goto Err;
304 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY2, x1, &v1 ) != nfu_Okay ) goto Err;
305 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY2, x2, &v2 ) != nfu_Okay ) goto Err;
306 found = 0;
307 if( u1 * u2 < 0 ) {
308 xz1 = ( u1 * x2 - u2 * x1 ) / ( u1 - u2 );
309 if( ptwXY_setValueAtX( smr, mul, xz1, 0. ) != nfu_Okay ) goto Err;
310 found = 1;
311 }
312 if( v1 * v2 < 0 ) {
313 xz2 = ( v1 * x2 - v2 * x1 ) / ( v1 - v2 );
314 if( ptwXY_setValueAtX( smr, mul, xz2, 0. ) != nfu_Okay ) goto Err;
315 found += 1;
316 }
317 if( found > 1 ) {
318 x = 0.5 * ( xz1 + xz2 );
319 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x, &u1 ) != nfu_Okay ) goto Err;
320 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY2, x, &v1 ) != nfu_Okay ) goto Err;
321 if( ptwXY_setValueAtX( smr, mul, x, u1 * v1 ) != nfu_Okay ) goto Err;
322 }
323 x2 = x1;
324 }
325
326 if( ptwXY_simpleCoalescePoints( smr, mul ) != nfu_Okay ) goto Err;
327 length = mul->length;
328 x2 = mul->points[mul->length-1].x;
329 y2 = mul->points[mul->length-1].y;
330 for( i = mul->length - 2; i >= 0; i-- ) { /* Make interpolation fit accuracy. Work backwards so new */
331 x1 = mul->points[i].x; /* points will not mess up loop. */
332 y1 = mul->points[i].y;
333 if( ptwXY_mul2_s_ptwXY( smr, mul, ptwXY1, ptwXY2, x1, y1, x2, y2, 0 ) != nfu_Okay ) goto Err;
334 x2 = x1;
335 y2 = y1;
336 }
337 ptwXY_update_biSectionMax( mul, (double) length );
338 }
339 return( mul );
340
341Err:
343 if( mul ) ptwXY_free( mul );
344 return( NULL );
345}
346/*
347************************************************************
348*/
349static nfu_status ptwXY_mul2_s_ptwXY( statusMessageReporting *smr, ptwXYPoints *mul, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2,
350 double x1, double y1, double x2, double y2, int level ) {
351
352 double u1, u2, v1, v2, x, y, yp, dx, a1, a2;
353 nfu_status status;
354
355 if( ( x2 - x1 ) < ClosestAllowXFactor * DBL_EPSILON * ( fabs( x1 ) + fabs( x2 ) ) ) return( nfu_Okay );
356 if( level >= mul->biSectionMax ) return( nfu_Okay );
357 level++;
358 if( ( status = ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x1, &u1 ) ) != nfu_Okay ) return( status );
359 if( ( status = ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x2, &u2 ) ) != nfu_Okay ) return( status );
360 if( ( status = ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY2, x1, &v1 ) ) != nfu_Okay ) return( status );
361 if( ( status = ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY2, x2, &v2 ) ) != nfu_Okay ) return( status );
362 if( ( u1 == u2 ) || ( v1 == v2 ) ) return( nfu_Okay );
363 a1 = u1 * v1;
364 if( y1 == 0 ) a1 = 0.; /* Fix rounding problem. */
365 a2 = u2 * v2;
366 if( y2 == 0 ) a2 = 0.; /* Fix rounding problem. */
367 if( ( a1 == 0. ) || ( a2 == 0. ) ) { /* Handle special case of 0 where accuracy can never be met. */
368 x = 0.5 * ( x1 + x2 ); }
369 else {
370 if( ( a1 * a2 < 0. ) ) return( nfu_Okay ); /* Assume rounding error and no point needed as zero */
371 a1 = sqrt( fabs( a1 ) ); /* crossings are set in ptwXY_mul2_ptwXY. */
372 a2 = sqrt( fabs( a2 ) );
373 x = ( a2 * x1 + a1 * x2 ) / ( a2 + a1 );
374 }
375 dx = x2 - x1;
376 yp = ( u1 * v1 * ( x2 - x ) + u2 * v2 * ( x - x1 ) ) / dx;
377 y = ( u1 * ( x2 - x ) + u2 * ( x - x1 ) ) * ( v1 * ( x2 - x ) + v2 * ( x - x1 ) ) / ( dx * dx );
378 if( fabs( y - yp ) < fabs( y * mul->accuracy ) ) return( nfu_Okay );
379 if( ptwXY_setValueAtX( smr, mul, x, y ) != nfu_Okay ) return( mul->status );
380 if( ptwXY_mul2_s_ptwXY( smr, mul, ptwXY1, ptwXY2, x, y, x2, y2, level ) != nfu_Okay ) return( mul->status );
381 ptwXY_mul2_s_ptwXY( smr, mul, ptwXY1, ptwXY2, x1, y1, x, y, level );
382 return( mul->status );
383}
384/*
385************************************************************
386*/
388
389 int isNAN1, isNAN2;
390 int64_t i, j, k, zeros = 0, length, iYs;
391 double x1, x2, y1, y2, u1, u2, v1, v2, y, xz, nan = nfu_getNAN( ), s1, s2;
392 ptwXYPoints *div = NULL;
393 ptwXYPoint *p;
394 nfu_status status = ptwXY_simpleCoalescePoints( smr, ptwXY1 );
395
396 if( status != nfu_Okay ) goto Err;
397 if( ptwXY_simpleCoalescePoints( smr, ptwXY2 ) != nfu_Okay ) goto Err;
398
399 if( ptwXY1->interpolation == ptwXY_interpolationOther ) {
400 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Source1: Other interpolation not allowed." );
401 return( NULL );
402 }
403 if( ptwXY2->interpolation == ptwXY_interpolationOther ) {
404 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_otherInterpolation, "Source2: Other interpolation not allowed." );
405 return( NULL );
406 }
407
408 if( ( ptwXY1->interpolation == ptwXY_interpolationFlat ) || ( ptwXY1->interpolation == ptwXY_interpolationFlat ) ) {
409 div = ptwXY_div_ptwXY_forFlats( smr, ptwXY1, ptwXY2, safeDivide );
410 if( div == NULL ) smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_Error, "Via." );
411 return( div );
412 }
413
414 if( ptwXY_areDomainsMutual( smr, ptwXY1, ptwXY2 ) != nfu_Okay ) {
415 double domainMin1, domainMax1, domainMin2, domainMax2;
416
417 ptwXY_domainMin( NULL, ptwXY1, &domainMin1 );
418 ptwXY_domainMax( NULL, ptwXY1, &domainMax1 );
419 ptwXY_domainMin( NULL, ptwXY2, &domainMin2 );
420 ptwXY_domainMax( NULL, ptwXY2, &domainMax2 );
421
422 smr_setReportError2( smr, nfu_SMR_libraryID, nfu_domainsNotMutual, "Domains not mutual (%.17e, %.17e) vs (%.17e, %.17e).",
423 domainMin1, domainMax1, domainMin2, domainMax2 );
424 return( NULL );
425 }
426
427 if( ( div = ptwXY_union( smr, ptwXY1, ptwXY2, ptwXY_union_fill | ptwXY_union_mergeClosePoints ) ) == NULL ) goto Err;
428 for( i = 0, p = div->points; i < div->length; i++, p++ ) {
429 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY2, p->x, &y ) != nfu_Okay ) goto Err;
430 if( y == 0. ) {
431 if( p->y == 0. ) {
432 iYs = 0;
433 y1 = 0.;
434 y2 = 0.;
435 if( i > 0 ) {
436 if( ( status = ptwXY_getSlopeAtX( smr, ptwXY1, p->x, '-', &s1 ) ) != nfu_Okay ) {
437 if( status != nfu_XOutsideDomain ) goto Err;
438 s1 = 0.;
439 }
440 if( ( status = ptwXY_getSlopeAtX( smr, ptwXY2, p->x, '-', &s2 ) ) != nfu_Okay ) goto Err;
441 if( s2 == 0. ) {
442 y1 = nan; }
443 else {
444 y1 = s1 / s2;
445 }
446 iYs++;
447 }
448 if( i < ( div->length - 1 ) ) {
449 if( ( status = ptwXY_getSlopeAtX( smr, ptwXY1, p->x, '+', &s1 ) ) != nfu_Okay ) {
450 if( status != nfu_XOutsideDomain ) goto Err;
451 s1 = 0.;
452 }
453 if( ( status = ptwXY_getSlopeAtX( smr, ptwXY2, p->x, '+', &s2 ) ) != nfu_Okay ) goto Err;
454 if( s2 == 0. ) {
455 y2 = nan; }
456 else {
457 y2 = s1 / s2;
458 }
459 iYs++;
460 }
461 p->y = ( y1 + y2 ) / iYs;
462 if( nfu_isNAN( p->y ) ) zeros++; }
463 else {
464 if( !safeDivide ) {
466 goto Err2;
467 }
468 zeros++;
469 p->y = nan;
470 } }
471 else {
472 p->y /= y;
473 }
474 }
475 length = div->length - 1;
476 if( length > 0 ) {
477 x2 = div->points[length].x;
478 for( i = length - 1; i >= 0; i-- ) { /* Find and add y zeros and NAN not currently in div's. */
479 x1 = div->points[i].x;
480 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x1, &u1 ) != nfu_Okay ) goto Err;
481 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x2, &u2 ) != nfu_Okay ) goto Err;
482 if( ptwXY_getValueAtX_signal_XOutsideDomainError( smr, __LINE__, __func__, ptwXY2, x1, &v1 ) != nfu_Okay ) goto Err;
483 if( ptwXY_getValueAtX_signal_XOutsideDomainError( smr, __LINE__, __func__, ptwXY2, x2, &v2 ) != nfu_Okay ) goto Err;
484 if( u1 * u2 < 0 ) {
485 xz = ( u1 * x2 - u2 * x1 ) / ( u1 - u2 );
486 if( ptwXY_setValueAtX( smr, div, xz, 0. ) != nfu_Okay ) goto Err;
487 }
488 if( v1 * v2 < 0 ) {
489 if( !safeDivide ) {
491 goto Err2;
492 }
493 zeros++;
494 xz = ( v1 * x2 - v2 * x1 ) / ( v1 - v2 );
495 if( ptwXY_setValueAtX( smr, div, xz, nan ) != nfu_Okay ) goto Err;
496 }
497 x2 = x1;
498 }
499 if( ptwXY_simpleCoalescePoints( smr, div ) != nfu_Okay ) goto Err;
500 length = div->length;
501 x2 = div->points[div->length-1].x;
502 y2 = div->points[div->length-1].y;
503 isNAN2 = nfu_isNAN( y2 );
504 for( i = div->length - 2; i >= 0; i-- ) { /* Make interpolation fit accuracy. Work backwards so new points will not mess up loop. */
505 x1 = div->points[i].x;
506 y1 = div->points[i].y;
507 isNAN1 = nfu_isNAN( y1 );
508 if( !isNAN1 || !isNAN2 ) {
509 if( ptwXY_div_s_ptwXY( smr, div, ptwXY1, ptwXY2, x1, y1, x2, y2, 0, isNAN1, isNAN2 ) != nfu_Okay ) goto Err;
510 }
511 x2 = x1;
512 y2 = y1;
513 isNAN2 = isNAN1;
514 }
515 ptwXY_update_biSectionMax( div, (double) length );
516 if( zeros ) {
517 if( ptwXY_simpleCoalescePoints( smr, div ) != nfu_Okay ) goto Err;
518 for( i = 0; i < div->length; i++ ) if( !nfu_isNAN( div->points[i].y ) ) break;
519 if( nfu_isNAN( div->points[0].y ) ) { /* Special case for first point. */
520 if( i == div->length ) { /* They are all nan's, what now? */
521 zeros = 0;
522 for( i = 0; i < div->length; i++ ) div->points[i].y = 0.; }
523 else {
524 div->points[0].y = 2. * div->points[i].y;
525 zeros--;
526 }
527 }
528 for( i = div->length - 1; i > 0; i-- ) if( !nfu_isNAN( div->points[i].y ) ) break;
529 if( nfu_isNAN( div->points[div->length - 1].y ) ) { /* Special case for last point. */
530 div->points[div->length - 1].y = 2. * div->points[i].y;
531 zeros--;
532 }
533 if( zeros ) {
534 for( i = 0; i < div->length; i++ ) if( nfu_isNAN( div->points[i].y ) ) break;
535 for( k = i + 1, j = i; k < div->length; k++ ) {
536 if( nfu_isNAN( div->points[k].y ) ) continue;
537 div->points[j] = div->points[k];
538 j++;
539 }
540 div->length = j;
541 }
542 }
543 }
544 return( div );
545
546Err:
547 if( status == nfu_XOutsideDomain ) {
548 smr_setReportError2p( smr, nfu_SMR_libraryID, nfu_XOutsideDomain, "x-value outside domain." ); }
549 else {
551 }
552Err2:
553 if( div ) ptwXY_free( div );
554 return( NULL );
555}
556/*
557************************************************************
558*/
559static nfu_status ptwXY_div_s_ptwXY( statusMessageReporting *smr, ptwXYPoints *div, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2,
560 double x1, double y1, double x2, double y2, int level, int isNAN1, int isNAN2 ) {
561
562 nfu_status status;
563 double u1, u2, v1, v2, v, x, y, yp, dx, a1, a2;
564
565 if( ( x2 - x1 ) < ClosestAllowXFactor * DBL_EPSILON * ( fabs( x1 ) + fabs( x2 ) ) ) return( nfu_Okay );
566 if( level >= div->biSectionMax ) return( nfu_Okay );
567 level++;
568 if( ( status = ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x1, &u1 ) ) != nfu_Okay ) return( status );
569 if( ( status = ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x2, &u2 ) ) != nfu_Okay ) return( status );
570 if( ( status = ptwXY_getValueAtX_signal_XOutsideDomainError( smr, __LINE__, __func__, ptwXY2, x1, &v1 ) ) != nfu_Okay ) return( status );
571 if( ( status = ptwXY_getValueAtX_signal_XOutsideDomainError( smr, __LINE__, __func__, ptwXY2, x2, &v2 ) ) != nfu_Okay ) return( status );
572 if( isNAN1 ) {
573 x = 0.5 * ( x1 + x2 );
574 if( ( status = ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x, &u1 ) ) != nfu_Okay ) return( status );
575 if( ( status = ptwXY_getValueAtX_signal_XOutsideDomainError( smr, __LINE__, __func__, ptwXY2, x, &v1 ) ) != nfu_Okay ) return( status );
576 y = u1 / v1; }
577 else if( isNAN2 ) {
578 x = 0.5 * ( x1 + x2 );
579 if( ( status = ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY1, x, &u2 ) ) != nfu_Okay ) return( status );
580 if( ( status = ptwXY_getValueAtX_signal_XOutsideDomainError( smr, __LINE__, __func__, ptwXY2, x, &v2 ) ) != nfu_Okay ) return( status );
581 y = u2 / v2; }
582 else {
583 if( ( u1 == u2 ) || ( v1 == v2 ) ) return( nfu_Okay );
584 if( ( y1 == 0. ) || ( y2 == 0. ) ) { /* Handle special case of 0 where accuracy can never be met. */
585 x = 0.5 * ( x1 + x2 ); }
586 else {
587 if( ( u1 * u2 < 0. ) ) return( nfu_Okay ); /* Assume rounding error and no point needed. */
588 a1 = sqrt( fabs( u1 ) );
589 a2 = sqrt( fabs( u2 ) );
590 x = ( a2 * x1 + a1 * x2 ) / ( a2 + a1 );
591 }
592 dx = x2 - x1;
593 v = v1 * ( x2 - x ) + v2 * ( x - x1 );
594 if( ( v1 == 0. ) || ( v2 == 0. ) || ( v == 0. ) ) return( nfu_Okay ); /* Probably not correct, but I had to do something. */
595 yp = ( u1 / v1 * ( x2 - x ) + u2 / v2 * ( x - x1 ) ) / dx;
596 y = ( u1 * ( x2 - x ) + u2 * ( x - x1 ) ) / v;
597 if( fabs( y - yp ) < fabs( y * div->accuracy ) ) return( nfu_Okay );
598 }
599 if( ( status = ptwXY_setValueAtX( smr, div, x, y ) ) != nfu_Okay ) return( status );
600 if( ( status = ptwXY_div_s_ptwXY( smr, div, ptwXY1, ptwXY2, x, y, x2, y2, level, 0, isNAN2 ) ) != nfu_Okay ) return( status );
601 status = ptwXY_div_s_ptwXY( smr, div, ptwXY1, ptwXY2, x1, y1, x, y, level, isNAN1, 0 );
602 return( status );
603}
604/*
605************************************************************
606*/
607static ptwXYPoints *ptwXY_div_ptwXY_forFlats( statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2, int safeDivide ) {
608
609 int64_t i;
610 ptwXYPoints *div = NULL;
611 ptwXYPoint *p;
612 double y;
613
614 if( ptwXY1->interpolation != ptwXY_interpolationFlat ) {
615 smr_setReportError2( smr, nfu_SMR_libraryID, nfu_invalidInterpolation, "Source1 interpolation not 'flat' but '%s'.",
616 ptwXY1->interpolationString );
617 return( NULL );
618 }
619 if( ptwXY2->interpolation != ptwXY_interpolationFlat ) {
620 smr_setReportError2( smr, nfu_SMR_libraryID, nfu_invalidInterpolation, "Source2 interpolation not 'flat' but '%s'.",
621 ptwXY2->interpolationString );
622 return( NULL );
623 }
624
625 if( ( div = ptwXY_union( smr, ptwXY1, ptwXY2, ptwXY_union_fill | ptwXY_union_mergeClosePoints ) ) != NULL ) {
626 for( i = 0, p = div->points; i < div->length; i++, p++ ) {
627 if( ptwXY_getValueAtX_ignore_XOutsideDomainError( smr, ptwXY2, p->x, &y ) != nfu_Okay ) goto Err;
628 if( y == 0. ) {
629 if( ( safeDivide ) && ( p->y == 0 ) ) {
631 goto Err;
632 } }
633 else {
634 p->y /= y;
635 }
636 }
637 }
638 return( div );
639
640Err:
641 if( div ) ptwXY_free( div );
642 return( NULL );
643}
644/*
645************************************************************
646*/
647static nfu_status ptwXY_getValueAtX_ignore_XOutsideDomainError( statusMessageReporting *smr, ptwXYPoints *ptwXY1, double x, double *y ) {
648
649 nfu_status status = ptwXY_getValueAtX( smr, ptwXY1, x, y );
650
651 if( status == nfu_XOutsideDomain ) status = nfu_Okay;
652 return( status );
653}
654/*
655************************************************************
656*/
657static nfu_status ptwXY_getValueAtX_signal_XOutsideDomainError( statusMessageReporting *smr, int line,
658 char const *function, ptwXYPoints *ptwXY1, double x, double *y ) {
659
660 nfu_status status = ptwXY_getValueAtX( smr, ptwXY1, x, y );
661
662 if( status == nfu_XOutsideDomain ) {
663 double domainMin, domainMax;
664
665 ptwXY_domainMin( NULL, ptwXY1, &domainMin );
666 ptwXY_domainMax( NULL, ptwXY1, &domainMax );
667
668 smr_setReportError2( smr, nfu_SMR_libraryID, nfu_XOutsideDomain, "x-value = %.17e outside domain (%.17e, %.17e)",
669 x, domainMin, domainMin );
670 smr_setReportError( smr, NULL, __FILE__, line, function, nfu_SMR_libraryID, nfu_Error, "Via." );
671 }
672 return( status );
673}
G4double(*)(G4double) function
G4ThreadLocal T * G4GeomSplitter< T >::offset
int nfu_isNAN(double d)
@ nfu_domainsNotMutual
@ nfu_invalidInterpolation
@ nfu_Okay
@ nfu_XOutsideDomain
@ nfu_Error
@ nfu_divByZero
@ nfu_otherInterpolation
enum nfu_status_e nfu_status
int nfu_SMR_libraryID
double nfu_getNAN(void)
nfu_status ptwXY_neg(statusMessageReporting *smr, ptwXYPoints *ptwXY)
nfu_status ptwXY_setValueAtX(statusMessageReporting *smr, ptwXYPoints *ptwXY, double x, double y)
char const * ptwXY_interpolationToString(ptwXY_interpolation interpolation)
int64_t ptwXY_getNonOverflowLength(statusMessageReporting *smr, ptwXYPoints const *ptwXY)
Definition ptwXY_core.c:805
ptwXYPoints * ptwXY_clone(statusMessageReporting *smr, ptwXYPoints *ptwXY)
Definition ptwXY_core.c:302
struct ptwXYOverflowPoint_s ptwXYOverflowPoint
nfu_status ptwXY_areDomainsMutual(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2)
@ ptwXY_interpolationFlat
Definition ptwXY.h:38
@ ptwXY_interpolationLinLog
Definition ptwXY.h:37
@ ptwXY_interpolationLinLin
Definition ptwXY.h:37
@ ptwXY_interpolationOther
Definition ptwXY.h:38
struct ptwXYPoints_s ptwXYPoints
#define ptwXY_union_fill
Definition ptwXY.h:34
void ptwXY_update_biSectionMax(ptwXYPoints *ptwXY1, double oldLength)
Definition ptwXY_misc.c:37
#define ClosestAllowXFactor
Definition ptwXY.h:28
#define ptwXY_union_mergeClosePoints
Definition ptwXY.h:36
ptwXYPoints * ptwXY_union(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2, int unionOptions)
struct ptwXYPoint_s ptwXYPoint
ptwXYPoints * ptwXY_free(ptwXYPoints *ptwXY)
Definition ptwXY_core.c:782
nfu_status ptwXY_getSlopeAtX(statusMessageReporting *smr, ptwXYPoints *ptwXY, double x, char side, double *slope)
nfu_status ptwXY_domainMax(statusMessageReporting *smr, ptwXYPoints *ptwXY, double *value)
nfu_status ptwXY_getValueAtX(statusMessageReporting *smr, ptwXYPoints *ptwXY, double x, double *y)
nfu_status ptwXY_simpleCoalescePoints(statusMessageReporting *smr, ptwXYPoints *ptwXY)
Definition ptwXY_core.c:734
nfu_status ptwXY_domainMin(statusMessageReporting *smr, ptwXYPoints *ptwXY, double *value)
nfu_status ptwXY_div_fromDouble(statusMessageReporting *smr, ptwXYPoints *ptwXY, double value)
nfu_status ptwXY_add_double(statusMessageReporting *smr, ptwXYPoints *ptwXY, double value)
ptwXYPoints * ptwXY_mul_ptwXY(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2)
nfu_status ptwXY_sub_doubleFrom(statusMessageReporting *smr, ptwXYPoints *ptwXY, double value)
nfu_status ptwXY_div_doubleFrom(statusMessageReporting *smr, ptwXYPoints *ptwXY, double value)
ptwXYPoints * ptwXY_add_ptwXY(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2)
ptwXYPoints * ptwXY_binary_ptwXY(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2, double v1, double v2, double v1v2)
nfu_status ptwXY_slopeOffset(statusMessageReporting *smr, ptwXYPoints *ptwXY, double slope, double offset)
nfu_status ptwXY_mul_double(statusMessageReporting *smr, ptwXYPoints *ptwXY, double value)
ptwXYPoints * ptwXY_sub_ptwXY(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2)
ptwXYPoints * ptwXY_div_ptwXY(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2, int safeDivide)
ptwXYPoints * ptwXY_mul2_ptwXY(statusMessageReporting *smr, ptwXYPoints *ptwXY1, ptwXYPoints *ptwXY2)
nfu_status ptwXY_mod(statusMessageReporting *smr, ptwXYPoints *ptwXY, double m, int pythonMod)
nfu_status ptwXY_sub_fromDouble(statusMessageReporting *smr, ptwXYPoints *ptwXY, double value)
#define smr_setReportError2(smr, libraryID, code, fmt,...)
#define smr_setReportError2p(smr, libraryID, code, fmt)
int smr_setReportError(statusMessageReporting *smr, void *userInterface, char const *file, int line, char const *function, int libraryID, int code, char const *fmt,...)
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
ptwXYOverflowPoint overflowHeader
Definition ptwXY.h:92
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
#define DBL_EPSILON
Definition templates.hh:66