TPCCLIB
Loading...
Searching...
No Matches
disp4dft.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "tpcclibConfig.h"
10/*****************************************************************************/
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <string.h>
15#include <math.h>
16/*****************************************************************************/
17#include "libtpcmisc.h"
18#include "libtpccurveio.h"
19/*****************************************************************************/
20
21/*****************************************************************************/
22static char *info[] = {
23 "Add dispersion effect to ideal TAC data (ON), or correct a measured data set",
24 "for dispersion (OFF) (1, 2).",
25 "The time constant of the dispersion must be given in the same time units as",
26 "those that are used in the data file.",
27 "Program output is written in file in the same format as the input datafile.",
28 " ",
29 "Usage: @P [Options] ON|OFF tacfile dispersion outputfile",
30 " ",
31 "Options:",
32 " -Log",
33 " Dispersion time and other log information is written as comments in",
34 " the corrected TAC file.",
35 " -stdoptions", // List standard options like --help, -v, etc
36 " ",
37 "Example 1: check that specified data files are suitable as input TACs",
38 " @P off us488.bld 2.5 us488blood_disp.bld",
39 " ",
40 "References:",
41 " 1. Iida H, Kanno I, Miura S, Murakami M, Takahashi K, Uemura K. Error",
42 " analysis of a quantitative cerebral blood flow measurement using H215O",
43 " autoradiography and positron emission tomography, with respect to the",
44 " dispersion of the input function.",
45 " J Cereb Blood Flow Metab. 1986;6:536-545.",
46 " 2. Oikonen V. Model equations for the dispersion of the input function in",
47 " bolus infusion PET studies. TPCMOD0003 2002-09-03;",
48 " https://www.turkupetcentre.net/reports/tpcmod0003.pdf",
49 " ",
50 "See also: tacunit, fit_sinf, fitdelay, tactime, convexpf, simdisp",
51 " ",
52 "Keywords: TAC, dispersion, input, blood, simulation",
53 0};
54/*****************************************************************************/
55
56/*****************************************************************************/
57/* Turn on the globbing of the command line, since it is disabled by default in
58 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
59 In Unix&Linux wildcard command line processing is enabled by default. */
60/*
61#undef _CRT_glob
62#define _CRT_glob -1
63*/
64int _dowildcard = -1;
65/*****************************************************************************/
66
67/*****************************************************************************/
71int main(int argc, char **argv)
72{
73 int ai, help=0, version=0, verbose=1;
74 int makeLog=0; // 0=no log; 1=write log
75 int dispersion=-1; // 0=correct for dispersion; 1=simulate dispersion
76 char *cptr, tmp[FILENAME_MAX];
77 char ifile[FILENAME_MAX], ofile[FILENAME_MAX];
78 double tau=-1.0, k;
79 DFT tac;
80
81
82 /*
83 * Get arguments
84 */
85 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
86 ifile[0]=ofile[0]=(char)0;
87 dftInit(&tac);
88 /* Options */
89 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
90 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
91 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
92 if(strncasecmp(cptr, "LOG", 1)==0) {
93 makeLog=1; continue;
94 }
95 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
96 return(1);
97 } else break;
98
99 /* Print help or version? */
100 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
101 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
102 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
103
104 /* Next argument must be the dispersion on/off code */
105 if(ai<argc) {
106 if(strcasecmp(argv[ai], "OFF")==0) dispersion=0;
107 else if(strcasecmp(argv[ai], "ON")==0) dispersion=1;
108 else if(strcasecmp(argv[ai], "NO")==0) dispersion=0;
109 else if(strcasecmp(argv[ai], "YES")==0) dispersion=1;
110 else {
111 fprintf(stderr, "Error: dispersion must be set ON or OFF.\n");
112 return(1);
113 }
114 ai++;
115 }
116
117 /* Next argument must be the input TAC file */
118 if(ai<argc) {strcpy(ifile, argv[ai]); ai++;}
119
120 /* Next argument must be the dispersion time constant */
121 if(ai<argc) {
122 tau=atof_dpi(argv[ai]);
123 if(tau<0.0) {
124 fprintf(stderr, "Error: invalid dispersion time constant.\n");
125 return(1);
126 }
127 ai++;
128 }
129
130 /* Next argument must be the output file */
131 if(ai<argc) {strcpy(ofile, argv[ai]); ai++;}
132
133 /* Is something extra? */
134 if(ai<argc) {
135 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
136 return(1);
137 }
138
139 /* Is something missing? */
140 if(!ofile[0]) {
141 fprintf(stderr, "Error: missing command-line argument; try %s --help\n",
142 argv[0]);
143 return(1);
144 }
145 if(tau>1.0E-08) k=1.0/tau; else k=1.0E+08;
146
147 /* In verbose mode print arguments and options */
148 if(verbose>1) {
149 printf("ifile := %s\n", ifile);
150 printf("ofile := %s\n", ofile);
151 printf("dispersion := %i\n", dispersion);
152 printf("tau := %f\n", tau);
153 printf("1/tau := %g\n", k);
154 printf("makeLog := %d\n", makeLog);
155 }
156
157
158 /*
159 * Read TAC data
160 */
161 if(verbose>1) printf("reading %s\n", ifile);
162 if(dftRead(ifile, &tac)) {
163 fprintf(stderr, "Error in reading '%s': %s\n", ifile, dfterrmsg);
164 return(2);
165 }
166 if(tac.voiNr>1) {
167 fprintf(stderr, "Warning: %s contains %d TACs.\n", ifile, tac.voiNr);
168 }
169 if(verbose>9) dftPrint(&tac);
170 if(tac.frameNr<2) {
171 fprintf(stderr, "Error: data is not suitable for processing dispersion.\n");
172 dftEmpty(&tac); return(2);
173 }
174 /* Sort data by sample times */
175 dftSortByFrame(&tac);
176
177
178 /*
179 * As required, correct for dispersion or add dispersion effect
180 */
181 double *meas, *ideal, *measi, *ideali, *tempData, *t, dt2;
182 int i, j, n;
183 /* Allocate memory for temporary data */
184 tempData=(double*)malloc(tac.frameNr*sizeof(double));
185 if(tempData==NULL) {
186 fprintf(stderr, "Error in allocating memory.\n");
187 dftEmpty(&tac); return(4);
188 }
189 if(dispersion==0 && (fabs(tau)>1.0E-08)) {
190
191 /*
192 * Correct for dispersion
193 */
194 if(verbose>1) printf("correcting for dispersion\n");
195 /* Check that times are ascending and that no duplicate samples exist */
196 for(j=1; j<tac.frameNr; j++) if(tac.x[j]<=tac.x[j-1]) {
197 fprintf(stderr, "Error: invalid sample timing in datafile.\n");
198 dftEmpty(&tac); free((char*)tempData); return(5);
199 }
200 /* one curve at a time */
201 for(i=0; i<tac.voiNr; i++) {
202 /* Set pointers */
203 meas=tac.voi[i].y; ideal=tac.voi[i].y2; measi=tac.voi[i].y3;
204 ideali=tempData; t=tac.x; n=tac.frameNr;
205 /* Integrate measured data */
206 measi[0]=0.5*meas[0]*t[0];
207 for(j=1; j<n; j++)
208 measi[j]=measi[j-1]+0.5*(meas[j]+meas[j-1])*(t[j]-t[j-1]);
209 /* Calculate ideal data integral */
210 for(j=0; j<n; j++) ideali[j]=measi[j]+tau*meas[j];
211 /* Calculate ideal data */
212 j=0; dt2=0.5*t[j];
213 if(dt2>0.0) ideal[j]=ideali[j]/dt2; else ideal[j]=0.0;
214 for(j=1; j<n-1; j++) {
215 ideal[j]=(ideali[j+1]-ideali[j-1])/(t[j+1]-t[j-1]);
216 }
217 ideal[j]=(ideali[j]-ideali[j-1])/(t[j]-t[j-1]);
218 if(verbose>12) {
219 for(j=0; j<n; j++) printf("%9.3f %12.3e %16.7e %12.3e %12.3e\n",
220 t[j], ideal[j], ideali[j], meas[j], measi[j]);
221 }
222 } /* next curve */
223
224 } else if(dispersion!=0 && (fabs(tau)>1.0E-08)) {
225
226 /*
227 * Add dispersion
228 */
229 if(verbose>1) printf("adding dispersion\n");
230 /* one curve at a time */
231 for(i=0; i<tac.voiNr; i++) {
232 /* Set pointers */
233 ideal=tac.voi[i].y; meas=tac.voi[i].y2; ideali=tac.voi[i].y3;
234 measi=tempData; t=tac.x; n=tac.frameNr;
235 /* Integrate ideal data */
236 ideali[0]=0.5*ideal[0]*t[0];
237 for(j=1; j<n; j++)
238 ideali[j]=ideali[j-1]+0.5*(ideal[j]+ideal[j-1])*(t[j]-t[j-1]);
239 /* Calculate measured data */
240 j=0; dt2=0.5*t[j];
241 meas[j]=k*ideali[j]/(1.0+k*dt2);
242 measi[j]=meas[j]*dt2;
243 for(j=1; j<n; j++) {
244 dt2=0.5*(t[j]-t[j-1]);
245 meas[j]=(k*ideali[j] - k*(measi[j-1] + dt2*meas[j-1])) / (1.0+k*dt2);
246 measi[j]=measi[j-1]+dt2*(meas[j]+meas[j-1]);
247 }
248 if(verbose>12) {
249 for(j=0; j<n; j++) printf("%9.3f %12.3e %12.3e %12.3e %12.3e\n",
250 t[j], ideal[j], ideali[j], meas[j], measi[j]);
251 }
252 }
253 /* Remove duplicate data 'frames' */
254 n=1; while(n<tac.frameNr) {
255 if(tac.x[n]>tac.x[n-1]) {n++; continue;}
256 for(j=n; j<tac.frameNr; j++) {
257 tac.x[j-1]=tac.x[j]; tac.x1[j-1]=tac.x1[j]; tac.x2[j-1]=tac.x2[j];
258 for(i=0; i<tac.voiNr; i++) {
259 tac.voi[i].y[j-1]=tac.voi[i].y[j];
260 tac.voi[i].y2[j-1]=tac.voi[i].y2[j];
261 tac.voi[i].y3[j-1]=tac.voi[i].y3[j];
262 }
263 }
264 tac.frameNr--;
265 }
266 } else { /* tau is about zero */
267 if(makeLog==0)
268 fprintf(stderr, "Warning: dispersion time constant is set to 0.\n");
269 for(i=0; i<tac.voiNr; i++) for(j=0; j<tac.frameNr; j++)
270 tac.voi[i].y2[j]=tac.voi[i].y[j];
271 }
272
273 /* Avoid peaks in the beginning */
274 for(i=0; i<tac.voiNr; i++){
275 if(tac.voi[i].y2[0]> 5.0*tac.voi[i].y2[1]) tac.voi[i].y2[0]=0.00;
276 }
277
278 /* free temp memory */
279 free((char*)tempData);
280 if(verbose>10) dftPrint(&tac);
281
282
283 /*
284 * Save new data
285 */
286 if(verbose>3) printf("saving data\n");
287 for(i=0; i<tac.voiNr; i++) for(j=0; j<tac.frameNr; j++)
288 tac.voi[i].y[j]=tac.voi[i].y2[j];
289 /* Add the log information, if required */
290 if(makeLog!=0) {
291 if(verbose>2) printf("saving log information\n");
292 if(strlen(tac.comments)>0) strcat(tac.comments, "\n");
293 sprintf(tmp, "# dispersion_time := %g\n", tau);
294 strcat(tac.comments, tmp);
295 if(dispersion==0) strcat(tac.comments, "# dispersion := off\n");
296 else if(dispersion==1) strcat(tac.comments, "# dispersion := on\n");
297 }
298 /* Write */
299 if(verbose>1) printf("writing %s\n", ofile);
300 if(dftWrite(&tac, ofile)) {
301 fprintf(stderr, "Error in writing '%s': %s\n", ofile, dfterrmsg);
302 dftEmpty(&tac); return(11);
303 }
304 if(verbose>0) printf("TAC written in %s\n", ofile);
305
306 /* free memory */
307 dftEmpty(&tac);
308
309 return(0);
310}
311/*****************************************************************************/
312
313/*****************************************************************************/
315
double atof_dpi(char *str)
Definition decpoint.c:59
void dftInit(DFT *data)
Definition dft.c:38
char dfterrmsg[64]
Definition dft.c:6
int dftSortByFrame(DFT *dft)
Definition dft.c:1169
void dftEmpty(DFT *data)
Definition dft.c:20
int dftRead(char *filename, DFT *data)
Definition dftio.c:22
void dftPrint(DFT *data)
Definition dftio.c:538
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
Header file for libtpccurveio.
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
Voi * voi
double * x1
char comments[_DFT_COMMENT_LEN+1]
int voiNr
double * x2
int frameNr
double * x
double * y2
double * y
double * y3