TPCCLIB
Loading...
Searching...
No Matches
conv1tcm.c
Go to the documentation of this file.
1
9/*****************************************************************************/
10#include "tpcclibConfig.h"
11/*****************************************************************************/
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <math.h>
16/*****************************************************************************/
17#include "tpcextensions.h"
18#include "tpcift.h"
19#include "tpctac.h"
20#include "tpcli.h"
21#include "tpccm.h"
22#include "tpctacmod.h"
23/*****************************************************************************/
24
25/*****************************************************************************/
26static char *info[] = {
27 "Simulation of PET tissue time-radioactivity concentration curve (TAC)",
28 "from arterial plasma (Ca) TAC, based on one-tissue compartment model,",
29 "using linear discrete time convolution:",
30 " ",
31 " ____ K1 ____ ",
32 " | Ca | ----> | Ct | ",
33 " |____| <---- |____| ",
34 " k2 ",
35 " ",
36 "Ct(T) = K1*Ca(T) (x) exp[-k2*T]",
37 ", where (x) denotes the operation of convolution.",
38 " ",
39 "Usage: @P [Options] plasmafile K1 k2 outputfile ",
40 " ",
41 "Options:",
42 " -i=<Interval>",
43 " Sample time interval in convolution; by default the shortest interval",
44 " in the plasma data; too long interval as compared to k2 leads to bias.",
45 " -stdoptions", // List standard options like --help, -v, etc
46 " ",
47 "The units of rate constants must be 1/min or 1/s depending on the time units",
48 "of the plasma file, min or s, respectively.",
49 "For accurate results, plasma TAC should have very short sampling intervals.",
50 "Frame durations are not used, even if available in the TAC file.",
51 " ",
52 "Example:",
53 " @P plasma.tac 0.4 0.5 simulated.tac",
54 " ",
55 "See also: sim_3tcm, fit2dat, tacadd, simdisp, simframe, svar4tac, fitk2",
56 " ",
57 "Keywords: TAC, simulation, modelling, compartmental model, convolution",
58 0};
59/*****************************************************************************/
60
61/*****************************************************************************/
62/* Turn on the globbing of the command line, since it is disabled by default in
63 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
64 In Unix&Linux wildcard command line processing is enabled by default. */
65/*
66#undef _CRT_glob
67#define _CRT_glob -1
68*/
69int _dowildcard = -1;
70/*****************************************************************************/
71
72/*****************************************************************************/
76int main(int argc, char **argv)
77{
78 int ai, help=0, version=0, verbose=1;
79 char tacfile[FILENAME_MAX], simfile[FILENAME_MAX];
80 double k1=nan(""), k2=nan(""), interval=nan("");
81
82
83 /*
84 * Get arguments
85 */
86 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
87 tacfile[0]=simfile[0]=(char)0;
88 /* Options */
89 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
90 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
91 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
92 if(strncasecmp(cptr, "I=", 2)==0) {
93 interval=atofVerified(cptr+2); if(interval>0.0) continue;
94 }
95 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
96 return(1);
97 } else break; // tac name argument may start with '-'
98
99 TPCSTATUS status; statusInit(&status);
100 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
101 status.verbose=verbose-1;
102
103 /* Print help or version? */
104 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
105 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
106 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
107
108 /* Process other arguments, starting from the first non-option */
109 if(ai<argc) {strlcpy(tacfile, argv[ai++], FILENAME_MAX);}
110 if(ai<argc) {
111 k1=atofVerified(argv[ai]);
112 if(isnan(k1) || k1<0.0 || k1>1000.0) {
113 fprintf(stderr, "Error: invalid K1 '%s'.\n", argv[ai]); return(1);}
114 ai++;
115 }
116 if(ai<argc) {
117 k2=atofVerified(argv[ai]);
118 if(isnan(k2) || k1<=0.0 || k2>1000.0) {
119 fprintf(stderr, "Error: invalid k2 '%s'.\n", argv[ai]); return(1);}
120 ai++;
121 }
122 if(ai<argc) {strlcpy(simfile, argv[ai++], FILENAME_MAX);}
123 if(ai<argc) {
124 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
125 return(1);
126 }
127
128 /* Is something missing? */
129 if(!simfile[0]) {
130 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
131 return(1);
132 }
133
134 /* In verbose mode print arguments and options */
135 if(verbose>1) {
136 printf("tacfile := %s\n", tacfile);
137 printf("simfile := %s\n", simfile);
138 printf("K1 := %g\n", k1);
139 printf("k2 := %g\n", k2);
140 if(!isnan(interval)) printf("interval := %g\n", interval);
141 fflush(stdout);
142 }
143
144
145 /*
146 * Read plasma TAC
147 */
148 if(verbose>1) fprintf(stdout, "reading %s\n", tacfile);
149 TAC tac; tacInit(&tac);
150 if(tacRead(&tac, tacfile, &status)!=TPCERROR_OK) {
151 fprintf(stderr, "Error: %s (%s)\n", errorMsg(status.error), tacfile);
152 tacFree(&tac); return(2);
153 }
154 if(verbose>2) {
155 printf("fileformat := %s\n", tacFormattxt(tac.format));
156 printf("tacNr := %d\n", tac.tacNr);
157 printf("sampleNr := %d\n", tac.sampleNr);
158 printf("xunit := %s\n", unitName(tac.tunit));
159 printf("yunit := %s\n", unitName(tac.cunit));
160 if(tacIsWeighted(&tac)) printf("weighting := yes\n");
161 }
162 /* Check for missing sample times */
163 if(tacXNaNs(&tac)>0) {
164 fprintf(stderr, "Error: missing frame times.\n");
165 tacFree(&tac); return(2);
166 }
167 /* Check for missing concentrations */
168 if(tacYNaNs(&tac, -1)>0) {
169 fprintf(stderr, "Error: missing concentrations.\n");
170 tacFree(&tac); return(2);
171 }
172 if(tac.sampleNr<3) {
173 fprintf(stderr, "Error: too few samples in plasma data.\n");
174 tacFree(&tac); return(2);
175 }
176 if(tac.tacNr>1) {
177 fprintf(stderr, "Warning: only first TAC in %s is used.\n", tacfile);
178 tac.tacNr=1;
179 }
180 if(tacSortByTime(&tac, &status)!=TPCERROR_OK) {
181 fprintf(stderr, "Error: invalid sample times.\n");
182 tacFree(&tac); return(2);
183 }
184 if(tac.isframe!=0 && verbose>0) {
185 if(tacSetX(&tac, &status)!=TPCERROR_OK) { // make sure that frame middle times are set
186 fprintf(stderr, "Error: invalid sample times.\n");
187 tacFree(&tac); return(2);
188 }
189 fprintf(stderr, "Warning: frame durations are ignored.\n");
190 }
191 if(interval>0.1*tac.x[tac.sampleNr-1]) {
192 fprintf(stderr, "Error: too long interval time.\n");
193 tacFree(&tac); return(2);
194 }
195 if(interval>0.01*tac.x[tac.sampleNr-1]) {
196 if(verbose>0) fprintf(stderr, "Warning: interval time may be too long.\n");
197 }
198
199
200 /*
201 * Interpolate data with even sample intervals for convolution
202 */
203 TAC itac; tacInit(&itac);
204 if(tacInterpolateToEqualLengthFrames(&tac, interval, interval, &itac, &status)!=TPCERROR_OK) {
205 fprintf(stderr, "Error: cannot interpolate data to even sample times.\n");
206 tacFree(&tac); return(3);
207 }
208 /* Get the sample interval in interpolated data */
209 double freq=itac.x2[0]-itac.x1[0];
210 if(verbose>1) {
211 printf("sample_intervals_in_convolution := %g\n", freq);
212 printf("interpolated data range: %g - %g\n", itac.x1[0], itac.x2[itac.sampleNr-1]);
213 }
214
215
216 if(verbose>0) fprintf(stdout, "allocate memory for kernel...\n");
217 double *kernel=(double*)malloc(2*itac.sampleNr*sizeof(double));
218 if(kernel==NULL) {
219 fprintf(stderr, "Error: out of memory.\n");
220 tacFree(&tac); tacFree(&itac); return(5);
221 }
222 double *cy=kernel+itac.sampleNr;
223
224
225 /*
226 * Calculate the response function for convolution
227 */
228 if(verbose>1) fprintf(stdout, "computing the kernel...\n");
229 double ksum=0.0;
230 if(verbose>6) printf("\nData\tKernel:\n");
231 for(int i=0; i<itac.sampleNr; i++) {
232 kernel[i]=(exp(k2*freq) - 1.0) * exp(-k2*(itac.x[i]+0.5*freq)) / k2;
233 ksum+=kernel[i];
234 if(verbose>4) printf("%g\t%g\n", itac.c[0].y[i], kernel[i]);
235 }
236 if(verbose>2) printf("Sum of response function := %g\n", ksum);
237 if(!isnormal(ksum)) {
238 fprintf(stderr, "Error: invalid kernel contents.\n");
239 tacFree(&tac); tacFree(&itac); free(kernel); return(6);
240 }
241
242
243 /*
244 * Convolution
245 */
246 if(verbose>1) fprintf(stdout, "convolution...\n");
247 if(convolve1D(itac.c[0].y, itac.sampleNr, kernel, itac.sampleNr, cy)!=0) {
248 fprintf(stderr, "Error: cannot convolve the data.\n");
249 tacFree(&tac); tacFree(&itac); free(kernel); return(7);
250 }
251 if(verbose>4) {
252 printf("\nData x\ty\tKernel\tConvolved\n");
253 for(int i=0; i<itac.sampleNr; i++)
254 printf("%g\t%g\t%g\t%g\n", itac.x[i], itac.c[0].y[i], kernel[i], cy[i]);
255 }
256
257 /*
258 * Multiply by K1
259 */
260 for(int i=0; i<itac.sampleNr; i++) cy[i]*=k1;
261
262 /* Copy convoluted curve over interpolated curve */
263 for(int i=0; i<itac.sampleNr; i++) itac.c[0].y[i]=cy[i];
264 /* No need for kernel or working space */
265 free(kernel);
266
267
268 /*
269 * Interpolate convolved data into original sample times
270 */
271 if(verbose>1) fprintf(stdout, "interpolating to original sample times...\n");
272#if(1)
273 int ret=0;
274 if(tac.isframe==0)
275 ret=liInterpolate(itac.x, itac.c[0].y, itac.sampleNr, tac.x, tac.c[0].y, NULL, NULL,
276 tac.sampleNr, 4, 1, verbose-10);
277 else
278 ret=liInterpolateForPET(itac.x, itac.c[0].y, itac.sampleNr, tac.x1, tac.x2, tac.c[0].y,
279 NULL, NULL, tac.sampleNr, 4, 1, verbose-10);
280 tacFree(&itac);
281#else
282 /* Transform sample interval data into dot-to-dot data */
283 TAC dtac; tacInit(&dtac);
284 if(tacFramesToSteps(&itac, &dtac, &status)!=TPCERROR_OK) {
285 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
286 tacFree(&tac); tacFree(&itac); return(8);
287 }
288 tacFree(&itac);
289 /* Interpolate to original times */
290 int ret=0;
291 if(tac.isframe==0)
292 ret=liInterpolate(dtac.x, dtac.c[0].y, dtac.sampleNr, tac.x, tac.c[0].y, NULL, NULL,
293 tac.sampleNr, 0, 0, verbose-10);
294 else
295 ret=liInterpolateForPET(dtac.x, dtac.c[0].y, dtac.sampleNr, tac.x1, tac.x2, tac.c[0].y,
296 NULL, NULL, tac.sampleNr, 0, 1, verbose-10);
297 tacFree(&dtac);
298#endif
299 if(ret!=0) {
300 fprintf(stderr, "Error: cannot interpolate back.\n");
301 tacFree(&tac); return(9);
302 }
303
304
305 /*
306 * Write the file
307 */
308 if(verbose>1) printf("writing simulated data in %s\n", simfile);
309 FILE *fp; fp=fopen(simfile, "w");
310 if(fp==NULL) {
311 fprintf(stderr, "Error: cannot open file for writing (%s)\n", simfile);
312 tacFree(&tac); return(11);
313 }
314 ret=tacWrite(&tac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
315 fclose(fp); tacFree(&tac);
316 if(ret!=TPCERROR_OK) {
317 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
318 return(12);
319 }
320 if(verbose>=0) printf("Simulated TAC saved in %s\n", simfile);
321
322 return(0);
323}
324/*****************************************************************************/
326/*****************************************************************************/
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...
Definition convolut.c:27
double atofVerified(const char *s)
Definition decpoint.c:75
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)
Definition lisim.c:214
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:169
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:339
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:114
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
char * errorMsg(tpcerror e)
Definition statusmsg.c:68
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
double * y
Definition tpctac.h:75
Definition tpctac.h:87
double * x
Definition tpctac.h:97
unit cunit
Definition tpctac.h:105
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
int isframe
Definition tpctac.h:95
TACC * c
Definition tpctac.h:117
double * x2
Definition tpctac.h:101
unit tunit
Definition tpctac.h:109
double * x1
Definition tpctac.h:99
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
void tacFree(TAC *tac)
Definition tac.c:106
void tacInit(TAC *tac)
Definition tac.c:24
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
int tacYNaNs(TAC *tac, const int i)
Definition tacnan.c:47
int tacXNaNs(TAC *tac)
Definition tacnan.c:23
int tacSortByTime(TAC *d, TPCSTATUS *status)
Definition tacorder.c:74
int tacIsWeighted(TAC *tac)
Definition tacw.c:24
int tacFramesToSteps(TAC *inp, TAC *out, TPCSTATUS *status)
Transform TAC with frames into TAC with frames represented with stepwise changing dot-to-dot data.
Definition tacx.c:942
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.
Definition tacx.c:653
Header file for libtpccm.
Header file for library libtpcextensions.
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.
Header file for libtpcli.
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28
Header file for libtpctacmod.