TPCCLIB
Loading...
Searching...
No Matches
fitdelay.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 "libtpcmodel.h"
19#include "libtpccurveio.h"
20/*****************************************************************************/
21#define MAX_DELAY 60
22/*****************************************************************************/
23
24/*****************************************************************************/
25static char *info[] = {
26 "For estimation and correction of the delay-time (difference in appearance",
27 "times of radioactivity) between PET tissue and input (blood or plasma) TACs.",
28 " ",
29 "Program is based on the previously published methods (1,2,3):",
30 "The plasma/blood curve is shifted -60 - +60 sec, and a two-tissue",
31 "compartment model (with parameters K1, k2, k3, k4 and Vb) in multilinear",
32 "form (3,4) is fitted to the shifted TAC and each regional tissue TAC,",
33 "with the non-negative least squares method (5).",
34 "For each region, the delay leading to the lowest sum-of-squares is selected;",
35 "the over-all delay value is calculated as a median of the regional delays.",
36 "Dispersion is not considered in this application.",
37 " ",
38 "Usage: @P [options] inputfile tissuefile fittime [inputfile2 [inputfile3 [inputfile4]]]",
39 " ",
40 "Options:",
41 " -o=<Filename>",
42 " Filename for the time delay corrected TAC made from inputfile.",
43 " -o2=<Filename>",
44 " Filename for the time delay corrected TAC made from inputfile2.",
45 " -o3=<Filename>",
46 " Filename for the time delay corrected TAC made from inputfile3.",
47 " -o4=<Filename>",
48 " Filename for the time delay corrected TAC made from inputfile4.",
49 " -timeunit=<min|sec>",
50 " If datafile(s) do not contain the unit of sample times, it is",
51 " recommended to specify it with this option. By default, units in data",
52 " files are trusted.",
53 " -format=<none|dft|pmod|if>",
54 " Specify the output data format; none means that no title lines are saved.",
55 " -fit=<Filename>",
56 " Filename for fitted best TACs; by default these are not saved.",
57 " -model=<1|2>",
58 " Select whether 1- or 2-tissue (default) compartment model is applied.",
59 " -L[og]",
60 " Time delay and other log information is written as comments in",
61 " the corrected TAC file, if format supports comments.",
62 " -matrix=<Filename>",
63 " Filename for saving NNLS matrix in CSV format for testing purposes.",
64 " With this option the tissue file must contain one TAC only.",
65 " -stdoptions", // List standard options like --help, -v, etc
66 " ",
67 "As tissue data, the scanner count-rate curve is recommended, unless scanned",
68 "volume contains heart or large artery or vein where tracer was injected;",
69 "It may be possible to use also regional TACs, if datafile contains frame",
70 "start and end times. If tissue data contains background, remove it first",
71 "with dftrmbkg. The units of sample times should be specified in datafiles;",
72 "file format is specified in (5).",
73 " ",
74 "Fit time must be given in seconds.",
75 " ",
76 "Estimated tracer appearance times in blood/plasma and tissue curves, and",
77 "their differences (time delays and median time delay) are written in stdout.",
78 "By default, delay corrected blood/plasma file is written with name *.delay.*",
79 "but this can be changed with option -o=<Filename>.",
80 "The same correction can be applied to 1-3 additional files, for",
81 "example plasma metabolite TACs.",
82 " ",
83 "Example 1.",
84 "Delay correction for C-11 or F-18 labelled tracer data, using",
85 "metabolite corrected plasma curve as input and count-rate data as tissue",
86 "and correcting also plasma metabolites and total blood for the delay-time:",
87 " fitdelay ut345ap_pure.kbq ut345dy1.img.cr 1800 ut345ap_met.kbq ut345ab.kbq",
88 " ",
89 "Example 2.",
90 "Delay correction for [O-15]water data, using regional tissue",
91 "curves as replacement for count-rate data:",
92 " fitdelay ut111ab.kbq ut111dy1.dft 120",
93 " ",
94 "References:",
95 " 1. Iida H et al. Evaluation of regional differences of tracer appearance",
96 " time in cerebral tissues using [15O]water and dynamic positron emission",
97 " tomography. J Cereb Blood Flow Metab. 1988; 8:285-288.",
98 " 2. Meyer. Simultaneous correction for tracer arrival delay and dispersion",
99 " in CBF measurements by the H215O autoradiographic method and dynamic PET.",
100 " J Nucl Med 1989; 30:1069-1078.",
101 " 3. van den Hoff et al. Accurate local blood flow measurements with",
102 " dynamic PET: fast determination of input function delay and dispersion",
103 " by multilinear minimization. J Nucl Med 1993; 34:1770-1777.",
104 " 4. Blomqvist G. On the construction of functional maps in positron",
105 " emission tomography. J Cereb Blood Flow Metab 1984; 4:629-632.",
106 " 5. Lawson CL & Hanson RJ. Solving least squares problems.",
107 " Prentice-Hall, 1974.",
108 " 5. https://www.turkupetcentre.net/petanalysis/format_tpc_dft.html",
109 " ",
110 "See also: tactime, imghead, tacmean, tocr, dftrmbkg, tacunit, fit_h2o, fitdt",
111 " ",
112 "Keywords: TAC, modelling, input, blood, time delay",
113 0};
114/*****************************************************************************/
115
116/*****************************************************************************/
117/* Turn on the globbing of the command line, since it is disabled by default in
118 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
119 In Unix&Linux wildcard command line processing is enabled by default. */
120/*
121#undef _CRT_glob
122#define _CRT_glob -1
123*/
124int _dowildcard = -1;
125/*****************************************************************************/
126
127/*****************************************************************************/
131int main(int argc, char **argv)
132{
133 int ai, help=0, version=0, verbose=1;
134 int ri, fi, fj, di, ret;
135 int min;
136 int make_log=0;
137 int time_unit=TUNIT_UNKNOWN;
138 int orig_tissue_time_unit, orig_input_time_unit;
139 int output_format=DFT_FORMAT_UNKNOWN;
140 int model=2;
141 double v, f, ss, coeff[5], minv, maxv, length=-1.0, onep;
142 double *regional_delay;
143 char *cptr, tmp[FILENAME_MAX];
144 char pfile[FILENAME_MAX], tfile[FILENAME_MAX], rfile[FILENAME_MAX];
145 char p2file[FILENAME_MAX], p3file[FILENAME_MAX], p4file[FILENAME_MAX];
146 char r2file[FILENAME_MAX], r3file[FILENAME_MAX], r4file[FILENAME_MAX];
147 char ffile[FILENAME_MAX];
148 char matfile[FILENAME_MAX];
149 DFT pdata, data, ipdata, fdata;
150 /* nnls */
151 int NNLS_N=5;
152 int n, m, nnls_n, nnls_m, nnls_index[NNLS_N];
153 double *nnls_a[NNLS_N], *nnls_b, *nnls_zz, nnls_x[NNLS_N], *nnls_mat,
154 nnls_wp[NNLS_N], *dptr, nnls_rnorm;
155
156
157 /*
158 * Get arguments
159 */
160 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
161 pfile[0]=rfile[0]=tfile[0]=p2file[0]=p3file[0]=r2file[0]=r3file[0]=(char)0;
162 p4file[0]=r4file[0]=ffile[0]=(char)0;
163 matfile[0]=(char)0;
164 dftInit(&pdata); dftInit(&data); dftInit(&ipdata); dftInit(&fdata);
165 orig_tissue_time_unit=orig_input_time_unit=TUNIT_UNKNOWN;
166
167 /* Options */
168 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
169 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
170 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
171 cptr=argv[ai]+1;
172 if(strcasecmp(cptr, "L")==0 || strcasecmp(cptr, "LOG")==0) {
173 make_log=1; continue;
174 } else if(strncasecmp(cptr, "O=", 2)==0) {
175 cptr+=2; if(strlen(cptr)>0) {strcpy(rfile, cptr); continue;}
176 } else if(strncasecmp(cptr, "O2=", 3)==0) {
177 cptr+=3; if(strlen(cptr)>0) {strcpy(r2file, cptr); continue;}
178 } else if(strncasecmp(cptr, "O3=", 3)==0) {
179 cptr+=3; if(strlen(cptr)>0) {strcpy(r3file, cptr); continue;}
180 } else if(strncasecmp(cptr, "O4=", 3)==0) {
181 cptr+=3; if(strlen(cptr)>0) {strcpy(r4file, cptr); continue;}
182 } else if(strncasecmp(cptr, "MATRIX=", 7)==0) {
183 cptr+=7; if(strlen(cptr)>0) {strcpy(matfile, cptr); continue;}
184 } else if(strncasecmp(cptr, "TIMEUNIT=", 9)==0) {
185 cptr+=9;
186 if(strncasecmp(cptr, "S", 1)==0) {time_unit=TUNIT_SEC; continue;}
187 if(strncasecmp(cptr, "M", 1)==0) {time_unit=TUNIT_MIN; continue;}
188 } else if(strncasecmp(cptr, "FORMAT=", 7)==0) {
189 cptr+=7;
190 if(strncasecmp(cptr, "DFT", 1)==0) {
191 output_format=DFT_FORMAT_STANDARD; continue;}
192 if(strncasecmp(cptr, "NONE", 2)==0) {
193 output_format=DFT_FORMAT_PLAIN; continue;}
194 if(strncasecmp(cptr, "PMOD", 2)==0) {
195 output_format=DFT_FORMAT_PMOD; continue;}
196 if(strcasecmp(cptr, "IF")==0) {
197 output_format=DFT_FORMAT_IF; continue;}
198 } else if(strncasecmp(cptr, "MODEL=", 6)==0) {
199 model=atoi(cptr+6); if(model==1 || model==2) continue;
200 } else if(strncasecmp(cptr, "FIT=", 4)==0) {
201 cptr+=4; strcpy(ffile, cptr); if(strlen(ffile)>0) continue;
202 }
203 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
204 return(1);
205 } else break;
206
207 /* Print help or version? */
208 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
209 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
210 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
211
212 /* Process other arguments, starting from the first non-option */
213 for(; ai<argc; ai++) {
214 if(!pfile[0]) {strcpy(pfile, argv[ai]); continue;}
215 if(!tfile[0]) {strcpy(tfile, argv[ai]); continue;}
216 if(length<=0.9) {
217 length=atof_dpi(argv[ai]); if(length>0.0) continue;
218 fprintf(stderr, "Error: invalid fit time as an argument.\n"); return(1);
219 }
220 if(!p2file[0]) {strcpy(p2file, argv[ai]); continue;}
221 if(!p3file[0]) {strcpy(p3file, argv[ai]); continue;}
222 if(!p4file[0]) {strcpy(p4file, argv[ai]); continue;}
223 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
224 return(1);
225 }
226
227 /* Is something missing? */
228 if(!tfile[0]) {
229 fprintf(stderr, "Error: missing tissue file name.\n");
230 return(1);
231 }
232 if(length<60.0) {
233 fprintf(stderr, "Error: invalid fit time.\n");
234 return(1);
235 }
236
237 /* In verbose mode print arguments and options */
238 if(verbose>1) {
239 printf("pfile := %s\n", pfile);
240 printf("p2file := %s\n", p2file);
241 printf("p3file := %s\n", p3file);
242 printf("p4file := %s\n", p4file);
243 printf("tfile := %s\n", tfile);
244 printf("rfile := %s\n", rfile);
245 printf("r2file := %s\n", r2file);
246 printf("r3file := %s\n", r3file);
247 printf("r4file := %s\n", r4file);
248 printf("ffile := %s\n", ffile);
249 if(matfile[0]) printf("matfile := %s\n", matfile);
250 printf("output_format := %d\n", output_format);
251 printf("make_log := %d\n", make_log);
252 printf("time_unit := %s\n", petTunit(time_unit));
253 printf("length := %g\n", length);
254 printf("model := %d\n", model);
255 }
256
257 /* Check that extra files do exist, if file names were given */
258 if(p2file[0] && access(p2file, 0)==-1) {
259 fprintf(stderr, "Error: %s not found.\n", p2file); return(1);}
260 if(p3file[0] && access(p3file, 0)==-1) {
261 fprintf(stderr, "Error: %s not found.\n", p3file); return(1);}
262 if(p4file[0] && access(p4file, 0)==-1) {
263 fprintf(stderr, "Error: %s not found.\n", p4file); return(1);}
264
265 /* Set NNLS_N */
266 if(model==1) NNLS_N=3; else NNLS_N=5;
267
268
269 /*
270 * Read data
271 */
272
273 /* Input */
274 if(verbose>1) printf("reading %s\n", pfile);
275 if(dftRead(pfile, &pdata)) {
276 fprintf(stderr, "Error in reading '%s': %s\n", pfile, dfterrmsg);
277 dftEmpty(&pdata); return(2);
278 }
279 if(pdata.voiNr>1) {
280 fprintf(stderr, "Warning: %s contains %d TACs; only first is used.\n",
281 pfile, pdata.voiNr);
282 pdata.voiNr=1;
283 }
284 orig_input_time_unit=pdata.timeunit;
285 if(verbose>13) dftPrint(&pdata);
286
287 /* Tissue (or count-rate) data */
288 if(verbose>1) printf("reading %s\n", tfile);
289 if(dftRead(tfile, &data)) {
290 fprintf(stderr, "Error in reading '%s': %s\n", tfile, dfterrmsg);
291 dftEmpty(&pdata); dftEmpty(&data); return(2);
292 }
293 orig_tissue_time_unit=data.timeunit;
294 if(verbose>2) {
295 printf("pdata_time_unit := %s\n", petTunit(pdata.timeunit));
296 if(verbose>2) printf("last_t := %g\n", pdata.x[pdata.frameNr-1]);
297 printf("data_time_unit := %s\n", petTunit(data.timeunit));
298 if(verbose>2) printf("last_t := %g\n", data.x[data.frameNr-1]);
299 }
300
301 /* If more than one tissue TAC then do not allow saving NNLS matrix */
302 if(data.voiNr>1 && matfile[0]) {
303 matfile[0]=(char)0;
304 fprintf(stderr, "Warning: option -matrix disabled because more than one tissue TAC found.\n");
305 }
306
307 /*
308 * Check time units and convert times to sec when necessary
309 */
310 if(verbose>1) printf("checking time units\n");
311 /* Make sure that input time unit is set */
312 if(pdata.timeunit==TUNIT_UNKNOWN) {
313 if(time_unit!=TUNIT_UNKNOWN) {
314 /* If user known what time unit is, then use it */
315 pdata.timeunit=time_unit;
316 } else { /* If not, then we have to start guessing */
317 if(data.timeunit!=TUNIT_UNKNOWN) {
318 /* If tissue time unit is known, then use it */
319 pdata.timeunit=data.timeunit;
320 } else {
321 /* Guess time unit based on last sample time */
322 if(pdata.x[pdata.frameNr-1]>=180) pdata.timeunit=TUNIT_SEC;
323 else pdata.timeunit=TUNIT_MIN;
324 }
325 fprintf(stderr, "Warning: assuming input time_unit := %s\n", petTunit(pdata.timeunit));
326 }
327 }
328 /* Make sure that tissue time unit is set */
329 if(data.timeunit==TUNIT_UNKNOWN) {
330 if(time_unit!=TUNIT_UNKNOWN) {
331 /* If user known what time unit is, then use it */
332 data.timeunit=time_unit;
333 } else { /* If not, then we have to start guessing */
334 if(pdata.timeunit!=TUNIT_UNKNOWN) {
335 /* If input time unit was known, then use it */
336 data.timeunit=pdata.timeunit;
337 } else {
338 /* Guess time unit based on last sample time */
339 if(data.x[data.frameNr-1]>=180) data.timeunit=TUNIT_SEC;
340 else data.timeunit=TUNIT_MIN;
341 }
342 fprintf(stderr, "Warning: assuming tissue time_unit := %s\n", petTunit(data.timeunit));
343 }
344 }
345 /* Save the original unit, so that units can be converted back */
346 orig_input_time_unit=pdata.timeunit;
347 orig_tissue_time_unit=data.timeunit;
348 if(verbose>2) {
349 printf("orig_input_time_unit := %s\n", petTunit(orig_input_time_unit));
350 printf("orig_tissue_time_unit := %s\n", petTunit(orig_tissue_time_unit));
351 }
352 /* Convert data times to sec */
353 if(data.timeunit!=TUNIT_SEC) {
354 if(verbose>0)
355 fprintf(stdout, "Note: tissue sample times are converted to seconds for fitting.\n");
356 dftTimeunitConversion(&data, TUNIT_SEC);
357 }
358 if(pdata.timeunit!=TUNIT_SEC) {
359 if(verbose>0)
360 fprintf(stdout, "Note: input sample times are converted to seconds for fitting.\n");
361 dftTimeunitConversion(&pdata, TUNIT_SEC);
362 }
363 /* Check fit time */
364 if(length<data.x[data.frameNr-1]/60.0 || length<pdata.x[pdata.frameNr-1]/60.0)
365 fprintf(stderr, "Warning: fit time (%g s) is short, compared with data.\n", length);
366
367
368 /* Check if the ascending part of PTAC has been missed */
369 if(verbose>1) printf("checking if the ascending part of plasma TAC has been missed\n");
370 for(fi=1, n=0, maxv=pdata.voi[0].y[0]; fi<pdata.frameNr; fi++) {
371 v=pdata.voi[0].y[fi];
372 if(fi>1 && fi<pdata.frameNr-2) {
373 // mean of samples to avoid noise effects
374 v+=pdata.voi[0].y[fi-1]+pdata.voi[0].y[fi+1];
375 v+=pdata.voi[0].y[fi-2]+pdata.voi[0].y[fi+2];
376 v/=5.0;
377 } else if(fi>0 && fi<pdata.frameNr-1) {
378 // mean of samples to avoid noise effects
379 v+=pdata.voi[0].y[fi-1]+pdata.voi[0].y[fi+1];
380 v/=3.0;
381 }
382 if(v>maxv) {maxv=v; n=fi;}
383 }
384 if(verbose>2) printf("maxv := %g\nmax_index := %d\nmax_time := %g\n", maxv, n, pdata.x[n]);
385 if(n==0) { /* the first or second value is the highest */
386 fprintf(stderr, "Error: missed the ascending phase of plasma/blood data.\n");
387 dftEmpty(&pdata); dftEmpty(&data); return(2);
388 }
389 if(pdata.x[n]>length) { /* peak after fit end time */
390 fprintf(stderr,
391 "Error: missed the plasma/blood peak; check the time unit.\n");
392 dftEmpty(&pdata); dftEmpty(&data); return(2);
393 }
394 /* check tissue data (first TAC) */
395 if(verbose>1) printf("checking if the ascending part of tissue TAC has been missed\n");
396 for(fi=1, n=0, maxv=data.voi[0].y[0]; fi<data.frameNr; fi++)
397 if(data.voi[0].y[fi]>maxv) {maxv=data.voi[0].y[fi]; n=fi;}
398 if(verbose>2) printf("maxv := %g\nmax_index := %d\n", maxv, n);
399 if(n==0) {
400 fprintf(stderr, "Error: missed the ascending phase of tissue data.\n");
401 if(verbose>12) dftPrint(&data);
402 dftEmpty(&pdata); dftEmpty(&data); return(2);
403 }
404 if(n<2) fprintf(stderr, "Warning: check the first samples in %s\n", tfile);
405
406
407 /* "Remove" tissue data after fit length */
408 if(data.timetype==DFT_TIME_STARTEND) {
409 if(length>data.x2[data.frameNr-1]) length=data.x2[data.frameNr-1];
410 } else {
411 if(length>data.x[data.frameNr-1]) length=data.x[data.frameNr-1];
412 }
413 for(fi=0; fi<data.frameNr; fi++) {
414 if(data.timetype==DFT_TIME_STARTEND) {if(data.x1[fi]>=length) break;}
415 else {if(data.x[fi]>=length) break;}
416 } fi--;
417 if(fi<5) {
418 fprintf(stderr, "Error: too few time frames included in fit.\n");
419 dftEmpty(&data); dftEmpty(&pdata); return(2);
420 }
421 if(fi<data.frameNr) {
422 data.frameNr=fi;
423 } else {
424 if(data.timetype==3) length=data.x2[data.frameNr-1];
425 else length=data.x[data.frameNr-1];
426 }
427 if(verbose>3) printf("fit_frameNr := %d\nfit_length := %g\n", data.frameNr, length);
428 if(verbose>2) {
429 if(verbose>10) dftPrint(&data);
430 printf("pdata_time_unit := %s\n", petTunit(pdata.timeunit));
431 if(verbose>2) printf("last_t := %g\n", pdata.x[pdata.frameNr-1]);
432 printf("data_time_unit := %s\n", petTunit(data.timeunit));
433 if(verbose>2) printf("last_t := %g\n", data.x[data.frameNr-1]);
434 }
435
436 /* Check how many plasma/blood samples there are during fit time */
437 for(fi=0; fi<pdata.frameNr; fi++) if(pdata.x[fi]>length) break;
438 if(verbose>1) printf("nr of input samples in fit range := %d\n", fi);
439 if(fi<5 || (fi<10 && fi<data.frameNr)) {
440 fprintf(stderr, "Error: too few plasma/blood samples included in fit.\n");
441 dftEmpty(&pdata); dftEmpty(&data); return(2);
442 }
443
444
445 /* Calculate tissue integrals at frame mid times */
446 if(verbose>1) printf("integrating tissue TACs\n");
447 for(ri=0; ri<data.voiNr; ri++) {
448 if(data.timetype==3)
449 ret=petintegral(data.x1, data.x2, data.voi[ri].y, data.frameNr,
450 data.voi[ri].y2, data.voi[ri].y3);
451 else
452 ret=interpolate(data.x, data.voi[ri].y, data.frameNr, data.x,
453 NULL, data.voi[ri].y2, data.voi[ri].y3, data.frameNr);
454 if(ret) {
455 fprintf(stderr, "Error in integration of tissue data (%d).\n", ret);
456 dftEmpty(&data); dftEmpty(&pdata); return(2);
457 }
458 }
459
460 /* Find the time where plasma curve starts to rise by integrating original plasma data
461 and searching the time where integral is >= 1/1000 of final integral */
462 ret=integrate(pdata.x, pdata.voi[0].y, pdata.frameNr, pdata.voi[0].y2);
463 if(ret) {
464 fprintf(stderr, "Error in integration of plasma data (%d).\n", ret);
465 dftEmpty(&data); dftEmpty(&pdata); return(2);
466 }
467 for(fi=0, onep=0.0; fi<pdata.frameNr-1; fi++)
468 if(pdata.voi[0].y2[fi]>=0.001*pdata.voi[0].y2[pdata.frameNr-1]) {onep=pdata.x[fi]; break;}
469 if(verbose>1) fprintf(stdout, "Plasma curve starts to rise at about %g s.\n", onep);
470
471 /*
472 * Interpolate and integrate plasma TAC at frame mid times
473 * Do this also for plasma TACs moved -MAX_DELAY - +MAX_DELAY sec
474 */
475 if(verbose>1) printf("integrating input TACs\n");
476 dftInit(&ipdata);
477 if(dftSetmem(&ipdata, data.frameNr, 2*MAX_DELAY+1)) {
478 fprintf(stderr, "Error: out of memory.\n");
479 dftEmpty(&data); dftEmpty(&pdata); return(3);
480 }
481 dftCopymainhdr(&pdata, &ipdata); ipdata.timetype=data.timetype;
482 ipdata.voiNr=2*MAX_DELAY+1; ipdata.frameNr=data.frameNr;
483 for(fi=0; fi<data.frameNr; fi++) {
484 ipdata.x[fi]=data.x[fi]; ipdata.x1[fi]=data.x1[fi]; ipdata.x2[fi]=data.x2[fi];}
485 /* Original plasma data */
486 ri=0;
487 if(ipdata.timetype==3) {
488 ret=interpolate4pet(pdata.x, pdata.voi[0].y, pdata.frameNr,
489 ipdata.x1, ipdata.x2,
490 ipdata.voi[ri].y, ipdata.voi[ri].y2, ipdata.voi[ri].y3, ipdata.frameNr);
491 } else {
492 ret=interpolate(pdata.x, pdata.voi[0].y, pdata.frameNr,
493 ipdata.x, ipdata.voi[ri].y, ipdata.voi[ri].y2, ipdata.voi[ri].y3,
494 ipdata.frameNr);
495 }
496 if(ret) {
497 fprintf(stderr, "Error (%d) in interpolation of plasma data.\n", ret);
498 dftEmpty(&data); dftEmpty(&pdata); dftEmpty(&ipdata); return(4);
499 }
500 sprintf(ipdata.voi[ri].voiname, "d%d", 0);
501 if(verbose>3) printf("%s ip-integrals: %g %g %g\n", ipdata.voi[ri].voiname,
502 ipdata.voi[ri].y[ipdata.frameNr-1], ipdata.voi[ri].y2[ipdata.frameNr-1],
503 ipdata.voi[ri].y3[ipdata.frameNr-1]);
504 /* Subtracted times , skip negative times */
505 for(ri=1; ri<=MAX_DELAY; ri++) {
506 for(fi=0; fi<pdata.frameNr; fi++) {
507 pdata.x[fi]-=1.0; pdata.x1[fi]-=1.0; pdata.x2[fi]-=1.0;}
508 if(ipdata.timetype==3)
509 ret=interpolate4pet(pdata.x, pdata.voi[0].y, pdata.frameNr,
510 ipdata.x1, ipdata.x2, ipdata.voi[ri].y, ipdata.voi[ri].y2,
511 ipdata.voi[ri].y3, ipdata.frameNr);
512 else
513 ret=interpolate(pdata.x, pdata.voi[0].y, pdata.frameNr,
514 ipdata.x, ipdata.voi[ri].y, ipdata.voi[ri].y2, ipdata.voi[ri].y3,
515 ipdata.frameNr);
516 if(ret) {
517 fprintf(stderr, "Error (%d) in interpolation.\n", ret);
518 dftEmpty(&data); dftEmpty(&pdata); dftEmpty(&ipdata); return(4);
519 }
520 sprintf(ipdata.voi[ri].voiname, "d%d", -ri);
521 if(verbose>7) printf("%s ip-integrals: %g %g %g\n", ipdata.voi[ri].voiname,
522 ipdata.voi[ri].y[ipdata.frameNr-1], ipdata.voi[ri].y2[ipdata.frameNr-1],
523 ipdata.voi[ri].y3[ipdata.frameNr-1]);
524 }
525 for(fi=0; fi<pdata.frameNr; fi++) {
526 pdata.x[fi]+=(double)MAX_DELAY;
527 pdata.x1[fi]+=(double)MAX_DELAY; pdata.x2[fi]+=(double)MAX_DELAY;
528 }
529 /* Added times */
530 for(ri=MAX_DELAY+1; ri<=2*MAX_DELAY; ri++) {
531 for(fi=0; fi<pdata.frameNr; fi++) {
532 pdata.x[fi]+=1.0; pdata.x1[fi]+=1.0; pdata.x2[fi]+=1.0;}
533 if(ipdata.timetype==DFT_TIME_STARTEND) {
534 ret=interpolate4pet(pdata.x, pdata.voi[0].y, pdata.frameNr,
535 ipdata.x1, ipdata.x2, ipdata.voi[ri].y, ipdata.voi[ri].y2,
536 ipdata.voi[ri].y3, ipdata.frameNr);
537 if(ret==3) { /* time ranges do not match any more */
538 for(fi=0; fi<ipdata.frameNr; fi++)
539 ipdata.voi[ri].y[fi]=ipdata.voi[ri].y2[fi]=ipdata.voi[ri].y3[fi]=0.0;
540 ret=0;
541 }
542 } else {
543 ret=interpolate(pdata.x, pdata.voi[0].y, pdata.frameNr,
544 ipdata.x, ipdata.voi[ri].y, ipdata.voi[ri].y2, ipdata.voi[ri].y3, ipdata.frameNr);
545 }
546 if(ret!=0) {
547 fprintf(stderr, "Error in interpolation (%d).\n", ret);
548 dftEmpty(&data); dftEmpty(&pdata); dftEmpty(&ipdata); return(4);
549 }
550 sprintf(ipdata.voi[ri].voiname, "d%d", ri-MAX_DELAY);
551 if(verbose>7) printf("%s ip-integrals: %g %g %g\n", ipdata.voi[ri].voiname,
552 ipdata.voi[ri].y[ipdata.frameNr-1], ipdata.voi[ri].y2[ipdata.frameNr-1],
553 ipdata.voi[ri].y3[ipdata.frameNr-1]);
554 }
555 for(fi=0; fi<pdata.frameNr; fi++) {
556 pdata.x[fi]-=(double)MAX_DELAY;
557 pdata.x1[fi]-=(double)MAX_DELAY; pdata.x2[fi]-=(double)MAX_DELAY;
558 }
559 if(verbose>6) dftPrint(&ipdata);
560
561
562 /*
563 * Fit K1-k4 & Vb
564 */
565 if(verbose>1) printf("fitting\n");
566 /* Allocate memory required by NNLS */
567 nnls_n=NNLS_N; nnls_m=data.frameNr;
568 nnls_mat=(double*)malloc(((nnls_n+2)*nnls_m)*sizeof(double));
569 if(nnls_mat==NULL) {
570 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
571 dftEmpty(&data); dftEmpty(&pdata); dftEmpty(&ipdata);
572 return(5);
573 }
574 for(n=0, dptr=nnls_mat; n<nnls_n; n++) {nnls_a[n]=dptr; dptr+=nnls_m;}
575 nnls_b=dptr; dptr+=nnls_m; nnls_zz=dptr;
576 /* Allocate memory for delays producing smallest SS */
577 regional_delay=(double*)calloc(data.voiNr, sizeof(double));
578 if(regional_delay==NULL) {
579 fprintf(stderr, "Error: cannot allocate memory for regional delays.\n");
580 dftEmpty(&data); dftEmpty(&pdata); dftEmpty(&ipdata); free(nnls_mat);
581 return(5);
582 }
583 /* Allocate memory for fitted (best) curves */
584 if(ffile[0]) {
585 ret=dftdup(&data, &fdata);
586 if(ret) {
587 fprintf(stderr, "Error: cannot allocate memory for fitted TAC(s).\n");
588 dftEmpty(&data); dftEmpty(&pdata); dftEmpty(&ipdata);
589 free(nnls_mat); free(regional_delay);
590 return(5);
591 }
592 }
593
594 /* Fit with different regions */
595 if(data.isweight) { /* use quare root of weights */
596 for(m=0; m<nnls_m; m++) {
597 if(data.w[m]<=1.0e-20) data.w[m]=0.0; else data.w[m]=sqrt(data.w[m]);}
598 }
599 if(data.voiNr>1) printf("Regional time delays:\n");
600 for(ri=0; ri<data.voiNr; ri++) {
601
602
603 /* If requested, open file to save NNLS matrix in */
604 FILE *mfp=NULL;
605 if(matfile[0]) {
606 mfp=fopen(matfile, "w");
607 if(mfp==NULL) {
608 fprintf(stderr, "Error: cannot write file '%s'.\n", matfile);
609 dftEmpty(&data); dftEmpty(&pdata); dftEmpty(&ipdata);
610 free(nnls_mat); free(regional_delay);
611 return(30);
612 }
613 }
614
615 /* Fit with different delays */
616 min=-1; minv=9.9e+99;
617 for(di=0; di<=2*MAX_DELAY; di++) {
618
619 /* Fill the NNLS data matrix */
620 if(model==1) {
621 for(m=0; m<nnls_m; m++) {
622 nnls_a[0][m]=ipdata.voi[di].y[m];
623 nnls_a[1][m]=ipdata.voi[di].y2[m];
624 nnls_a[2][m]=-data.voi[ri].y2[m];
625 nnls_b[m]=data.voi[ri].y[m];
626 }
627 } else {
628 for(m=0; m<nnls_m; m++) {
629 nnls_a[0][m]=ipdata.voi[di].y[m];
630 nnls_a[1][m]=ipdata.voi[di].y2[m];
631 nnls_a[2][m]=ipdata.voi[di].y3[m];
632 nnls_a[3][m]=-data.voi[ri].y2[m];
633 nnls_a[4][m]=-data.voi[ri].y3[m];
634 nnls_b[m]=data.voi[ri].y[m];
635 }
636 }
637
638 /* Add weights */
639 if(data.isweight) for(m=0; m<nnls_m; m++) {
640 nnls_b[m]*=data.w[m];
641 for(n=0; n<nnls_n; n++) nnls_a[n][m]*=data.w[m];
642 }
643
644 /* If requested, save NNLS matrix in file */
645 if(matfile[0]) {
646 int dt;
647 if(di<=MAX_DELAY) dt=-di; else dt=di-MAX_DELAY;
648 fprintf(mfp, "%d\nB", dt);
649 for(int n=0; n<nnls_n; n++) fprintf(mfp, ",A%d", n+1);
650 fprintf(mfp, "\n");
651 for(int m=0; m<nnls_m; m++) {
652 fprintf(mfp, "%g", nnls_b[m]);
653 for(int n=0; n<nnls_n; n++) fprintf(mfp, ",%g", nnls_a[n][m]);
654 fprintf(mfp, "\n");
655 }
656 }
657
658 /* NNLS */
659 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
660 if(ret>1) { /* no solution is possible */
661 continue;
662 } else if(ret==1) { /* max iteration count exceeded */ }
663 /* Get coefficients */
664 for(n=0; n<nnls_n; n++) coeff[n]=nnls_x[n];
665 /* Calculate Sum-of-Squares */
666 if(model==1) {
667 for(m=0; m<nnls_m; m++) {
668 nnls_a[0][m]=ipdata.voi[di].y[m];
669 nnls_a[1][m]=ipdata.voi[di].y2[m];
670 nnls_a[2][m]=-data.voi[ri].y2[m];
671 nnls_b[m]=data.voi[ri].y[m];
672 }
673 } else {
674 for(m=0; m<nnls_m; m++) {
675 nnls_a[0][m]=ipdata.voi[di].y[m];
676 nnls_a[1][m]=ipdata.voi[di].y2[m];
677 nnls_a[2][m]=ipdata.voi[di].y3[m];
678 nnls_a[3][m]=-data.voi[ri].y2[m];
679 nnls_a[4][m]=-data.voi[ri].y3[m];
680 nnls_b[m]=data.voi[ri].y[m];
681 }
682 }
683 if(ffile[0]) {
684 for(m=0, ss=0.0; m<nnls_m; m++) {
685 for(n=0, f=0.0; n<nnls_n; n++) f+=nnls_x[n]*nnls_a[n][m];
686 fdata.voi[ri].y2[m]=f;
687 }
688 }
689 if(data.isweight) for(m=0; m<nnls_m; m++) {
690 nnls_b[m]*=data.w[m];
691 for(n=0; n<nnls_n; n++) nnls_a[n][m]*=data.w[m];
692 }
693 for(m=0, ss=0.0; m<nnls_m; m++) {
694 for(n=0, f=0.0; n<nnls_n; n++) f+=nnls_x[n]*nnls_a[n][m];
695 v=f; f-=nnls_b[m]; ss+=f*f;
696 }
697
698 if(verbose>4) {
699 if(model==1) {
700 printf("Fit %2d -> SS=%12.3e Vb=%g K1+Vb*k2=%g k2=%g\n", di, ss, coeff[0], coeff[1], coeff[2]);
701 } else {
702 printf("Fit %2d -> SS=%12.3e Vb=%g K1+Vb*(k2+k3+k4)=%g\n", di, ss, coeff[0], coeff[1]);
703 printf(" K1*(k3+k4)=%g k2+k3+k4=%g k2k4=%g\n", coeff[2], coeff[3], coeff[4]);
704 }
705 }
706
707 /* Check if minimum SS */
708 if(ss<minv) {
709 minv=ss; min=di;
710 if(ffile[0]) for(m=0; m<nnls_m; m++) fdata.voi[ri].y[m]=fdata.voi[ri].y2[m];
711 }
712
713 } /* next delay time */
714
715 if(matfile[0]) fclose(mfp);
716
717 /* what delay times the minima are? */
718 if(verbose>5) printf(" min TAC (%s) := %d\n", data.voi[ri].name, min);
719 if(min<=MAX_DELAY) min=-min; else min-=MAX_DELAY;
720 regional_delay[ri]=(double)min;
721 if(verbose>=0 && data.voiNr>1)
722 printf(" time_delay for %s := %g s\n", data.voi[ri].name, regional_delay[ri]);
723
724 } /* next region */
725
726 /* Free memory of fit data */
727 free(nnls_mat);
728
729
730 /*
731 * Calculate the median of all delay values
732 */
733 if(verbose>1) printf("calculating median\n");
734 v=dmedian(regional_delay, data.voiNr);
735 /* regional delays are not needed any more */
736 free(regional_delay);
737 if(verbose>=0) {
738 printf("Estimated tracer appearance time in plasma := %.1f s\n", onep);
739 printf("Estimated tracer appearance time in tissue := %.1f s\n", onep+(double)v);
740 printf("Median time delay := %g s\n", v);
741 }
742
743 /* Check that plasma is not moved too much to the left */
744 /* i.e. it should not start to rise before time 0 */
745 /*
746 if(-v>onep) v=-onep;
747 printf("Applied delay %g s\n", v);
748 */
749 if(-v>onep) {
750 fprintf(stderr, "Warning: possible error in determined tracer appearance time.\n");
751 fprintf(stderr, " Please check the delay corrected input against tissue data.\n");
752 }
753
754 /* Ok this is the final delay time (in seconds) */
755 double delayT=v;
756
757
758 /*
759 * Delay correction for input data
760 */
761 if(verbose>1) printf("correcting input TACs\n");
762 for(fi=0; fi<pdata.frameNr; fi++) {
763 pdata.x[fi]+=delayT; pdata.x1[fi]+=delayT; pdata.x2[fi]+=delayT;}
764 /* Remove samples which have now negative times */
765 fi=0; while(fi<pdata.frameNr) {
766 if(pdata.x[fi]>=0.0) break;
767 for(fj=fi+1; fj<pdata.frameNr; fj++) {
768 for(ri=0; ri<pdata.voiNr; ri++) pdata.voi[ri].y[fj-1]=pdata.voi[ri].y[fj];
769 pdata.x[fj-1]=pdata.x[fj]; pdata.x1[fj-1]=pdata.x1[fj];
770 pdata.x2[fj-1]=pdata.x2[fj];
771 }
772 pdata.frameNr--;
773 }
774 if(pdata.frameNr<=0) {
775 fprintf(stderr, "Error: no positive sample times left.\n");
776 dftEmpty(&data); dftEmpty(&pdata); dftEmpty(&ipdata); dftEmpty(&fdata);
777 return(6);
778 }
779 if(verbose>10) dftPrint(&pdata);
780
781
782 /*
783 * Save delay corrected plasma data
784 */
785 /* If not specified, then create the filename for output */
786 if(!rfile[0]) {
787 cptr=strrchr(pfile, '.'); if(cptr!=NULL) n=strlen(cptr); else n=0;
788 strcpy(rfile, pfile); rfile[strlen(pfile)-n]=(char)0;
789 strcat(rfile, ".delay"); if(cptr!=NULL) strcat(rfile, cptr);
790 if(verbose>2) printf("rfile := %s\n", rfile);
791 if(verbose>=0) printf(" %s -> %s\n", pfile, rfile);
792 }
793 /* Set output file format */
794 if(output_format!=DFT_FORMAT_UNKNOWN) pdata._type=output_format;
795 /* Change times back to original unit if necessary */
796 if(pdata.timeunit!=orig_input_time_unit) {
797 if(verbose>2) printf("converting input %s to %s\n",
798 petTunit(pdata.timeunit), petTunit(orig_input_time_unit) );
799 if(verbose>3) printf("last_t := %g\n", pdata.x[pdata.frameNr-1]);
800 ret=dftTimeunitConversion(&pdata, orig_input_time_unit);
801 if(verbose>3) printf("last_t := %g\n", pdata.x[pdata.frameNr-1]);
802 }
803 /* Write the log information, if required */
804 dftSetComments(&pdata);
805 if(make_log!=0) {
806 //if(strlen(pdata.comments)>0) strcat(pdata.comments, "\n");
807 sprintf(tmp, "# delay_fit_time := %g s\n", length);
808 strcat(pdata.comments, tmp);
809 sprintf(tmp, "# time_delay := %g s\n", delayT);
810 strcat(pdata.comments, tmp);
811 sprintf(tmp, "# tissue_compartment_nr := %d\n", model);
812 strcat(pdata.comments, tmp);
813 }
814 /* Write the TAC */
815 if(verbose>1) printf("writing %s\n", rfile);
816 if(dftWrite(&pdata, rfile)) {
817 fprintf(stderr, "Error in writing '%s': %s\n", rfile, dfterrmsg);
818 dftEmpty(&data); dftEmpty(&pdata); dftEmpty(&ipdata); dftEmpty(&fdata);
819 return(11);
820 }
821
822 /*
823 * Free memory
824 */
825 dftEmpty(&pdata); dftEmpty(&ipdata);
826
827 /*
828 * Save fitted TACs, if necessary
829 */
830 if(ffile[0]) {
831 sprintf(fdata.comments, "# Curves fitted from %s\n", tfile);
832
833 /* Change times back to original unit if necessary */
834 if(data.timeunit!=orig_tissue_time_unit) {
835 ret=dftTimeunitConversion(&data, orig_tissue_time_unit);
836 }
837 dftSetComments(&fdata);
838 if(make_log!=0) {
839 //if(strlen(pdata.comments)>0) strcat(pdata.comments, "\n");
840 sprintf(tmp, "# delay_fit_time := %g s\n", length);
841 strcat(pdata.comments, tmp);
842 sprintf(tmp, "# time_delay := %g s\n", delayT);
843 strcat(pdata.comments, tmp);
844 sprintf(tmp, "# tissue_compartment_nr := %d\n", model);
845 strcat(pdata.comments, tmp);
846 }
847 if(verbose>1) printf("writing %s\n", ffile);
848 if(dftWrite(&fdata, ffile)) {
849 fprintf(stderr, "Error in writing '%s': %s\n", ffile, dfterrmsg);
850 dftEmpty(&data); dftEmpty(&fdata);
851 return(13);
852 }
853 }
854 dftEmpty(&fdata);
855
856
857 /*
858 * Delay correction for other files, if required
859 */
860 if(p2file[0]) {
861 /* Read in */
862 if(verbose>1) printf("reading %s\n", p2file);
863 if(dftRead(p2file, &pdata)) {
864 fprintf(stderr, "Error in reading '%s': %s\n", p2file, dfterrmsg);
865 dftEmpty(&data); return(8);
866 }
867 /* If time unit is unknown, then set it */
868 if(pdata.timeunit==TUNIT_UNKNOWN) {
869 /* Assume that it is the same as in input data */
870 pdata.timeunit=orig_input_time_unit;
871 }
872 /* Make delay correction, changing delay time to correct units */
873 f=delayT; if(pdata.timeunit==TUNIT_MIN) f/=60;
874 for(fi=0; fi<pdata.frameNr; fi++) {
875 pdata.x[fi]+=f; pdata.x1[fi]+=f; pdata.x2[fi]+=f;}
876 /* Remove negative times */
877 fi=0; while(fi<pdata.frameNr) {
878 if(pdata.x[fi]>=0.0) break;
879 for(fj=fi+1; fj<pdata.frameNr; fj++) {
880 for(ri=0; ri<pdata.voiNr; ri++)
881 pdata.voi[ri].y[fj-1]=pdata.voi[ri].y[fj];
882 pdata.x[fj-1]=pdata.x[fj]; pdata.x1[fj-1]=pdata.x1[fj];
883 pdata.x2[fj-1]=pdata.x2[fj];
884 }
885 pdata.frameNr--;
886 }
887 if(pdata.frameNr<=0) {
888 fprintf(stderr, "Error: no positive sample times left.\n");
889 dftEmpty(&data); dftEmpty(&pdata); return(9);
890 }
891 /* Construct output filename */
892 if(!r2file[0]) {
893 strcpy(r2file, p2file); cptr=strrchr(p2file, '.');
894 if(cptr!=NULL) r2file[strlen(p2file)-strlen(cptr)]=(char)0;
895 strcat(r2file, ".delay"); if(cptr!=NULL) strcat(r2file, cptr);
896 }
897 /* Set output file format */
898 if(output_format!=DFT_FORMAT_UNKNOWN) pdata._type=output_format;
899 /* Save output file */
900 dftSetComments(&pdata);
901 if(make_log!=0) {
902 //if(strlen(pdata.comments)>0) strcat(pdata.comments, "\n");
903 sprintf(tmp, "# delay_fit_time := %g s\n", length);
904 strcat(pdata.comments, tmp);
905 sprintf(tmp, "# time_delay := %g s\n", delayT);
906 strcat(pdata.comments, tmp);
907 sprintf(tmp, "# tissue_compartment_nr := %d\n", model);
908 strcat(pdata.comments, tmp);
909 }
910 if(verbose>=0) printf(" %s -> %s\n", p2file, r2file);
911 ret=dftWrite(&pdata, r2file); dftEmpty(&pdata);
912 if(ret) {
913 fprintf(stderr,
914 "Error (%d) in writing '%s': %s\n", ret, r2file, dfterrmsg);
915 dftEmpty(&data); dftEmpty(&pdata); return(16);
916 }
917 }
918
919 if(p3file[0]) {
920 /* Read in */
921 if(verbose>1) printf("reading %s\n", p3file);
922 dftEmpty(&pdata);
923 if(dftRead(p3file, &pdata)) {
924 fprintf(stderr, "Error in reading '%s': %s\n", p3file, dfterrmsg);
925 dftEmpty(&data); return(8);
926 }
927 /* If time unit is unknown, then set it */
928 if(pdata.timeunit==TUNIT_UNKNOWN) {
929 /* Assume that it is the same as in input data */
930 pdata.timeunit=orig_input_time_unit;
931 }
932 /* Make delay correction, changing delay time to correct units */
933 f=delayT; if(pdata.timeunit==TUNIT_MIN) f/=60;
934 for(fi=0; fi<pdata.frameNr; fi++) {
935 pdata.x[fi]+=f; pdata.x1[fi]+=f; pdata.x2[fi]+=f;}
936 /* Remove negative times */
937 fi=0; while(fi<pdata.frameNr) {
938 if(pdata.x[fi]>=0.0) break;
939 for(fj=fi+1; fj<pdata.frameNr; fj++) {
940 for(ri=0; ri<pdata.voiNr; ri++)
941 pdata.voi[ri].y[fj-1]=pdata.voi[ri].y[fj];
942 pdata.x[fj-1]=pdata.x[fj]; pdata.x1[fj-1]=pdata.x1[fj];
943 pdata.x2[fj-1]=pdata.x2[fj];
944 }
945 pdata.frameNr--;
946 }
947 if(pdata.frameNr<=0) {
948 fprintf(stderr, "Error: no positive sample times left.\n");
949 dftEmpty(&data); dftEmpty(&pdata); return(9);
950 }
951 /* Construct output filename */
952 if(!r3file[0]) {
953 strcpy(r3file, p3file); cptr=strrchr(p3file, '.');
954 if(cptr!=NULL) r3file[strlen(p3file)-strlen(cptr)]=(char)0;
955 strcat(r3file, ".delay"); if(cptr!=NULL) strcat(r3file, cptr);
956 }
957 /* Set output file format */
958 if(output_format!=DFT_FORMAT_UNKNOWN) pdata._type=output_format;
959 /* Save output file */
960 dftSetComments(&pdata);
961 if(make_log!=0) {
962 //if(strlen(pdata.comments)>0) strcat(pdata.comments, "\n");
963 sprintf(tmp, "# delay_fit_time := %g s\n", length);
964 strcat(pdata.comments, tmp);
965 sprintf(tmp, "# time_delay := %g s\n", delayT);
966 strcat(pdata.comments, tmp);
967 sprintf(tmp, "# tissue_compartment_nr := %d\n", model);
968 strcat(pdata.comments, tmp);
969 }
970 if(verbose>=0) printf(" %s -> %s\n", p3file, r3file);
971 ret=dftWrite(&pdata, r3file); dftEmpty(&pdata);
972 if(ret) {
973 fprintf(stderr, "Error (%d) in writing '%s': %s\n", ret, r3file, dfterrmsg);
974 dftEmpty(&data); dftEmpty(&pdata); return(17);
975 }
976 }
977
978 if(p4file[0]) {
979 /* Read in */
980 if(verbose>1) printf("reading %s\n", p4file);
981 dftEmpty(&pdata);
982 if(dftRead(p4file, &pdata)) {
983 fprintf(stderr, "Error in reading '%s': %s\n", p4file, dfterrmsg);
984 dftEmpty(&data); return(8);
985 }
986 /* If time unit is unknown, then set it */
987 if(pdata.timeunit==TUNIT_UNKNOWN) {
988 /* Assume that it is the same as in input data */
989 pdata.timeunit=orig_input_time_unit;
990 }
991 /* Make delay correction, changing delay time to correct units */
992 f=delayT; if(pdata.timeunit==TUNIT_MIN) f/=60;
993 for(fi=0; fi<pdata.frameNr; fi++) {
994 pdata.x[fi]+=f; pdata.x1[fi]+=f; pdata.x2[fi]+=f;}
995 /* Remove negative times */
996 fi=0; while(fi<pdata.frameNr) {
997 if(pdata.x[fi]>=0.0) break;
998 for(fj=fi+1; fj<pdata.frameNr; fj++) {
999 for(ri=0; ri<pdata.voiNr; ri++) pdata.voi[ri].y[fj-1]=pdata.voi[ri].y[fj];
1000 pdata.x[fj-1]=pdata.x[fj]; pdata.x1[fj-1]=pdata.x1[fj];
1001 pdata.x2[fj-1]=pdata.x2[fj];
1002 }
1003 pdata.frameNr--;
1004 }
1005 if(pdata.frameNr<=0) {
1006 fprintf(stderr, "Error: no positive sample times left.\n");
1007 dftEmpty(&data); dftEmpty(&pdata); return(9);
1008 }
1009 /* Construct output filename */
1010 if(!r4file[0]) {
1011 strcpy(r4file, p4file); cptr=strrchr(p4file, '.');
1012 if(cptr!=NULL) r4file[strlen(p3file)-strlen(cptr)]=(char)0;
1013 strcat(r4file, ".delay"); if(cptr!=NULL) strcat(r4file, cptr);
1014 }
1015 /* Set output file format */
1016 if(output_format!=DFT_FORMAT_UNKNOWN) pdata._type=output_format;
1017 /* Save output file */
1018 dftSetComments(&pdata);
1019 if(make_log!=0) {
1020 //if(strlen(pdata.comments)>0) strcat(pdata.comments, "\n");
1021 sprintf(tmp, "# delay_fit_time := %g s\n", length);
1022 strcat(pdata.comments, tmp);
1023 sprintf(tmp, "# time_delay := %g s\n", delayT);
1024 strcat(pdata.comments, tmp);
1025 sprintf(tmp, "# tissue_compartment_nr := %d\n", model);
1026 strcat(pdata.comments, tmp);
1027 }
1028 if(verbose>=0) printf(" %s -> %s\n", p4file, r4file);
1029 ret=dftWrite(&pdata, r4file); dftEmpty(&pdata);
1030 if(ret) {
1031 fprintf(stderr, "Error (%d) in writing '%s': %s\n", ret, r4file, dfterrmsg);
1032 dftEmpty(&data); dftEmpty(&pdata); return(18);
1033 }
1034 }
1035
1036 /*
1037 * Free memory
1038 */
1039 dftEmpty(&data); dftEmpty(&pdata);
1040
1041 return(0);
1042}
1043/*****************************************************************************/
1044
1045/*****************************************************************************/
double atof_dpi(char *str)
Definition decpoint.c:59
void dftInit(DFT *data)
Definition dft.c:38
int dftdup(DFT *dft1, DFT *dft2)
Definition dft.c:655
char dfterrmsg[64]
Definition dft.c:6
void dftSetComments(DFT *dft)
Definition dft.c:1326
int dftSetmem(DFT *data, int frameNr, int voiNr)
Definition dft.c:57
void dftEmpty(DFT *data)
Definition dft.c:20
int dftCopymainhdr(DFT *dft1, DFT *dft2)
Definition dft.c:561
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
int dftTimeunitConversion(DFT *dft, int tunit)
Definition dftunit.c:119
int petintegral(double *x1, double *x2, double *y, int nr, double *ie, double *iie)
Integrate PET TAC data to frame mid times.
Definition integr.c:771
int integrate(double *x, double *y, int nr, double *yi)
Definition integr.c:271
int interpolate(double *x, double *y, int nr, double *newx, double *newy, double *newyi, double *newyii, int newnr)
Linear interpolation and integration.
Definition integr.c:28
int interpolate4pet(double *x, double *y, int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, int newnr)
Interpolate and integrate TAC to PET frames.
Definition integr.c:510
Header file for libtpccurveio.
#define DFT_FORMAT_PMOD
#define DFT_FORMAT_STANDARD
#define DFT_FORMAT_IF
#define DFT_FORMAT_PLAIN
#define DFT_TIME_STARTEND
#define DFT_FORMAT_UNKNOWN
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
char * petTunit(int tunit)
Definition petunits.c:226
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
Header file for libtpcmodel.
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *w, double *zz, int *index)
Definition nnls.c:37
double dmedian(double *data, int n)
Definition median.c:48
int _type
int timetype
Voi * voi
int timeunit
double * w
double * x1
char comments[_DFT_COMMENT_LEN+1]
int voiNr
double * x2
int frameNr
int isweight
double * x
double * y2
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
char name[MAX_REGIONNAME_LEN+1]
double * y3