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