TPCCLIB
Loading...
Searching...
No Matches
integrate.c File Reference

Linear integration. More...

#include "tpcclibConfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include "tpcextensions.h"
#include "tpcli.h"

Go to the source code of this file.

Functions

int liIntegrate (double *x, double *y, const int nr, double *yi, const int se, const int verbose)
 Linear integration of TAC with trapezoidal method.
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.
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.
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 interpolation, assuming that original y values represent the mean value during the frame, i.e. AUC(frame start - frame end time)/frame duration.
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.
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.

Detailed Description

Linear integration.

Definition in file integrate.c.

Function Documentation

◆ liDerivate()

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.

The derivative for point i is calculated as d[i]=(y[i]-y[i-1])/(x[i]-x[i-1]). For the first point, i=0, it is assumed that d[0]=0 if y[0]=0; otherwise we assume an imaginary previous data point y[-1]=0 at x[-1]=x[0]-(x[1]-x[0]) and thus d[0]=y[0]/(x[1]-x[0]).

See also
liInterpolate, liIntegrate, liDerivate3
Author
Vesa Oikonen
Returns
0 if successful, otherwise >0.
Parameters
xArray of input data x (time) values; obligatory. Data must be sorted by ascending x, and consecutive points must not have the same x. Negative x is accepted.
yArray of input data y (concentration) values; obligatory.
nrNumber of samples in input data; obligatory; must be >1.
dArray for derivatives at each x; obligatory.
ddArray for 2nd derivatives at each x; NULL if not needed.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 444 of file integrate.c.

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}

Referenced by tacDelayCMFit().

◆ liDerivate3()

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.

See also
liDerivate, liInterpolate, liIntegrate
Author
Vesa Oikonen
Returns
0 if successful, otherwise >0.
Parameters
xArray of input data x values (sample times); obligatory.
yArray of input data y (concentration) values; obligatory.
nrNumber of samples in input data; obligatory; must be >1.
dArray for derivatives at each x; obligatory.
ddArray for 2nd derivatives at each x; NULL if not needed.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 493 of file integrate.c.

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}
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 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

Referenced by liDerivate3(), and tacDelayCMFit().

◆ liIntegrate()

int liIntegrate ( double * x,
double * y,
const int nr,
double * yi,
const int se,
const int verbose )

Linear integration of TAC with trapezoidal method.

Use this function for input data, or PET data when frame start and end times are not known. Data must be frequently sampled to get accurate results. AUC calculation is started from time 0 or first input sample time, whichever is smaller. Very simple data extrapolation can be optionally enabled. Results will be wrong if data contains NaNs. To get the same result as with integrate() in the libtpcmodel, set se=3.

See also
liInterpolate, liIntegratePET
Author
Vesa Oikonen
Returns
0 if successful, otherwise >0.
Parameters
xArray of input data x (time) values; obligatory. Data must be sorted by ascending x, but consecutive points may have the same x. Negative x is accepted, AUCs are then started from the first x, otherwise from 0.
yArray of input data y (concentration) values; obligatory.
nrNumber of samples in input data; obligatory.
yiArray for integrals (AUCs) at each x; obligatory.
seExtrapolation setting for the start of data:
  • 0= assuming y=0 when x<x[0]
  • 1= assuming y=y[0] when 0<=x<x[0] and y=0 when x<x[0]<0
  • 2= assuming y=0 when x<=0 and x[0]>0, and y=x*y[0]/x[0] when 0<x<x[0] and y[0]>0
  • 3= same as '2' if 2*x[0]-x[1]<=0, otherwise same as '0'
  • 4= same as '2' if 2*x[0]-x[1]<=0, otherwise assuming y=0 when x<=2*x[0]-x[1], and y=(x-(2*x[0]-x[1]))*y[0]/x[0] when (2*x[0]-x[1])<x<x[0] and y[0]>0.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 33 of file integrate.c.

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}

Referenced by tacDelayCMFit(), and tacIntegrate().

◆ liIntegrateFE()

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.

Use this function for PET data when frame start and end times are known. AUC calculation is started from first frame start time, ignoring possible time gap before it. Any gaps between time frames are filled with an imaginary frame calculated as weighted average of previous and next frame. Frames must be in ascending time order and frame overlaps removed.

See also
liIntegratePET, liInterpolate, liIntegrate, liInterpolateForPET
Author
Vesa Oikonen
Returns
enum tpcerror (TPCERROR_OK when successful).
Parameters
x1Array of input data x1 (frame start time) values; obligatory. Negative frame times are accepted.
x2Array of input data x2 (frame end time) values; obligatory. Negative frame times are accepted, but it is required that for each frame x2>=x1.
yArray of frame mean y (concentration) values; obligatory.
nrNumber of samples (frames); obligatory.
ieArray for integrals (AUCs) at each x (frame middle time); enter NULL if not needed.
iieArray for 2nd integrals (AUCs) at each x (frame middle time); enter NULL if not needed.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 219 of file integrate.c.

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}
@ TPCERROR_INVALID_X
Invalid sample time.
@ TPCERROR_OK
No error.
@ TPCERROR_NO_DATA
File contains no data.

Referenced by tacDelayCMFit(), and tacIntegrateFE().

◆ liIntegrateHalfFrame()

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 interpolation, assuming that original y values represent the mean value during the frame, i.e. AUC(frame start - frame end time)/frame duration.

Original data and new x values must be sorted by ascending x. Subsequent x values can have equal values, enabling the use of step functions. Negative x (time) values can be processed. Results will be wrong if data contains NaNs. The beginning and end of true TAC is assumed to follow a line drawn based on the two first/last TAC middle frame y values.

Note
Not for production use, just for play.
Author
Vesa Oikonen
See also
liInterpolate, liIntegratePET, liInterpolateForPET
Returns
0 if successful, otherwise >0.
Parameters
x1Array of PET frame start times; obligatory. Data must be sorted by ascending x, but consecutive points may have the same x. Negative x is accepted.
x2Array of PET frame end times; obligatory. Data must be sorted by ascending x, but consecutive points may have the same x. Negative x is accepted, but frame duration (x2-x1) must be >=0.
yArray of original TAC y (concentration) values, representing the average concentration during the PET frame; obligatory
nrNumber of samples in the data; obligatory
fhiArray for first-half frame integrals of TAC y (concentration) values for each PET frame; obligatory
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 309 of file integrate.c.

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}

◆ liIntegratePET()

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.

Use this function for PET data when frame start and end times are known. AUC at the end of frame i is calculated as AUCe[i]=AUCe[i-1]+y[i]*(x2[i]-x1[i]), and the integral for frame i is calculated as an average AUC[i]=(AUCe[i]+AUCe[i-1])/2. AUC calculation is started from first frame start time, ignoring possible time gap before it. Any gaps between time frames are filled with an imaginary frame calculated as weighted average of previous and next frame. Frames must be in ascending time order and frame overlaps removed; wrong order or large overlaps will lead to substantial errors in integrals without warning. Results will be wrong if data contains NaNs.

See also
liInterpolate, liIntegrate, liInterpolateForPET
Author
Vesa Oikonen
Returns
0 if successful, otherwise >0.
Parameters
x1Array of input data x1 (frame start time) values; obligatory. Negative frame times are accepted.
x2Array of input data x2 (frame end time) values; obligatory. Negative frame times are accepted, but it is required that for each frame x2>=x1.
yArray of frame mean y (concentration) values; obligatory.
nrNumber of samples (frames); obligatory.
ieArray for integrals (AUCs) at each x (frame middle time); enter NULL if not needed.
iieArray for 2nd integrals (AUCs) at each x (frame middle time); enter NULL if not needed.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 120 of file integrate.c.

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}

Referenced by bfm1TCM(), tacIntegrate(), tacInterpolate(), and tacInterpolateInto().