TPCCLIB
Loading...
Searching...
No Matches
tpcli.h File Reference

Header file for libtpcli. More...

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

Go to the source code of this file.

Functions

int liInterpolate (double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
 Linear interpolation and/or integration with trapezoidal method.
int liInterpolateForPET (double *x, double *y, const int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
 Linear TAC interpolation and/or integration to PET frames.
double liFirstStepSize (double *x, const int nr)
 Find the initial x step size.
unsigned int simSamples (double initStep, double maxStep, double endTime, int mode, double *x)
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

Header file for libtpcli.

Header file for library libtpcli.

Author
Vesa Oikonen

Definition in file tpcli.h.

Function Documentation

◆ liDerivate()

int liDerivate ( double * x,
double * y,
const int nr,
double * d,
double * dd,
const int verbose )
extern

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 )
extern

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().

◆ liFirstStepSize()

double liFirstStepSize ( double * x,
const int nr )
extern

Find the initial x step size.

Author
Vesa Oikonen
Returns
the first x[i+1]-x[i] that is > 0, or x[last] if not found, or 0 if even that was not possible.
Parameters
xArray of x (time) values; must be sorted by ascending x, but consecutive points may have the same x. Negative x is accepted. Array must not contain NaNs.
nrNumber of samples in data.

Definition at line 25 of file interpolate.c.

32 {
33 int i;
34 double s, d;
35 if(nr<1 || x==NULL) return 0.0;
36 s=x[nr-1];
37 for(i=1; i<nr; i++) {
38 d=x[i]-x[i-1];
39 if(d>1.0E-20) {s=d; break;}
40 }
41 return s;
42}

Referenced by liInterpolate().

◆ liIntegrate()

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

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 )
extern

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 )
extern

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 )
extern

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().

◆ liInterpolate()

int liInterpolate ( double * x,
double * y,
const int nr,
double * newx,
double * newy,
double * newyi,
double * newyii,
const int newnr,
const int se,
const int ee,
const int verbose )
extern

Linear interpolation and/or integration with trapezoidal method.

PET 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 interpolate() in the libtpcmodel, set se=3 and ee=1.

Author
Vesa Oikonen
Returns
0 if successful, otherwise >0.
See also
liInterpolateForPET, tacInterpolate, tacAUC
Todo
Compute tyi only if either of integrals is needed.
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. Array must not contain NaNs.
yArray of input data y (concentration) values; obligatory. Array must not contain NaNs.
nrNumber of samples in input data; obligatory.
newxArray of output data x values; obligatory. Must be in ascending order. Negative x is accepted. Array must not contain NaNs.
newyArray for interpolated (extrapolated) y values; NULL can be given if not needed.
newyiArray for integrals (AUCs); NULL can be given if not needed.
newyiiArrays for 2nd integrals; NULL can be given if not needed.
newnrNr of samples in output data; obligatory.
seExtrapolation setting for the start of data:
  • 0= assuming y=0 when newx<x[0]
  • 1= assuming y=y[0] when 0<=newx<x[0] and y=0 when newx<x[0]<0
  • 2= assuming y=0 when newx<=0 and x[0]>0, and y=newx*y[0]/x[0] when 0<newx<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 newx<=2*x[0]-x[1], and y=(newx-(2*x[0]-x[1]))*y[0]/x[0] when (2*x[0]-x[1])<newx<x[0] and y[0]>0.
eeExtrapolation setting for the end of data:
  • 0= assuming y=0 when newx>x[nr-1]
  • 1= assuming y=y[nr-1] when newx>x[nr-1]
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 139 of file interpolate.c.

179 {
180 if(verbose>0) printf("%s(x, y, %d, nx, ny, ni, ni2, %d, %d, %d)\n", __func__, nr, newnr, se, ee);
181 /* Check for data */
182 if(nr<1 || newnr<1) return 1;
183 if(x==NULL || y==NULL || newx==NULL) return 1;
184
185 int i, j;
186 double ty, tyi, tyii;
187 double ox1, ox2, oy1, oy2, oi1, oi2, oii1, oii2, dt, ndt;
188
189 /* Initiate first two input samples */
190 if(se==0) {
191 if(x[0]<0.0) {ox1=ox2=x[0]; oy1=oy2=y[0];}
192 else {ox1=0.0; ox2=x[0]; oy1=0.0; oy2=0.0;}
193 } else if(se==1) {
194 if(x[0]<0.0) {ox1=ox2=x[0]; oy1=oy2=y[0];}
195 else {ox1=0.0; ox2=x[0]; oy1=oy2=y[0];}
196 } else {
197 ox1=ox2=x[0];
198 oy1=oy2=y[0];
199 }
200 /* Extrapolate the initial phase with triangle... */
201 if(ox1>0.0 && se>=2) {
202 oy1=0.0;
203 if(se==2) { // always
204 ox1=0.0;
205 } else if(se==3 && y[0]>0.0) { // if y[0]>0
206 // and initial gap is not too big
207 if(liFirstStepSize(x, nr)-x[0] >= 1.0E-20)
208 ox1=0.0;
209 } else if(se==4 && y[0]>0.0) { // if y[0]>0
210 // if initial gap is not too big, start triangle from zero
211 if(liFirstStepSize(x, nr)-x[0] >= 1.0E-20)
212 ox1=0.0;
213 else
214 // otherwise start triangle from guessed zero sample
215 ox1=x[0]-liFirstStepSize(x, nr);
216 }
217 }
218
219 /* Integrals too */
220 oi1=oii1=0.0;
221 oi2=oi1 + (ox2-ox1)*(oy1+oy2)/2.0;
222 oii2=oii1 + (ox2-ox1)*(oi1+oi2)/2.0;
223 if(verbose>1) {
224 printf("ox1=%g oy1=%g oi1=%g oii1=%g\n", ox1, oy1, oi1, oii1);
225 printf("ox2=%g oy2=%g oi2=%g oii2=%g\n", ox2, oy2, oi2, oii2);
226 }
227
228 /* Set interpolated data before input data (even imaginary) to zero */
229 if(verbose>2) printf("before input start\n");
230 j=0; while(j<newnr && newx[j]<ox1) {
231 ty=tyi=tyii=0.0; if(verbose>2) printf(" ndt=%g\n", ox1-newx[j]);
232 if(verbose>2) printf(" j=%d newx=%g ty=%g tyi=%g tyii=%g\n", j, newx[j], ty, tyi, tyii);
233 if(newy!=NULL) newy[j]=ty;
234 if(newyi!=NULL) newyi[j]=tyi;
235 if(newyii!=NULL) newyii[j]=tyii;
236 j++;
237 }
238
239 /* Set interpolated data between ox1 and ox2 */
240 if(verbose>2) printf("before input start #2\n");
241// dt=ox2-ox1; if(dt>0.0) while(j<newnr && newx[j]<=ox2) {
242 dt=ox2-ox1; if(dt>0.0) while(j<newnr && newx[j]<ox2) {
243 ndt=newx[j]-ox1; if(verbose>2) printf(" ndt=%g\n", ndt);
244 ty=((oy2-oy1)/dt)*ndt + oy1; if(newy!=NULL) newy[j]=ty;
245 tyi=oi1 + 0.5*(ty+oy1)*ndt; if(newyi!=NULL) newyi[j]=tyi;
246 if(newyii!=NULL) newyii[j]=tyii= oii1 + 0.5*(tyi+oi1)*ndt;
247 if(verbose>2) printf(" j=%d newx=%g ty=%g tyi=%g tyii=%g\n", j, newx[j], ty, tyi, tyii);
248 j++;
249 }
250
251 /* Go through input data, sample-by-sample */
252 if(verbose>2) printf("inside input range\n");
253 for(i=0; i<nr && j<newnr; i++) {
254
255 ox1=ox2; oy1=oy2; oi1=oi2; oii1=oii2;
256 ox2=x[i]; oy2=y[i];
257 oi2=oi1 + (ox2-ox1)*(oy1+oy2)/2.0;
258 oii2=oii1 + (ox2-ox1)*(oi1+oi2)/2.0;
259 if(verbose>2) {
260 printf("ox1=%g oy1=%g oi1=%g oii1=%g\n", ox1, oy1, oi1, oii1);
261 printf("ox2=%g oy2=%g oi2=%g oii2=%g\n", ox2, oy2, oi2, oii2);
262 }
263
264 /* Calculate input sample distance */
265 dt=ox2-ox1; if(dt<0.0) return 3; else if(dt==0.0) continue;
266
267 /* Any need for interpolation between ox1 and ox2? */
268 while(j<newnr && newx[j]<=ox2) {
269 ndt=newx[j]-ox1;
270 ty=((oy2-oy1)/dt)*ndt + oy1; if(newy!=NULL) newy[j]=ty;
271 tyi=oi1 + 0.5*(ty+oy1)*ndt; if(newyi!=NULL) newyi[j]=tyi;
272 if(newyii!=NULL) newyii[j]=tyii= oii1 + 0.5*(tyi+oi1)*ndt;
273 if(verbose>4)
274 printf(" j=%d newx=%g ndt=%g ty=%g tyi=%g tyii=%g\n", j, newx[j], ndt, ty, tyi, tyii);
275 j++;
276 }
277
278 } // next input sample
279
280 /* Set interpolated data after input data, assuming zero or steady input */
281 if(verbose>2) printf("after input range\n");
282 while(j<newnr) {
283 ndt=newx[j]-ox2;
284 if(ee==0) ty=0.0; else ty=oy2;
285 if(ee==0) tyi=oi2; else tyi=oi2 + oy2*ndt;
286 tyii=oii2 + 0.5*(tyi+oi2)*ndt;
287 if(newy!=NULL) newy[j]=ty;
288 if(newyi!=NULL) newyi[j]=tyi;
289 if(newyii!=NULL) newyii[j]=tyii;
290 if(verbose>4) printf(" j=%d newx=%g ty=%g tyi=%g tyii=%g\n", j, newx[j], ty, tyi, tyii);
291 j++;
292 }
293
294 if(verbose>3) printf("%s() ready\n", __func__);
295 return 0;
296}
double liFirstStepSize(double *x, const int nr)
Find the initial x step size.
Definition interpolate.c:25

Referenced by bfm1TCM(), liInterpolateForPET(), tacAUC(), tacDelay(), tacDelayCMFit(), tacInput2sim(), tacInterpolate(), and tacInterpolateInto().

◆ liInterpolateForPET()

int liInterpolateForPET ( double * x,
double * y,
const int nr,
double * newx1,
double * newx2,
double * newy,
double * newyi,
double * newyii,
const int newnr,
const int se,
const int ee,
const int verbose )
extern

Linear TAC interpolation and/or integration to PET frames.

PET data must be frequently sampled to get accurate results. AUC calculation is started from time 0 or first input sample time, whichever is smaller. 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. PET frames can overlap, but interpolation may then be slower. Negative x (time) values can be processed. Results will be wrong if data contains NaNs. Very simple data extrapolation can be optionally enabled. To get the same result as with interpolate4pet() in the libtpcmodel, set se=3 and ee=1.

Author
Vesa Oikonen
See also
liInterpolate(), liIntegratePET(), tacInterpolateInto, tacInterpolate, tacAUC
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.
newx1Array of PET frame start times for output data; obligatory. Must be in ascending order. Negative times are accepted.
newx2Array of PET frame end times for output data; obligatory. Must be in ascending order. Negative times are accepted, but frame duration (x2-x1) must be >=0.
newyArray for mean concentration values for each PET frame; NULL can be given if not needed.
newyiArray for integrals (AUCs) at frame middle times; NULL can be given if not needed.
newyiiArrays for 2nd integrals at frame middle times; NULL can be given if not needed.
newnrNr of samples in output data; obligatory.
seExtrapolation setting for the start of data:
  • 0= assuming y=0 when newx<x[0]
  • 1= assuming y=y[0] when 0<=newx<x[0] and y=0 when newx<x[0]<0
  • 2= assuming y=0 when newx<=0 and x[0]>0, and y=newx*y[0]/x[0] when 0<newx<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 newx<=2*x[0]-x[1], and y=(newx-(2*x[0]-x[1]))*y[0]/x[0] when (2*x[0]-x[1])<newx<x[0] and y[0]>0.
eeExtrapolation setting for the end of data:
  • 0= assuming y=0 when newx>x[nr-1]
  • 1= assuming y=y[nr-1] when newx>x[nr-1]
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 317 of file interpolate.c.

361 {
362 if(verbose>0)
363 printf("%s(x, y, %d, nx1, nx2, ny, ni, ni2, %d, %d, %d)\n", __func__, nr, newnr, se, ee);
364
365 /* Check for data */
366 if(nr<1 || newnr<1) return 1;
367 if(x==NULL || y==NULL || newx1==NULL || newx2==NULL) return 1;
368 /* Check that input data is not totally outside the input data */
369 if(newx2[newnr-1]<=x[0] || newx1[0]>=x[nr-1]) return 3;
370
371 /* Nothing to do if output arrays were not given */
372 if(newy==NULL && newyi==NULL && newyii==NULL) return 0;
373
374 int ret, fi, zeroframe=0, overlap=0;
375 double fdur;
376
377 /* Check frame lengths, also for overlap and zero length frames */
378 for(fi=0; fi<newnr; fi++) {
379 /* Calculate frame length */
380 fdur=newx2[fi]-newx1[fi];
381 /* If frame length is <0, that is an error */
382 if(fdur<0.0) return 4;
383 if(fdur==0.0) zeroframe++;
384 /* Overlap? */
385 if(fi>0 && newx2[fi-1]>newx1[fi]) overlap++;
386 }
387 if(verbose>2) {
388 printf("overlap := %d\n", overlap);
389 printf("zeroframe := %d\n", zeroframe);
390 }
391
392 /* Interpolate and integrate one frame at a time, if:
393 -there are overlapping frames
394 -there are frames of zero length
395 -only few interpolated frames
396 -if frame mean values are not needed
397 */
398
399 if(overlap>0 || zeroframe>0 || newnr<=3 || newy==NULL )
400 {
401 double petx[3], pety[3], petyi[3], petyii[3];
402
403 if(verbose>1) printf("frame-by-frame interpolation/integration\n");
404 for(fi=0; fi<newnr; fi++) {
405 /* Set frame start, middle and end times */
406 petx[0]=newx1[fi]; petx[2]=newx2[fi]; petx[1]=0.5*(petx[0]+petx[2]);
407 /* Calculate frame length */
408 fdur=petx[2]-petx[0];
409 /* If frame length is <0, that is an error */
410 if(fdur<0.0) return 4;
411 /* If frame length is 0, then use direct interpolation */
412 if(fdur==0.0) {
413 ret=liInterpolate(x, y, nr, petx, pety, petyi, petyii, 1, se, ee, verbose-1);
414 if(ret) return 10+ret;
415 if(newy!=NULL) newy[fi]=petyi[0];
416 if(newyi!=NULL) newyi[fi]=petyi[0];
417 if(newyii!=NULL) newyii[fi]=petyii[0];
418 continue;
419 }
420 /* Calculate integrals at frame start, middle, and end */
421 ret=liInterpolate(x, y, nr, petx, NULL, petyi, petyii, 3, se, ee, verbose-1);
422 if(ret) return 20+ret;
423 /* Set output integrals, if required */
424 if(newyi!=NULL) newyi[fi]=petyi[1];
425 if(newyii!=NULL) newyii[fi]=petyii[1];
426 /* Calculate frame mean, if required */
427 if(newy!=NULL) newy[fi]=(petyi[2]-petyi[0])/fdur;
428 } // next frame
429
430 } else {
431
432 if(verbose>1) printf("all-frames-at-once interpolation/integration\n");
433 /* Set temp array */
434 double *tp=NULL; tp=malloc(newnr*sizeof(double)); if(tp==NULL) return 7;
435 /* Integrate at frame start times */
436 ret=liInterpolate(x, y, nr, newx1, NULL, tp, NULL, newnr, se, ee, verbose-1);
437 if(ret) {free(tp); return 10+ret;}
438 /* Integrate at frame end times */
439 ret=liInterpolate(x, y, nr, newx2, NULL, newy, NULL, newnr, se, ee, verbose-1);
440 if(ret) {free(tp); return 10+ret;}
441 /* Calculate average frame value */
442 for(fi=0; fi<newnr; fi++)
443 newy[fi]=(newy[fi]-tp[fi])/(newx2[fi]-newx1[fi]);
444 /* Calculate integrals */
445 if(newyi!=NULL || newyii!=NULL) {
446 for(fi=0; fi<newnr; fi++) tp[fi]=0.5*(newx2[fi]+newx1[fi]);
447 ret=liInterpolate(x, y, nr, tp, NULL, newyi, newyii, newnr, se, ee, verbose-1);
448 if(ret) {free(tp); return 10+ret;}
449 }
450 free(tp);
451 }
452
453 if(verbose>1) printf("%s() ready\n", __func__);
454
455
456 return 0;
457}
int liInterpolate(double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear interpolation and/or integration with trapezoidal method.

Referenced by bfm1TCM(), tacDelay(), tacDelayCMFit(), tacInterpolate(), tacInterpolateInto(), and tacInterpolateToEqualLengthFrames().

◆ simSamples()

unsigned int simSamples ( double initStep,
double maxStep,
double endTime,
int mode,
double * x )
extern

Create sample times with more frequent sampling in the beginning.

Returns
Returns the number of samples.
See also
liInterpolate, liInterpolateForPET, simC1, simBTAC
Parameters
initStepInitial sampling frequency.
maxStepMaximal sampling frequency which is never exceeded; enter 0 to set it automatically.
endTimeEnd time; last sample will usually be later.
modeSampling scheme:
  • Mode 0: 1s, 2s, 3s, 4s, ...
  • Mode 1: 10 x s, 5 x 2s, 2 x 5s, s*=10, ...
  • Mode 2: 20 x s, 10 x 2s, 5 x 5s, s*=10, ...
xAllocated array for the samples; NULL if only computing the number of samples.

Definition at line 50 of file interpolate.c.

65 {
66 unsigned int n=0;
67 if(initStep<=0.0 || endTime<=0.0 || endTime<initStep) return(n);
68 if(maxStep<initStep) maxStep=endTime;
69
70 double x1=0.0, s=initStep;
71 if(mode==0) {
72 while(x1<endTime) {
73 if(x!=NULL) x[n]=x1;
74 x1+=s; n++;
75 }
76 if(x!=NULL) x[n]=x1;
77 n++;
78 } else if(mode==1) {
79 while(x1<endTime) {
80 for(int i=0; i<10 && x1<endTime; i++, n++) {
81 if(x!=NULL) x[n]=x1;
82 x1+=s;
83 }
84 s*=2.0; if(s>maxStep) s=maxStep;
85 for(int i=0; i<5 && x1<endTime; i++, n++) {
86 if(x!=NULL) x[n]=x1;
87 x1+=s;
88 }
89 s*=2.5; if(s>maxStep) s=maxStep;
90 for(int i=0; i<2 && x1<endTime; i++, n++) {
91 if(x!=NULL) x[n]=x1;
92 x1+=s;
93 }
94 s*=2.0; if(s>maxStep) s=maxStep;
95 }
96 if(x!=NULL) x[n]=x1;
97 n++;
98 } else if(mode==2) {
99 while(x1<endTime) {
100 for(int i=0; i<20 && x1<endTime; i++, n++) {
101 if(x!=NULL) x[n]=x1;
102 x1+=s;
103 }
104 s*=2.0; if(s>maxStep) s=maxStep;
105 for(int i=0; i<10 && x1<endTime; i++, n++) {
106 if(x!=NULL) x[n]=x1;
107 x1+=s;
108 }
109 s*=2.5; if(s>maxStep) s=maxStep;
110 for(int i=0; i<5 && x1<endTime; i++, n++) {
111 if(x!=NULL) x[n]=x1;
112 x1+=s;
113 }
114 s*=2.0; if(s>maxStep) s=maxStep;
115 }
116 if(x!=NULL) x[n]=x1;
117 n++;
118 }
119 return(n);
120}