TPCCLIB
Loading...
Searching...
No Matches
integrate.c
Go to the documentation of this file.
1
4/*****************************************************************************/
5#include "tpcclibConfig.h"
6/*****************************************************************************/
7#include <stdio.h>
8#include <stdlib.h>
9#include <math.h>
10#include <time.h>
11#include <string.h>
12/*****************************************************************************/
13#include "tpcextensions.h"
14/*****************************************************************************/
15#include "tpcli.h"
16/*****************************************************************************/
17
18/*****************************************************************************/
37 double *x,
39 double *y,
41 const int nr,
43 double *yi,
54 const int se,
56 const int verbose
57) {
58 if(verbose>0) printf("liIntegrate(x, y, %d, yi, %d)\n", nr, se);
59 /* Check for data */
60 if(nr<1) return 1;
61 if(x==NULL || y==NULL || yi==NULL) return 1;
62
63 /* Initiate the first integral to 0 */
64 yi[0]=0.0;
65
66 /* Extrapolate the initial phase */
67 if(se==0) {
68 /* No extrapolation */
69 } else if(se==1) {
70 /* Extrapolation with a rectangle */
71 if(x[0]>0.0) yi[0]+=x[0]*y[0];
72 } else if(se==2) {
73 /* Extrapolation with a triangle starting from zero */
74 if(x[0]>0.0 && y[0]>0.0) yi[0]+=0.5*x[0]*y[0];
75 } else if(se==3) {
76 /* Extrapolation with a triangle, if small gap */
77 if(x[0]>0.0 && y[0]>0.0) {
78 if(nr<2 || (2.0*x[0]-x[1])<1.0E-10)
79 yi[0]+=0.5*x[0]*y[0];
80 }
81 } else if(se==4) {
82 /* Extrapolation with a triangle */
83 if(x[0]>0.0 && y[0]>0.0) {
84 if(nr<2 || (2.0*x[0]-x[1])<1.0E-10)
85 yi[0]+=0.5*x[0]*y[0];
86 else {
87 double nx;
88 nx=2.0*x[0]-x[1];
89 yi[0]+=0.5*(x[0]-nx)*y[0];
90 }
91 }
92 }
93
94 /* Dot-to-dot for the rest of data */
95 for(int j=1; j<nr; j++) yi[j]=yi[j-1]+0.5*(y[j]+y[j-1])*(x[j]-x[j-1]);
96
97 if(verbose>3) printf("liIntegrate() ready\n");
98 return 0;
99}
100/*****************************************************************************/
101
102/*****************************************************************************/
123 double *x1,
126 double *x2,
128 double *y,
130 int nr,
132 double *ie,
134 double *iie,
136 const int verbose
137) {
138 if(verbose>0) printf("liIntegratePET(x1, x2, y, %d, i, ii)\n", nr);
139
140 /* Check for data */
141 if(nr<1) return(1);
142 if(x1==NULL || x2==NULL || y==NULL) return(1);
143 /* No use to do anything if both output arrays are NULL */
144 if(ie==NULL && iie==NULL) return(0);
145
146 int i;
147 double x, xs, fdur, half_fdur, gap, gap_y, midi, midii, fulli;
148 double box_integral=0.0, box_integral2=0.0;
149 double gap_integral=0.0, gap_integral2=0.0;
150 double prev_x2=x1[0], prev_fdur=0.0;
151
152 for(i=0; i<nr; i++) {
153 /* Duration of this time frame */
154 fdur=x2[i]-x1[i]; if(!(fdur>=0.0)) return(2);
155 half_fdur=0.5*fdur;
156 x=0.5*(x1[i]+x2[i]);
157 if(verbose>3) {
158 printf(" x=%g\n", x);
159 printf(" fdur=%g\n", fdur);
160 }
161 /* Integral of a possible gap between frames */
162 gap=x1[i]-prev_x2;
163 if(i>0 && gap>1.0E-10) {
164 /* Estimate y during gap as weighted mean of previous and this frame */
165 gap_y=fdur*y[i]+prev_fdur*(y[i-1]);
166 xs=fdur+prev_fdur; if(xs>0.0) gap_y/=xs;
167 gap_integral=gap*gap_y;
168 gap_integral2=gap*0.5*(box_integral+box_integral+gap_integral);
169 if(verbose>3) {
170 printf(" gap=%g\n", gap);
171 printf(" gap_y=%g\n", gap_y);
172 printf(" gap_integral=%g\n", gap_integral);
173 printf(" gap_integral2=%g\n", gap_integral2);
174 }
175 /* Add gap integrals */
176 box_integral+=gap_integral;
177 box_integral2+=gap_integral2;
178 }
179 /* Calculate integrals at frame middle time */
180 midi=y[i]*half_fdur;
181 midii=0.5*(box_integral+box_integral+midi)*half_fdur;
182 if(verbose>4) {
183 printf(" midframe_integral=%g\n", midi);
184 printf(" midframe_integral2=%g\n", midii);
185 }
186 if(ie!=NULL) ie[i]=box_integral+midi;
187 if(iie!=NULL) iie[i]=box_integral2+midii;
188 /* Add full frame integrals */
189 fulli=fdur*y[i];
190 box_integral2+=0.5*(box_integral+box_integral+fulli)*fdur;
191 box_integral+=fulli;
192 if(verbose>3) {
193 printf(" box_integral=%g\n", box_integral);
194 printf(" box_integral2=%g\n", box_integral2);
195 }
196 /* Prepare for the next frame */
197 prev_x2=x2[i]; prev_fdur=fdur;
198 } // next time frame
199
200 if(verbose>3) printf("liIntegratePET() ready\n");
201 return(0);
202}
203/*****************************************************************************/
204
205/*****************************************************************************/
222 double *x1,
225 double *x2,
227 double *y,
229 int nr,
231 double *ie,
233 double *iie,
235 const int verbose
236) {
237 if(verbose>0) {printf("liIntegrateFE(x1, x2, y, %d, i, ii, %d)\n", nr, verbose); fflush(stdout);}
238
239 /* Check for data */
240 if(nr<1 || x1==NULL || x2==NULL || y==NULL) return(TPCERROR_NO_DATA);
241 /* No use to do anything if both output arrays are NULL */
242 if(ie==NULL && iie==NULL) return(TPCERROR_OK);
243
244 double prev_fdur=0.0;
245 double prev_iy=0.0, prev_iiy=0.0;
246 double iy=0.0, iiy=0.0;
247 for(int i=0; i<nr; i++) {
248 /* Duration of this time frame */
249 double fdur=x2[i]-x1[i];
250 if(!isfinite(fdur)) return(TPCERROR_INVALID_X);
251 if(fabs(fdur)<1.0E-10) { // frame length is about zero
252 if(ie!=NULL) ie[i]=prev_iy;
253 if(iie!=NULL) iie[i]=prev_iiy;
254 continue;
255 }
256 if(fdur<0.0) return(TPCERROR_INVALID_X);
257 /* Check for gap */
258 if(i>0) {
259 double gap=x1[i]-x2[i-1];
260 if(gap<0.0) return(TPCERROR_INVALID_X); // overlap not accepted
261 if(gap>1.0E-10) {
262 /* Estimate the integral of during the gap;
263 estimate y during gap as weighted mean of previous and this frame */
264 double gap_y=fdur*y[i]+prev_fdur*(y[i-1]);
265 double xs=fdur+prev_fdur; if(xs>0.0) gap_y/=xs;
266 double gap_integral=gap*gap_y;
267 double gap_integral2=gap*0.5*(iy+iy+gap_integral);
268 /* Add gap integrals */
269 iy+=gap_integral;
270 iiy+=gap_integral2;
271 }
272 }
273 /* Calculate integrals at frame end */
274 double box_integral=fdur*y[i];
275 double box_integral2=fdur*0.5*(iy+iy+box_integral);
276 /* Add frame integrals */
277 iy+=box_integral;
278 iiy+=box_integral2;
279 if(ie!=NULL) ie[i]=iy;
280 if(iie!=NULL) iie[i]=iiy;
281 /* Prepare for the next frame */
282 prev_fdur=fdur; prev_iy=iy; prev_iiy=iiy;
283 } // next time frame
284
285 return(TPCERROR_OK);
286}
287/*****************************************************************************/
288
289/*****************************************************************************/
313 double *x1,
317 double *x2,
320 double *y,
322 const size_t nr,
325 double *fhi,
327 const int verbose
328) {
329 if(verbose>0)
330 printf("liIntegrateHalfFrame(x1, x2, y, %zu, fhi, %d)\n", nr, verbose);
331
332 /* Check for data */
333 if(nr<1) return 1;
334 if(x1==NULL || x2==NULL || y==NULL || fhi==NULL) return 1;
335
336 /* If just one frame */
337 if(nr==1) {
338 if(verbose>2) printf("just one frame.\n");
339 fhi[0]=y[0]*(x2[0]-x1[0])/2.0;
340 return 0;
341 }
342
343 /* Calculate frame middle times and durations / 2.
344 Check that frames durations are >=0.
345 Check that frame times are in ascending order.
346 */
347 double hfdur[nr], x[nr];
348 for(size_t i=0; i<nr; i++) {
349 x[i]=0.5*(x1[i]+x2[i]);
350 hfdur[i]=0.5*(x2[i]-x1[i]);
351 if(hfdur[i]<0.0) {
352 if(verbose>0) fprintf(stderr, "negative frame length.\n");
353 return 2;
354 }
355 if(i>0 && x[i]<x[i-1]) {
356 if(verbose>0) fprintf(stderr, "frame times not ascending.\n");
357 return 3;
358 }
359 }
360
361 /* If just two frames */
362 if(nr<3) {
363 if(verbose>2) printf("just two frames.\n");
364 double k, dx;
365 dx=x[1]-x[0];
366 if(dx<1.0E-100) {fhi[0]=y[0]*hfdur[0]; fhi[1]=y[1]*hfdur[1]; return 0;}
367 k=(y[1]-y[0])/dx;
368 fhi[0]=hfdur[0]*(y[0]-k*0.5*hfdur[0]);
369 fhi[1]=hfdur[1]*(y[1]-k*0.5*hfdur[1]);
370 return 0;
371 }
372
373 /* Compute data matrix for solving (very simply) the y values at frame middle
374 times */
375 double A[2][nr], B[nr], xdif;
376 A[0][0]=1.0; A[1][0]=0.0; B[0]=y[0];
377 for(size_t i=1; i<nr-1; i++) {
378 xdif=x[i+1]-x[i];
379 if(!(hfdur[i]>1.0E-100) || !(xdif>1.0E-100)) { // catches both zero and NaN
380 A[0][i]=0.0; A[1][i]=0.0; B[i]=y[i];
381 } else {
382 A[0][i]=4.0*(x[i]-x[i-1])/hfdur[i] - (x[i+1]-x[i-1])/xdif;
383 A[1][i]=(x[i]-x[i-1])/xdif;
384 B[i]=4.0*y[i]*(x[i]-x[i-1])/hfdur[i];
385 }
386 }
387 A[0][nr-1]=1.0; A[1][nr-1]=0.0; B[nr-1]=y[nr-1];
388 if(verbose>4) {
389 printf("A[1]\tA[2]\t\tB\n");
390 for(size_t i=0; i<nr; i++) printf("%g\t%g\t\t%g\n", A[0][i], A[1][i], B[i]);
391 }
392
393 /* Solve */
394 for(size_t i=1; i<nr-1; i++) {
395 if(fabs(A[0][i])<1.0E-100) continue;
396 A[0][i]-=A[1][i-1]; B[i]-=B[i-1];
397 A[1][i]/=A[0][i]; B[i]/=A[0][i]; A[0][i]=1.0;
398 }
399 if(verbose>5) {
400 printf("A[1]\tA[2]\t\tB\n");
401 for(size_t i=0; i<nr; i++) printf("%g\t%g\t\t%g\n", A[0][i], A[1][i], B[i]);
402 }
403 fhi[0]=y[0]; fhi[nr-1]=y[nr-1];
404 for(size_t i=nr-2; i>0; i--) {
405 fhi[i]=B[i]-fhi[i+1]*A[1][i];
406 if(verbose>5) printf("X[%zu]=%g\n", i+1, fhi[i]);
407 }
408 /* Set any NaNs to original values (which of course may be NaN as well) */
409 for(size_t i=1; i<nr-1; i++) if(isnan(fhi[i])) fhi[i]=y[i];
410 if(verbose>10) {
411 printf("estimated frame mid values:\n");
412 for(size_t i=0; i<nr; i++) printf(" %g\n", fhi[i]);
413 }
414
415 /* Compute the first half integrals */
416 double newi, lasty=fhi[0];
417 double dx=x[1]-x[0];
418 if(!(dx>1.0E-100)) fhi[0]*=hfdur[0];
419 else fhi[0]=hfdur[0]*(fhi[0]-0.5*hfdur[0]*(fhi[1]-fhi[0])/dx);
420 for(size_t i=1; i<nr; i++) {
421 dx=x[i]-x[i-1];
422 if(!(dx>1.0E-100)) newi=fhi[i]*hfdur[0];
423 else newi=hfdur[i]*(fhi[i]-0.5*hfdur[i]*(fhi[i]-lasty)/dx);
424 lasty=fhi[i]; fhi[i]=newi;
425 }
426
427 if(verbose>1) printf("liIntegrateHalfFrame() ready\n");
428 return 0;
429}
430/*****************************************************************************/
431
432/*****************************************************************************/
448 double *x,
450 double *y,
452 const int nr,
454 double *d,
456 double *dd,
458 const int verbose
459) {
460 if(verbose>0) printf("liDerivate(x, y, %d, *d, *dd, %d)\n", nr, verbose);
461 /* Check for data */
462 if(nr<2) return(1);
463 if(x==NULL || y==NULL || d==NULL) return(1);
464
465 double dx;
466
467 /* Estimate the first data point */
468 d[0]=0.0; if(dd!=NULL) dd[0]=0.0;
469 if(fabs(y[0])>1.0E-20) {
470 dx=x[1]-x[0]; if(!(dx>0.0)) return(2);
471 d[0]=y[0]/dx; if(!isfinite(d[0])) return(3);
472 if(dd!=NULL) {dd[0]=d[0]/dx; if(!isfinite(dd[0])) return(4);}
473 }
474
475 /* Following data points */
476 for(int i=1; i<nr; i++) {
477 dx=x[i]-x[i-1]; if(!(dx>0.0)) return(2);
478 d[i]=(y[i]-y[i-1])/dx; if(!isfinite(d[i])) return(3);
479 if(dd!=NULL) {dd[i]=(d[i]-d[i-1])/dx; if(!isfinite(dd[i])) return(4);}
480 }
481
482 if(verbose>3) printf("liDerivate() ready\n");
483 return(0);
484}
485/*****************************************************************************/
486
487/*****************************************************************************/
495 double *x,
497 double *y,
499 const int nr,
501 double *d,
503 double *dd,
505 const int verbose
506) {
507 if(verbose>0) printf("liDerivate3(x, y, %d, *d, *dd, %d)\n", nr, verbose);
508 /* Check for data */
509 if(nr<3) return(1);
510 if(x==NULL || y==NULL || d==NULL) return(1);
511
512 int i=0;
513 /* Estimate the first data point */
514 if(linRegr3p(x[i]+x[i]-x[i+1], 0.0, x[i], y[i], x[i+1], y[i+1], &d[i], NULL)) return(2);
515 /* Following data points except the last */
516 for(++i; i<nr-1; i++)
517 if(linRegr3p(x[i-1], y[i-1], x[i], y[i], x[i+1], y[i+1], &d[i], NULL)) return(3);
518 /* The last point */
519 d[i]=(y[i]-y[i-1])/(x[i]-x[i-1]);
520 if(!isfinite(d[i])) return(4);
521
522 /* Second derivative */
523 if(dd!=NULL) {
524 return(liDerivate3(x, d, nr, dd, NULL, verbose));
525 }
526
527 if(verbose>3) printf("liDerivate3() ready\n");
528 return(0);
529}
530/*****************************************************************************/
531
532/*****************************************************************************/
int linRegr3p(double x1, double y1, double x2, double y2, double x3, double y3, double *slope, double *ic)
Linear regression for three (x,y) points.
Definition doubleutil.c:521
int liIntegrateHalfFrame(double *x1, double *x2, double *y, const size_t nr, double *fhi, const int verbose)
Calculate the integrals (AUC) of the first halves of PET frames based on dot-to-dot linear interpolat...
Definition integrate.c:309
int liDerivate3(double *x, double *y, const int nr, double *d, double *dd, const int verbose)
Simplistic derivation of PET TAC using regression line over three points.
Definition integrate.c:493
int liIntegrateFE(double *x1, double *x2, double *y, int nr, double *ie, double *iie, const int verbose)
Linear integration of PET TAC to frame end times.
Definition integrate.c:219
int liIntegrate(double *x, double *y, const int nr, double *yi, const int se, const int verbose)
Linear integration of TAC with trapezoidal method.
Definition integrate.c:33
int liIntegratePET(double *x1, double *x2, double *y, int nr, double *ie, double *iie, const int verbose)
Calculate PET TAC AUC from start to each time frame, as averages during each frame.
Definition integrate.c:120
int liDerivate(double *x, double *y, const int nr, double *d, double *dd, const int verbose)
Simplistic derivation of TAC as Δy divided by Δx, in relation to the previous point.
Definition integrate.c:444
Header file for library libtpcextensions.
@ TPCERROR_INVALID_X
Invalid sample time.
@ TPCERROR_OK
No error.
@ TPCERROR_NO_DATA
File contains no data.
Header file for libtpcli.