8#include "tpcclibConfig.h"
24static char *info[] = {
25 "Convolution of PET time-activity curve (TAC) with response function h(t)",
26 "based on one-parameter n-compartmental transit-time (time-delay) model",
27 " h(t) = b^(n-1) / (b+t)^n",
28 "Function integral from 0 to infinity is 1/(n-1), when n>1 and b>0.",
40 "Output TAC, Co(t), is calculated from input TAC, Ci(t), as",
41 "Co(T) = Ci(T) (x) h(T)",
42 ", where (x) denotes the operation of convolution.",
44 "Usage: @P [Options] tacfile n b outputfile ",
48 " Sample time interval in convolution; by default the shortest interval",
49 " in the plasma data; too long interval as compared to b's leads to bias.",
51 " Output is written with sample intervals used in convolution; by default",
52 " data is interpolated back to the sample times of the TAC data.",
54 " Scale response function to have integral from 0 to infinity to unity;",
55 " that will lead to similar AUC for the input and output TACs.",
56 " In practise, then h(t) = (n-1) * b^(n-1) / (b+t)^n",
58 " Scale response function to h(0)=1, i.e. use h(t) = b^n / (b+t)^n",
65 "The units of b and the optional sample interval must be the same as",
66 "the time units of the TAC.",
67 "For accurate results, input TAC should have very short sample intervals.",
68 "Frame durations are not used, even if available in the TAC file.",
71 " @P plasma.tac 2 2.17 simulated.tac",
73 "See also: convexpf, simdisp, fit2dat, simframe, sim_av, tacunit",
75 "Keywords: TAC, simulation, modelling, convolution, transit-time",
120 if(nr<2 || n<1)
return(1);
121 if(t==NULL || c0i==NULL || cout==NULL)
return(2);
123 if(!(k>=0.0))
return(3);
125 double c[n+1], ci[n+1];
126 double c_last[n+1], ci_last[n+1];
127 for(
int j=0; j<=n; j++) c[j]=c_last[j]=ci[j]=ci_last[j]=0.0;
130 double t_last=0.0;
if(t[0]<t_last) t_last=t[0];
131 for(
int i=0; i<nr; i++) {
133 double dt2=0.5*(t[i]-t_last);
if(!(dt2>=0.0))
return(5);
135 double kdt=k/(1.0+dt2*k);
139 for(
int j=1; j<=n; j++) {
140 c[j] = kdt * (ci[j-1] - ci_last[j] - dt2*c_last[j]);
141 ci[j] = ci_last[j] + dt2*(c_last[j]+c[j]);
144 for(
int j=0; j<=n; j++) {
152 for(
int j=0; j<=n; j++) {
167int main(
int argc,
char **argv)
169 int ai, help=0, version=0, verbose=1;
170 char tacfile[FILENAME_MAX], simfile[FILENAME_MAX];
171 double interval=nan(
""), h0=nan(
""), auc=nan(
"");
174 int output_sampling=0;
181 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
182 tacfile[0]=simfile[0]=(char)0;
184 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
186 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
187 if(strncasecmp(cptr,
"I=", 2)==0) {
188 interval=
atofVerified(cptr+2);
if(interval>0.0)
continue;
189 }
else if(strcasecmp(cptr,
"SI")==0) {
190 output_sampling=1;
continue;
191 }
else if(strcasecmp(cptr,
"AUC=1")==0) {
193 }
else if(strncasecmp(cptr,
"AUC=", 4)==0) {
195 }
else if(strcasecmp(cptr,
"h0=1")==0) {
197 }
else if(strncasecmp(cptr,
"h0=", 3)==0) {
199 }
else if(strncasecmp(cptr,
"EULER", 3)==0) {
202 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
211 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
216 if(ai<argc) {
strlcpy(tacfile, argv[ai++], FILENAME_MAX);}
220 fprintf(stderr,
"Error: invalid a1 '%s'.\n", argv[ai]);
return(1);}
225 if(!(beta>0.0)) {fprintf(stderr,
"Error: invalid beta '%s'.\n", argv[ai]);
return(1);}
228 if(ai<argc) {
strlcpy(simfile, argv[ai++], FILENAME_MAX);}
230 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
236 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
243 printf(
"tacfile := %s\n", tacfile);
244 printf(
"simfile := %s\n", simfile);
245 printf(
"n := %u\n", n);
246 printf(
"beta := %g\n", beta);
247 if(!isnan(auc)) printf(
"auc := %g\n", auc);
248 if(!isnan(h0)) printf(
"h0 := %g\n", h0);
249 if(!isnan(interval)) printf(
"interval := %g\n", interval);
250 printf(
"output_sampling := %d\n", output_sampling);
251 if(sol>0) printf(
"solution := %d\n", sol);
259 if(verbose>1) fprintf(stdout,
"reading %s\n", tacfile);
262 fprintf(stderr,
"Error: %s (%s)\n",
errorMsg(status.
error), tacfile);
267 printf(
"tacNr := %d\n", tac.
tacNr);
268 printf(
"sampleNr := %d\n", tac.
sampleNr);
275 fprintf(stderr,
"Error: missing frame times.\n");
280 fprintf(stderr,
"Error: missing concentrations.\n");
284 fprintf(stderr,
"Error: too few samples in plasma data.\n");
288 fprintf(stderr,
"Warning: only first TAC in %s is used.\n", tacfile);
292 fprintf(stderr,
"Error: invalid sample times.\n");
295 if(tac.
isframe!=0 && verbose>0) {
297 fprintf(stderr,
"Error: invalid sample times.\n");
300 fprintf(stderr,
"Warning: frame durations are ignored.\n");
314 fprintf(stderr,
"Error: cannot integrate input data.\n");
320 fprintf(stderr,
"Error: invalid data for simulation.\n");
324 for(
int i=0; i<tac.
sampleNr; i++) tac.
c[0].
y[i]=cout[i];
325 if(verbose>1) printf(
"writing simulated data in %s\n", simfile);
326 FILE *fp; fp=fopen(simfile,
"w");
328 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", simfile);
337 if(verbose>=0) printf(
"Simulated TAC saved in %s\n", simfile);
348 if(!isnan(interval) && interval>0.0) {
349 if(interval>0.01*tac.
x[tac.
sampleNr-1] || interval>0.2*beta) {
350 fprintf(stderr,
"Error: too long interval time.\n");
351 printf(
"time_range: %g - %g\n", tac.
x[0], tac.
x[tac.
sampleNr-1]);
352 printf(
"beta := %g\n", beta);
353 printf(
"interval := %g\n", interval);
354 fflush(stderr); fflush(stdout);
357 if(interval>0.001*tac.
x[tac.
sampleNr-1] || interval>0.05*beta) {
359 fprintf(stderr,
"Warning: interval time may be too long.\n");
360 printf(
"time_range: %g - %g\n", tac.
x[0], tac.
x[tac.
sampleNr-1]);
361 printf(
"beta := %g\n", beta);
362 printf(
"interval := %g\n", interval);
363 fflush(stderr); fflush(stdout);
371 if(!isnan(interval)) {
380 fprintf(stderr,
"Error: cannot interpolate data to even sample times.\n");
385 double freq=itac.
x2[0]-itac.
x1[0];
387 printf(
"sample_intervals_in_convolution := %g\n", freq);
388 printf(
"interpolated data range: %g - %g\n", itac.
x1[0], itac.
x2[itac.
sampleNr-1]);
392 if(verbose>0) {fprintf(stdout,
"allocate memory for kernel...\n"); fflush(stdout);}
393 double *kernel=(
double*)malloc(2*itac.
sampleNr*
sizeof(
double));
395 fprintf(stderr,
"Error: out of memory.\n");
404 if(verbose>0) {fprintf(stdout,
"computing the kernel...\n"); fflush(stdout);}
406 if(verbose>6) printf(
"\nData\tKernel:\n");
408 for(
int i=0; i<itac.
sampleNr; i++) {
409 kernel[i] = log(beta+itac.
x2[i]) - log(beta+itac.
x1[i]);
413 for(
int i=0; i<itac.
sampleNr; i++) {
414 kernel[i]=beta*freq/((beta+itac.
x1[i])*(beta+itac.
x2[i]));
418 for(
int i=0; i<itac.
sampleNr; i++) {
419 double x1, x2; x1=beta+itac.
x1[i]; x2=beta+itac.
x2[i];
420 double y=-(double)(n-1);
421 kernel[i] = pow(beta, (
double)(n-1)) * (pow(x1, y) - pow(x2, y)) / (
double)(n-1);
424 if(!isfinite(kernel[i])) {
425 printf(
"kernel[%d]=%g\n", i, kernel[i]);
426 printf(
"pow(%g, %d)=%g\n", beta, n-1, pow(beta, n-1));
427 printf(
"pow(10.0, -2.0)=%e\n", pow(10.0, -2.0));
429 x=beta+itac.
x1[i]; y=-(double)(n-1);
430 printf(
"pow(%g, %g)=%g\n", x, y, pow(x, y));
431 x=beta+itac.
x2[i]; y=-(double)(n-1);
432 printf(
"pow(%g, %g)=%g\n", x, y, pow(x, y));
438 if(verbose>2) {printf(
"Sum of unscaled response function := %g\n", ksum); fflush(stdout);}
439 if(!isnormal(ksum)) {
440 fprintf(stderr,
"Error: invalid kernel contents.\n");
444 for(
int i=0; i<itac.
sampleNr; i++) printf(
"%g\t%g\n", itac.
c[0].
y[i], kernel[i]);
450 double hauc=1.0/(double)(n-1);
457 if(sc>0.0 && sc!=1.0) {
459 if(verbose>7) printf(
"\nData\tKernel:\n");
460 for(
int i=0; i<itac.
sampleNr; i++) {
463 if(verbose>7) printf(
"%g\t%g\n", itac.
c[0].
y[i], kernel[i]);
465 if(verbose>2) printf(
"Sum of scaled response function := %g\n", ksum);
472 if(verbose>1) fprintf(stdout,
"convolution...\n");
474 fprintf(stderr,
"Error: cannot convolve the data.\n");
478 printf(
"\nData x\ty\tKernel\tConvolved\n");
480 printf(
"%g\t%g\t%g\t%g\n", itac.
x[i], itac.
c[0].
y[i], kernel[i], cy[i]);
484 for(
int i=0; i<itac.
sampleNr; i++) itac.
c[0].
y[i]=cy[i];
492 if(output_sampling==1) {
498 strcpy(itac.
c[0].
name,
"MMT");
503 if(verbose>1) printf(
"writing convolved data in %s\n", simfile);
504 FILE *fp; fp=fopen(simfile,
"w");
506 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", simfile);
515 if(verbose>=0) printf(
"Convolved TAC saved in %s\n", simfile);
527 if(verbose>1) fprintf(stdout,
"interpolating to original sample times...\n");
534 NULL, NULL, tac.
sampleNr, 4, 1, verbose-10);
537 fprintf(stderr,
"Error: cannot interpolate back.\n");
544 ret=
liInterpolate(dtac.x, dtac.c[0].y, dtac.sampleNr, atac.x, atac.c[0].y, NULL, NULL,
545 atac.sampleNr, 0, 0, verbose-10);
548 NULL, NULL, atac.sampleNr, 0, 1, verbose-10);
555 if(verbose>1) printf(
"writing convolved data in %s\n", simfile);
556 FILE *fp; fp=fopen(simfile,
"w");
558 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", simfile);
567 if(verbose>=0) printf(
"Convolved TAC saved in %s\n", simfile);
int convolve1D(double *data, const int n, double *kernel, const int m, double *out)
Calculates the convolution sum of a discrete real data set data[0..n-1] and a discretized response fu...
double atofVerified(const char *s)
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 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.
int atoiCheck(const char *s, int *v)
int tacInterpolateToEqualLengthFrames(TAC *inp, double minfdur, double maxfdur, TAC *tac, TPCSTATUS *status)
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
void tpcPrintBuild(const char *program, FILE *fp)
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
int simTTM_i(double *t, double *c0i, const int n, const double k, const int cn, double *cout)
void statusInit(TPCSTATUS *s)
char * errorMsg(tpcerror e)
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
char name[MAX_TACNAME_LEN+1]
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
char * tacFormattxt(tacformat c)
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
int tacYNaNs(TAC *tac, const int i)
int tacSortByTime(TAC *d, TPCSTATUS *status)
int tacIsWeighted(TAC *tac)
int tacSetX(TAC *d, TPCSTATUS *status)
Set TAC x values based on x1 and x2 values, or guess x1 and x2 values based on x values.
Header file for libtpccm.
Header file for library libtpcextensions.
char * unitName(int unit_code)
Header file for library libtpcift.
Header file for libtpcli.
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Header file for libtpctacmod.