8#include "tpcclibConfig.h"
24static char *info[] = {
25 "Convolution of PET time-activity curve (TAC) with response function h(t)",
26 "consisting of sum of three decaying exponential functions",
27 " h(t) = a1*exp(-b1*t) + a2*exp(-b2*t) + a3*exp(-b3*t)",
28 "Function integral from 0 to infinity is a1/b1 + a2/b2 + a3/b3.",
29 "Output TAC, Co(t), is calculated from input TAC, Ci(t), as",
30 "Co(T) = Ci(T) (x) h(T)",
31 ", where (x) denotes the operation of convolution.",
32 "To use sum of two exponentials as the response function, enter zeroes for",
33 "a3 and b3. To use a mono-exponential, set a2 and b2 to zero, too.",
35 "Usage: @P [Options] tacfile a1 b1 a2 b2 a3 b3 outputfile ",
39 " Sample time interval in convolution; by default the shortest interval",
40 " in the plasma data; too long interval as compared to b's leads to bias.",
42 " Scale response function to have integral from 0 to infinity to unity;",
43 " that will lead to similar AUC for the input and output TACs.",
45 " Scale response function to h(0)=1.",
48 "The units of a's and b's must be compatible with units of the TAC, and",
49 "the optional sample interval.",
50 "For accurate results, input TAC should have very short sampling intervals.",
51 "Frame durations are not used, even if available in the TAC file.",
54 " @P -auc=1 plasma.tac 1 0.05 0 0 0 0 simulated.tac",
56 "See also: sim_3tcm, fit2dat, tacadd, simdisp, simframe, sim_av, convsurg",
58 "Keywords: TAC, simulation, modelling, convolution",
77int main(
int argc,
char **argv)
79 int ai, help=0, version=0, verbose=1;
80 char tacfile[FILENAME_MAX], simfile[FILENAME_MAX];
81 double interval=nan(
""), h0=nan(
""), auc=nan(
"");
82 double a1=nan(
""), b1=nan(
""), a2=nan(
""), b2=nan(
""), a3=nan(
""), b3=nan(
"");
88 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
89 tacfile[0]=simfile[0]=(char)0;
91 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
93 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
94 if(strncasecmp(cptr,
"I=", 2)==0) {
95 interval=
atofVerified(cptr+2);
if(interval>0.0)
continue;
96 }
else if(strcasecmp(cptr,
"AUC=1")==0) {
98 }
else if(strncasecmp(cptr,
"AUC=", 4)==0) {
100 }
else if(strcasecmp(cptr,
"h0=1")==0) {
102 }
else if(strncasecmp(cptr,
"h0=", 3)==0) {
105 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
114 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
119 if(ai<argc) {
strlcpy(tacfile, argv[ai++], FILENAME_MAX);}
122 if(!(a1>0.0)) {fprintf(stderr,
"Error: invalid a1 '%s'.\n", argv[ai]);
return(1);}
127 if(!(b1>0.0)) {fprintf(stderr,
"Error: invalid b1 '%s'.\n", argv[ai]);
return(1);}
132 if(!(a2>=0.0)) {fprintf(stderr,
"Error: invalid a2 '%s'.\n", argv[ai]);
return(1);}
137 if(!(b2>=0.0)) {fprintf(stderr,
"Error: invalid b2 '%s'.\n", argv[ai]);
return(1);}
142 if(!(a3>=0.0)) {fprintf(stderr,
"Error: invalid a3 '%s'.\n", argv[ai]);
return(1);}
147 if(!(b3>=0.0)) {fprintf(stderr,
"Error: invalid b3 '%s'.\n", argv[ai]);
return(1);}
150 if(ai<argc) {
strlcpy(simfile, argv[ai++], FILENAME_MAX);}
152 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
158 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
163 if(a2==0.0 || b2==0.0) {a2=b2=a3=b3=nan(
"");}
164 else if(a3==0.0 || b3==0.0) {a3=b3=nan(
"");}
168 printf(
"tacfile := %s\n", tacfile);
169 printf(
"simfile := %s\n", simfile);
170 printf(
"a1 := %g\n", a1); printf(
"b1 := %g\n", b1);
171 if(a2>0.0) {printf(
"a2 := %g\n", a2); printf(
"b2 := %g\n", b2);}
172 if(a3>0.0) {printf(
"a3 := %g\n", a3); printf(
"b3 := %g\n", b3);}
173 if(!isnan(auc)) printf(
"auc := %g\n", auc);
174 if(!isnan(h0)) printf(
"h0 := %g\n", h0);
175 if(!isnan(interval)) printf(
"interval := %g\n", interval);
183 if(verbose>1) fprintf(stdout,
"reading %s\n", tacfile);
186 fprintf(stderr,
"Error: %s (%s)\n",
errorMsg(status.
error), tacfile);
191 printf(
"tacNr := %d\n", tac.
tacNr);
192 printf(
"sampleNr := %d\n", tac.
sampleNr);
199 fprintf(stderr,
"Error: missing frame times.\n");
204 fprintf(stderr,
"Error: missing concentrations.\n");
208 fprintf(stderr,
"Error: too few samples in plasma data.\n");
212 fprintf(stderr,
"Warning: only first TAC in %s is used.\n", tacfile);
216 fprintf(stderr,
"Error: invalid sample times.\n");
219 if(tac.
isframe!=0 && verbose>0) {
221 fprintf(stderr,
"Error: invalid sample times.\n");
224 fprintf(stderr,
"Warning: frame durations are ignored.\n");
227 fprintf(stderr,
"Error: too long interval time.\n");
230 if(interval>0.01*tac.
x[tac.
sampleNr-1]) {
231 if(verbose>0) fprintf(stderr,
"Warning: interval time may be too long.\n");
240 fprintf(stderr,
"Error: cannot interpolate data to even sample times.\n");
244 double freq=itac.
x2[0]-itac.
x1[0];
246 printf(
"sample_intervals_in_convolution := %g\n", freq);
247 printf(
"interpolated data range: %g - %g\n", itac.
x1[0], itac.
x2[itac.
sampleNr-1]);
251 if(verbose>0) fprintf(stdout,
"allocate memory for kernel...\n");
252 double *kernel=(
double*)malloc(2*itac.
sampleNr*
sizeof(
double));
254 fprintf(stderr,
"Error: out of memory.\n");
263 if(verbose>1) fprintf(stdout,
"computing the kernel...\n");
265 if(verbose>6) printf(
"\nData\tKernel:\n");
266 for(
int i=0; i<itac.
sampleNr; i++) {
267 kernel[i] = (a1/b1) * (exp(b1*freq) - 1.0) * exp(-b1*(itac.
x[i]+0.5*freq));
269 kernel[i] += (a2/b2) * (exp(b2*freq) - 1.0) * exp(-b2*(itac.
x[i]+0.5*freq));
270 if(a3>0.0) kernel[i] += (a3/b3) * (exp(b3*freq) - 1.0) * exp(-b3*(itac.
x[i]+0.5*freq));
273 if(verbose>6) printf(
"%g\t%g\n", itac.
c[0].
y[i], kernel[i]);
275 if(verbose>2) printf(
"Sum of unscaled response function := %g\n", ksum);
276 if(!isnormal(ksum)) {
277 fprintf(stderr,
"Error: invalid kernel contents.\n");
284 if(a2>0.0) hauc+=a2/b2;
285 if(a3>0.0) hauc+=a3/b3;
294 if(sc>0.0 && sc!=1.0) {
296 if(verbose>7) printf(
"\nData\tKernel:\n");
297 for(
int i=0; i<itac.
sampleNr; i++) {
300 if(verbose>7) printf(
"%g\t%g\n", itac.
c[0].
y[i], kernel[i]);
302 if(verbose>2) printf(
"Sum of scaled response function := %g\n", ksum);
309 if(verbose>1) fprintf(stdout,
"convolution...\n");
311 fprintf(stderr,
"Error: cannot convolve the data.\n");
315 printf(
"\nData x\ty\tKernel\tConvolved\n");
317 printf(
"%g\t%g\t%g\t%g\n", itac.
x[i], itac.
c[0].
y[i], kernel[i], cy[i]);
321 for(
int i=0; i<itac.
sampleNr; i++) itac.
c[0].
y[i]=cy[i];
329 if(verbose>1) fprintf(stdout,
"interpolating to original sample times...\n");
336 NULL, NULL, tac.
sampleNr, 4, 1, verbose-10);
339 fprintf(stderr,
"Error: cannot interpolate back.\n");
347 if(verbose>1) printf(
"writing convolved data in %s\n", simfile);
348 FILE *fp; fp=fopen(simfile,
"w");
350 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", simfile);
359 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 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 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)
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)
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.