TPCCLIB
Loading...
Searching...
No Matches
imgbfbp.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#include <time.h>
17/*****************************************************************************/
18#include "libtpccurveio.h"
19#include "libtpcmodext.h"
20#include "libtpcmisc.h"
21#include "libtpcmodel.h"
22#include "libtpcimgio.h"
23#include "libtpcimgp.h"
24/*****************************************************************************/
25#define MAX_N 2
26/*****************************************************************************/
27
28/*****************************************************************************/
29static char *info[] = {
30 "Computation of parametric image of binding potential (BPnd) from",
31 "dynamic PET images in ECAT, NIfTI, or Analyze format applying simplified",
32 "reference tissue model (SRTM) [1]. The model is solved using the basis",
33 "function approach [2], similar to the RPM program.",
34 "Note that default limits for theta3 are suitable for [C-11]raclopride;",
35 "for other tracers the limits need to be set using command-line options."
36 " ",
37 "Dynamic PET image and reference region TAC must be corrected for decay.",
38 " ",
39 "Fit is always weighted (unless specific weighting options are used), either",
40 "based on the counts in SIF provided by user, or if SIF is not provided,",
41 "then weights are estimated based on the mean radioactivity concentration",
42 "in the dynamic image.",
43 " ",
44 "Usage: @P [Options] imgfile rtacfile bpfile [sif]",
45 " ",
46 "Options:",
47 " -R1=<filename>",
48 " Programs computes also an R1 image.",
49 " -k2=<filename>",
50 " Programs computes also a k2 image.",
51 " -min=<value (1/min)>",
52 " Set minimum value for theta3; it must be >= k2min/(1+BPmax)+lambda.",
53 " Default is 0.06 min-1. Lambda for F-18 is 0.0063 and for C-11 0.034.",
54 " -max=<value (1/min)>",
55 " Set maximum value for theta3; it must be <= k2max+lambda.",
56 " Default is 0.60 min-1.",
57 " -nr=<value>",
58 " Set number of basis functions; default is 500, minimum 100.",
59 " -bf=<filename>",
60 " Basis function curves are written in specified file.",
61 " -wss=<filename>",
62 " Weighted sum-of-squares are written in specified image file.",
63 " -err=<filename>",
64 " Pixels with their theta3 in its min or max value are written",
65 " in the specified imagefile with values 1 and 2, respectively,",
66 " others with value 0.",
67 " -thr=<threshold%>",
68 " Pixels with AUC less than (threshold/100 x ref AUC) are set to zero;",
69 " default is 0%",
70 " -DVR",
71 " Instead of BP, program saves the DVR (=BP+1) values.",
72 " -noneg",
73 " Pixels with negative BP values are set to zero.",
74 " -end=<Fit end time (min)>",
75 " Use data from 0 to end time; by default, model is fitted to all frames.",
76 " -savesif=<filename>",
77 " If weights are created based on image data, then created SIF can be",
78 " saved with this option.",
79 " -wf | -w1",
80 " Weights are based only on frame length (-wf), or set to 1.0 (-w1).",
81 " -stdoptions", // List standard options like --help, -v, etc
82 " ",
83 "Example:",
84 " @P ua2918dy1.v ua2918cer.dft ua2918bp.v",
85 " ",
86 "References:",
87 "1. Lammertsma AA, Hume SP. Simplified reference tissue model for PET",
88 " receptor studies. NeuroImage 1996;4:153-158.",
89 "2. Gunn RN, Lammertsma AA, Hume SP, Cunningham VJ. Parametric imaging of",
90 " ligand-receptor binding in PET using a simplified reference region",
91 " model. NeuroImage 1997;6:279-287.",
92 " ",
93 "See also: imgunit, eframe, imgweigh, tacweigh, imgdecay, imgsrtm, bfmsrtm",
94 " ",
95 "Keywords: image, modelling, binding potential, SRTM, reference input",
96 0};
97/*****************************************************************************/
98
99/*****************************************************************************/
100/* Turn on the globbing of the command line, since it is disabled by default in
101 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
102 In Unix&Linux wildcard command line processing is enabled by default. */
103/*
104#undef _CRT_glob
105#define _CRT_glob -1
106*/
107int _dowildcard = -1;
108/*****************************************************************************/
109
110/*****************************************************************************/
114int main(int argc, char **argv)
115{
116 int ai, help=0, version=0, verbose=1;
117 int fitdimt;
118 char inpfile[FILENAME_MAX], petfile[FILENAME_MAX], bpfile[FILENAME_MAX];
119 char r1file[FILENAME_MAX], k2file[FILENAME_MAX], wssfile[FILENAME_MAX];
120 char errfile[FILENAME_MAX], siffile[FILENAME_MAX], bffile[FILENAME_MAX];
121 char newsiffile[FILENAME_MAX], tmp[FILENAME_MAX+1], *cptr;
122 int bfNr=500, bp_plus_one=0, *bf_opt_nr;
123 float threshold, calcThreshold=0.0;
124 double fittime=-1.0, f;
125 double t3min=0.06, t3max=0.6, lambda;
126 double BP, k2, wss, p1, p2, p3, rnorm_min;
127 SIF sif;
128 int ret, fi, pi, xi, yi, bi, bi_min;
129 int nosolution_nr=0, thresholded_nr=0;
130 int nonnegativity_constraint=0;
131 double WCORR_LIMIT = 100.0;
132 clock_t fitStart, fitFinish;
133 int weight_method=0; // 0=Mazoyer; 1=no weighting (set to 1.0);
134 // 2=frame duration
135
136 DFT tac, bf;
137 IMG img, bpimg, r1img, k2img, wssimg, errimg;
138 /* qr */
139 int m, n, M, N;
140 double **mem, **A, *B, X[MAX_N], *tau, *residual, RNORM, *chain;
141 double *qrweight, **wws, *ws, *wwschain, *ct, *cti;
142
143
144
145 /*
146 * Get arguments
147 */
148 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
149 inpfile[0]=petfile[0]=bpfile[0]=r1file[0]=k2file[0]=wssfile[0]=(char)0;
150 errfile[0]=siffile[0]=newsiffile[0]=bffile[0]=(char)0;
151 /* Get options */
152 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
153 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
154 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
155 if(strcasecmp(cptr, "DVR")==0 || strcasecmp(cptr, "BP+1")==0) {
156 bp_plus_one=1; continue;
157 } else if(strncasecmp(cptr, "R1=", 3)==0) {
158 strlcpy(r1file, cptr+3, FILENAME_MAX); continue;
159 } else if(strncasecmp(cptr, "k2=", 3)==0) {
160 strlcpy(k2file, cptr+3, FILENAME_MAX); continue;
161 } else if(strncasecmp(cptr, "NR=", 3)==0) {
162 bfNr=atoi(cptr+3); if(bfNr>5E+04) bfNr=5E+04;
163 if(bfNr>=100) continue;
164 } else if(strncasecmp(cptr, "MIN=", 4)==0) {
165 t3min=atof_dpi(cptr+4); if(t3min>0.0) continue;
166 } else if(strncasecmp(cptr, "MAX=", 4)==0) {
167 t3max=atof_dpi(cptr+4); if(t3max>0.0) continue;
168 } else if(strncasecmp(cptr, "BF=", 3)==0) {
169 strlcpy(bffile, cptr+3, FILENAME_MAX); continue;
170 } else if(strncasecmp(cptr, "WSS=", 4)==0) {
171 strlcpy(wssfile, cptr+4, FILENAME_MAX); continue;
172 } else if(strncasecmp(cptr, "ERR=", 4)==0) {
173 strlcpy(errfile, cptr+4, FILENAME_MAX); continue;
174 } else if(strncasecmp(cptr, "THR=", 4)==0) {
175 double v; ret=atof_with_check(cptr+4, &v);
176 if(!ret && v>=0.0 && v<200.0) {calcThreshold=(float)(0.01*v); continue;}
177 } else if(strncasecmp(cptr, "END=", 4)==0) {
178 fittime=60.0*atof_dpi(cptr+4); if(fittime>0.0) continue;
179 } else if(strncasecmp(cptr, "NONEG", 3)==0) {
180 nonnegativity_constraint=1; continue;
181 } else if(strncasecmp(cptr, "SAVESIF=", 8)==0) {
182 strlcpy(newsiffile, cptr+8, FILENAME_MAX); continue;
183 } else if(strcasecmp(cptr, "W1")==0) {
184 weight_method=1; continue;
185 } else if(strcasecmp(cptr, "WF")==0) {
186 weight_method=2; continue;
187 }
188 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
189 return(1);
190 } else break;
191
192 /* Print help or version? */
193 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
194 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
195 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
196
197 /* Process other arguments, starting from the first non-option */
198 if(ai<argc) strlcpy(petfile, argv[ai++], FILENAME_MAX);
199 if(ai<argc) strlcpy(inpfile, argv[ai++], FILENAME_MAX);
200 if(ai<argc) strlcpy(bpfile, argv[ai++], FILENAME_MAX);
201 if(ai<argc) strlcpy(siffile, argv[ai++], FILENAME_MAX);
202 if(ai<argc) {
203 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
204 return(1);
205 }
206 /* Did we get all the information that we need? */
207 if(!bpfile[0]) {
208 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
209 return(1);
210 }
211 if(t3min>=t3max) {
212 fprintf(stderr, "Error: invalid theta3 bounds.\n"); return(1);}
213 /* Do not accidentally overwrite sif, in case user forgot to enter previous
214 argument */
215 if(!siffile[0]) {
216 cptr=strrchr(bpfile, '.');
217 if(cptr!=NULL && strcasecmp(cptr, ".SIF")==0) {
218 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
219 return(1);
220 }
221 }
222 /* Give warning if user entered option -savesif, but we're not gonna do it */
223 if(weight_method!=0 && newsiffile[0]) {
224 fprintf(stderr, "Warning: SIF will not be saved with options -w1 and -wf.\n");
225 }
226
227 /* In verbose mode print arguments and options */
228 if(verbose>1) {
229 printf("petfile := %s\n", petfile);
230 printf("inpfile := %s\n", inpfile);
231 printf("bpfile := %s\n", bpfile);
232 printf("siffile := %s\n", siffile);
233 if(r1file[0]) printf("r1file := %s\n", r1file);
234 if(k2file[0]) printf("k2file := %s\n", k2file);
235 if(wssfile[0]) printf("wssfile := %s\n", wssfile);
236 if(errfile[0]) printf("errfile := %s\n", errfile);
237 if(newsiffile[0]) printf("newsiffile := %s\n", newsiffile);
238 printf("bp_plus_one := %d\n", bp_plus_one);
239 printf("t3min := %g\n", t3min);
240 printf("t3max := %g\n", t3max);
241 printf("bfNr := %d\n", bfNr);
242 printf("calcThreshold := %g\n", calcThreshold);
243 printf("nonnegativity_constraint := %d\n", nonnegativity_constraint);
244 if(fittime>0.0) printf("required_fittime := %g min\n", fittime/60.0);
245 printf("weight_method := %d\n", weight_method);
246 }
247 if(verbose>8) {IMG_TEST=verbose-8; SIF_TEST=verbose-8;}
248 else IMG_TEST=SIF_TEST=0;
249
250
251 sifInit(&sif);
252
253 /*
254 * Read PET image and reference tissue TAC
255 */
256 fittime/=60.; imgInit(&img); dftInit(&tac);
258 petfile, siffile, inpfile, NULL, NULL, &fittime, &fitdimt, &img,
259 NULL, &tac, 1, stdout, verbose-2, tmp);
260 if(ret!=0) {
261 fprintf(stderr, "Error: %s.\n", tmp);
262 if(verbose>1) printf(" ret := %d\n", ret);
263 return(2);
264 }
265 fittime*=60.;
266 if(imgNaNs(&img, 1)>0)
267 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
268 /* Half-life ok? */
269 if(img.isotopeHalflife<1.0) {
270 fprintf(stderr, "Error: image does not contain isotope halflife.\n");
271 imgEmpty(&img); dftEmpty(&tac); return(3);
272 }
273
274 /*
275 * Remove decay correction from the image and from the reference data
276 */
277 lambda=hl2lambda(img.isotopeHalflife/60.0);
278 if(verbose>1) fprintf(stdout, "lambda := %g min-1\n", lambda);
279 /* image */
281 // Assuming that image is decay corrected
282 fprintf(stderr, "Warning: image decay correction is removed.\n");
284 }
286 if(verbose>1) fprintf(stdout, "Removing decay correction from image\n");
287 ret=imgDecayCorrection(&img, 0);
288 if(ret) {
289 fprintf(stderr, "Error: cannot remove decay correction from image.\n");
290 imgEmpty(&img); dftEmpty(&tac); return(4);
291 }
292 } else if(verbose>0) {
293 fprintf(stderr, "Note: image is supposed to have no decay correction.\n");
294 }
295 /* reference tac */
297 // Assuming that reference TAC is decay corrected
298 fprintf(stderr, "Warning: decay correction in reference TAC is removed.\n");
300 }
302 if(verbose>1)
303 fprintf(stdout, "Removing decay correction from reference TAC\n");
304 ret=dftDecayCorrection(&tac, img.isotopeHalflife/60.0, 0, 1, 0, 0,
305 tmp, verbose-3);
306 if(ret) {
307 fprintf(stderr,
308 "Error: cannot remove decay correction from reference TAC.\n");
309 fprintf(stderr, "Error: %s.\n", tmp);
310 imgEmpty(&img); dftEmpty(&tac); return(4);
311 }
312 } else if(verbose>0) {
313 fprintf(stderr,
314 "Note: reference TAC is supposed to have no decay correction.\n");
315 }
316 /* Set time unit to min */
317 ret=dftTimeunitConversion(&tac, TUNIT_MIN);
318 /* Allocate memory for tissue data and integrals */
319 ret=dftAddmem(&tac, 1);
320 if(ret!=0) {
321 fprintf(stderr, "Error (%d) in allocating memory.\n", ret);
322 imgEmpty(&img); dftEmpty(&tac);
323 return(4);
324 }
325 strcpy(tac.voi[0].voiname, "input");
326 strcpy(tac.voi[1].voiname, "tissue");
327 if(verbose>1) {
328 printf("fittimeFinal := %g min\n", fittime/60.0);
329 printf("fitdimt := %d\n", fitdimt);
330 }
331
332
333 /* Determine the threshold */
334 if(verbose>20) dftPrint(&tac);
335 if(verbose>2) printf("ref_AUC[%g] := %g\n",
336 tac.x2[fitdimt-1], tac.voi[0].y2[fitdimt-1]);
337 threshold=calcThreshold*tac.voi[0].y2[fitdimt-1];
338 if(verbose>1) printf("threshold_AUC = %g\n", threshold);
339
340
341 /*
342 * Determine the weights for the fit
343 */
344 if(verbose>1) printf("setting weights\n");
345 /* If there is a SIF file with count data then use it */
346 if(weight_method==0 && siffile[0]) {
347 /* Read SIF file, this hopefully also contains the weights */
348 if(verbose>1) printf("reading %s\n", siffile);
349 ret=sifRead(siffile, &sif);
350 if(ret) {
351 fprintf(stderr, "Error in reading '%s': %s\n", siffile, siferrmsg);
352 imgEmpty(&img); dftEmpty(&tac); return(6);
353 }
354 if(verbose>7) sifPrint(&sif);
355 if(sif.frameNr<tac.frameNr) {
356 fprintf(stderr, "Error: different frame number in SIF and image.\n");
357 imgEmpty(&img); dftEmpty(&tac); sifEmpty(&sif); return(6);
358 }
359 /* Check that SIF actually contains count data */
360 if(sifExistentCounts(&sif)>0) {
361 /* Calculate weights for non-decay corrected data */
362 if(verbose>3) printf("compute the SIF weights.\n");
363 sifModerateTrues(&sif, WCORR_LIMIT);
364 sifWeight(&sif, 0.0); if(verbose>3) sifPrint(&sif);
365 /* Copy the weights to tac and img */
366 for(fi=0; fi<tac.frameNr; fi++) tac.w[fi]=img.weight[fi]=sif.weights[fi];
367 tac.isweight=1; img.isWeight=1;
368 } else {
369 fprintf(stderr, "Warning: SIF does not contain valid prompts data for weighting.\n");
370 strcpy(siffile, ""); // then calculated from image data in the next step
371 }
372 /* no need for SIF any more */
373 sifEmpty(&sif);
374 }
375 if(weight_method==0 && !siffile[0]) {
376 /* If no SIF, then calculate weights from the image */
377 if(verbose>0) fprintf(stdout, "calculating weights for the fit.\n");
378 /* Allocate memory for 'sif' data */
379 ret=sifSetmem(&sif, fitdimt);
380 if(ret) {
381 fprintf(stderr, "Error: out of memory.\n");
382 imgEmpty(&img); dftEmpty(&tac); return(6);
383 }
384 if(verbose>3)
385 printf("Memory for SIF allocated (sif.frameNr=%d).\n", sif.frameNr);
386 /* Set SIF information */
387 sif.colNr=4; strcpy(sif.isotope_name, "");
388 for(fi=0; fi<fitdimt; fi++) {
389 sif.x1[fi]=img.start[fi]; sif.x2[fi]=img.end[fi];}
390 sif.scantime=img.scanStart; sif.version=1;
391 /* Calculate average curve of all pixels */
392 if(verbose>3) printf("calculate image average curve.\n");
393 (void)imgAverageTAC(&img, img.weight);
394 for(fi=0; fi<fitdimt; fi++) sif.trues[fi]=img.weight[fi];
395 sifModerateTrues(&sif, WCORR_LIMIT);
396 /* Multiply image data with frame durations and 1E5 to reach count scale */
397 if(verbose>3) printf("Convert concentrations into count related scale.\n");
398 for(fi=0; fi<sif.frameNr; fi++) {
399 f=sif.x2[fi]-sif.x1[fi]; if(f<=1.0e-20) f=1.0;
400 sif.trues[fi]=sif.trues[fi]*f*1.0E5;
401 }
402 /* Fill more of SIF contents */
403 for(fi=0; fi<sif.frameNr; fi++) {
404 sif.prompts[fi]=sif.trues[fi]; sif.randoms[fi]=0.0;}
405 sif.colNr=5;
406 /* Compute the weights */
407 if(verbose>2) printf("compute the SIF weights.\n");
408 sifWeight(&sif, 0.0); sif.colNr++;
409 if(verbose>3) sifPrint(&sif);
410 /* Save SIF data, if required */
411 if(newsiffile[0]) {
412 ret=sifWrite(&sif, newsiffile);
413 if(ret==0 && verbose>0)
414 printf("%s was created based on the applied weights.\n", newsiffile);
415 }
416 /* Copy the weights to tac and img */
417 for(fi=0; fi<tac.frameNr; fi++) tac.w[fi]=img.weight[fi]=sif.weights[fi];
418 tac.isweight=1; img.isWeight=1;
419 /* no need for SIF any more */
420 sifEmpty(&sif);
421 }
422 if(weight_method==1) {
423 if(verbose>0) fprintf(stdout, "setting weights to 1.0 (no weights).\n");
424 for(fi=0; fi<tac.frameNr; fi++) tac.w[fi]=img.weight[fi]=1.0;
425 tac.isweight=0; img.isWeight=0;
426 }
427 if(weight_method==2) {
428 if(verbose>0) fprintf(stdout, "setting weights based on frame lengths.\n");
429 ret=dftWeightByFreq(&tac);
430 if(ret) {
431 fprintf(stderr, "Error: cannot weight based on frame durations.\n");
432 imgEmpty(&img); dftEmpty(&tac); return(6);
433 }
434 for(fi=0; fi<tac.frameNr; fi++) tac.w[fi]/=tac.frameNr;
435 for(fi=0; fi<tac.frameNr; fi++) img.weight[fi]=tac.w[fi];
436 tac.isweight=1; img.isWeight=1;
437 }
438 if(verbose>1) {
439 printf("\nFrame weights:\n");
440 for(fi=0; fi<tac.frameNr; fi++)
441 printf("%g %g %g\n", tac.x1[fi], tac.x2[fi], tac.w[fi]);
442 }
443
444
445 /*
446 * Calculate the basis functions
447 */
448 if(verbose>1) fprintf(stdout, "calculating basis functions\n");
449 dftInit(&bf);
450 ret=bf_srtm(tac.x, tac.voi[0].y, tac.frameNr, bfNr, t3min, t3max, &bf);
451 if(ret) {
452 fprintf(stderr, "Error: cannot calculate basis functions (%d).\n", ret);
453 imgEmpty(&img); dftEmpty(&tac); return(7);
454 }
455
456
457 /*
458 * Allocate result images
459 */
460 if(verbose>1) fprintf(stdout, "allocating memory for parametric images\n");
461 if(verbose>2) {
462 printf("dimz := %d\n", img.dimz);
463 printf("dimy := %d\n", img.dimy);
464 printf("dimx := %d\n", img.dimx);
465 }
466 imgInit(&bpimg); imgInit(&r1img); imgInit(&k2img);
467 imgInit(&wssimg); imgInit(&errimg);
468 ret=imgAllocateWithHeader(&bpimg, img.dimz, img.dimy, img.dimx, 1, &img);
469 if(ret==0 && k2file[0])
470 ret=imgAllocateWithHeader(&k2img, img.dimz, img.dimy, img.dimx, 1, &img);
471 if(ret==0 && r1file[0])
472 ret=imgAllocateWithHeader(&r1img, img.dimz, img.dimy, img.dimx, 1, &img);
473 if(ret==0 && wssfile[0])
474 ret=imgAllocateWithHeader(&wssimg, img.dimz, img.dimy, img.dimx, 1, &img);
475 if(ret==0 && errfile[0])
476 ret=imgAllocateWithHeader(&errimg, img.dimz, img.dimy, img.dimx, 1, &img);
477 if(ret) {
478 fprintf(stderr, "Error: out of memory.\n");
479 imgEmpty(&img); dftEmpty(&tac); dftEmpty(&bf);
480 imgEmpty(&bpimg); imgEmpty(&r1img); imgEmpty(&k2img);
481 imgEmpty(&wssimg); imgEmpty(&errimg);
482 return(6);
483 }
484 /* Set the rest of image header */
485 bpimg.start[0]=0.0; bpimg.end[0]=fittime;
486 bpimg.unit=IMGUNIT_UNITLESS;
487 if(k2file[0]) k2img.unit=IMGUNIT_PER_MIN;
488 if(r1file[0]) r1img.unit=IMGUNIT_UNITLESS;
489 if(wssfile[0]) wssimg.unit=IMGUNIT_UNITLESS;
490 if(errfile[0]) errimg.unit=IMGUNIT_UNITLESS;
491
492
493 /*
494 * Allocate memory for QR
495 */
496 if(verbose>1) fprintf(stdout, "allocating memory for QR\n");
497 N=2; M=fitdimt;
498
499 chain=(double*)malloc((M+1)*N*bf.voiNr * sizeof(double));
500 mem=(double**)malloc(bf.voiNr * sizeof(double*));
501 A=(double**)malloc(M * sizeof(double*));
502 B=(double*)malloc(M*sizeof(double));
503 residual=(double*)malloc(M*sizeof(double));
504 qrweight=(double*)malloc(M*sizeof(double));
505 wwschain=(double*)malloc((M*N+2*M)*sizeof(double));
506 wws=(double**)malloc(M * sizeof(double*));
507 if(chain==NULL || B==NULL || A==NULL || residual==NULL
508 || qrweight==NULL || wwschain==NULL || wws==NULL)
509 {
510 fprintf(stderr, "Error: out of memory.\n");
511 imgEmpty(&img); dftEmpty(&tac); dftEmpty(&bf);
512 imgEmpty(&bpimg); imgEmpty(&r1img); imgEmpty(&k2img);
513 imgEmpty(&wssimg); imgEmpty(&errimg);
514 return(8);
515 }
516 for(bi=0; bi<bf.voiNr; bi++) mem[bi]=chain+bi*(M+1)*N;
517 for(m=0; m<M; m++) wws[m]=wwschain+m*N;
518 ws=wwschain+M*N;
519
520 /* Compute QR weights beforehand for faster execution */
521 for(m=0; m<M; m++) {
522 if(tac.w[m]<=1.0e-20) qrweight[m]=0.0;
523 else qrweight[m]=sqrt(tac.w[m]);
524 }
525
526 /* Make A matrix and QR decomposition for it for all pixels
527 beforehand for faster execution */
528 if(verbose>1) fprintf(stdout, "calculating QR decomposition\n");
529 for(bi=0; bi<bf.voiNr; bi++) {
530
531 /* Define memory site for coefficient matrix and vector tau */
532 for(m=0; m<M; m++) A[m]=mem[bi]+m*N;
533 tau=mem[bi]+M*N;
534
535 /* Initiate matrix (A = mem[bi]) */
536 for(m=0; m<M; m++) {
537 A[m][0]=tac.voi[0].y[m];
538 A[m][1]=bf.voi[bi].y[m];
539 }
540
541 /* Apply data weights */
542 for(m=0; m<M; m++) for(n=0; n<N; n++) A[m][n]*=qrweight[m];
543
544 /* Compute QR decomposition of the coefficient matrix */
545 ret=qr_decomp(A, M, N, tau, wws, ws);
546
547 if(ret>0) { /* Decomposition failed */
548 free(chain); free(B); free(residual);
549 free(A); free(wwschain); free(wws); free(qrweight);
550 free(mem); dftEmpty(&tac); dftEmpty(&bf); imgEmpty(&img);
551 imgEmpty(&bpimg); imgEmpty(&k2img); imgEmpty(&r1img);
552 imgEmpty(&wssimg); imgEmpty(&errimg);
553 return(9);
554 }
555 } /* next BF */
556
557 /*
558 * Compute pixel-by-pixel
559 */
560 if(verbose>0) fprintf(stdout, "computing QR pixel-by-pixel\n");
561 thresholded_nr=0; ct=tac.voi[1].y; cti=tac.voi[1].y2; nosolution_nr=0;
562 /* Allocate memory for BF counters on how often each BF is
563 found to provide the optimal fit */
564 bf_opt_nr=(int*)malloc(bfNr*sizeof(int));
565 for(bi=0; bi<bf.voiNr; bi++) bf_opt_nr[bi]=0.0;
566 fitStart=clock();
567 for(pi=0; pi<img.dimz; pi++) {
568 if(verbose>2) printf("computing plane %d\n", img.planeNumber[pi]);
569 else if(img.dimz>1 && verbose>0) {fprintf(stdout, "."); fflush(stdout);}
570 for(yi=0; yi<img.dimy; yi++) {
571 if(verbose>5 && yi==4*img.dimy/10) printf(" computing row %d\n", yi+1);
572 for(xi=0; xi<img.dimx; xi++) {
573 if(verbose>5 && yi==4*img.dimy/10 && xi==4*img.dimx/10)
574 printf(" computing column %d\n", xi+1);
575
576 /* if AUC at the end is less than threshold value, then set values to 0 */
577 /* Calculate pixel integral */
578 for(m=0; m<tac.frameNr; m++) {ct[m]=img.m[pi][yi][xi][m];}
579 ret=petintegral(tac.x1, tac.x2, ct, tac.frameNr, cti, NULL);
580 if(verbose>6 && yi==4*img.dimy/10 && xi==4*img.dimx/10)
581 printf("Pixel (%d,%d,%d), int= %f, threshold= %g\n",
582 pi, yi, xi, cti[M-1], threshold);
583 if(cti[M-1]<threshold) {
584 bpimg.m[pi][yi][xi][0]=0.0;
585 if(k2file[0]) k2img.m[pi][yi][xi][0]=0.0;
586 if(r1file[0]) r1img.m[pi][yi][xi][0]=0.0;
587 if(wssfile[0]) wssimg.m[pi][yi][xi][0]=0.0;
588 if(errfile[0]) errimg.m[pi][yi][xi][0]=0.0;
589 thresholded_nr++;
590 continue;
591 }
592 /* Go through all basis functions */
593 bi_min=-1; rnorm_min=+1.0E80; p1=p2=p3=0.0;
594 for(bi=0; bi<bf.voiNr; bi++) {
595
596 /* Define memory site for preset coefficient matrix and vector tau */
597 for(m=0; m<M; m++) {A[m]=mem[bi]+ m*N;}
598 tau=mem[bi]+M*N;
599
600 /* Get data vector */
601 for(m=0; m<M; m++) {
602 B[m]=img.m[pi][yi][xi][m];
603 /* Apply data weights */
604 B[m]*=qrweight[m];
605 }
606
607 /* Compute solution */
608 ret=qr_solve(A, M, N, tau, B, X, residual, &RNORM, wws, ws);
609 if(ret>0) { /* no solution is possible */
610 for(n=0; n<N; n++) X[n]=0.0;
611 RNORM=1.0E80;
612 }
613
614 /* Check if this was best fit for now */
615 if(RNORM<rnorm_min && bf.voi[bi].size!=lambda) {
616 rnorm_min=RNORM; bi_min=bi;
617 p1=X[0]; p2=X[1]; p3=bf.voi[bi_min].size;
618 }
619 } /* next basis function */
620 if(bi_min<0 || rnorm_min>=1.0E50) {
621 bpimg.m[pi][yi][xi][0]=0.0;
622 if(k2file[0]) k2img.m[pi][yi][xi][0]=0.0;
623 if(r1file[0]) r1img.m[pi][yi][xi][0]=0.0;
624 if(wssfile[0]) wssimg.m[pi][yi][xi][0]=0.0;
625 if(errfile[0]) errimg.m[pi][yi][xi][0]=0.0;
626 nosolution_nr++;
627 continue;
628 } else bf_opt_nr[bi_min]+=1;
629
630 /* Solve k2 and BP */
631 k2=p1*(p3-lambda)+p2; BP=k2/(p3-lambda) - 1.0;
632 if(verbose>6 && yi==4*img.dimy/10 && xi==4*img.dimx/10) {
633 printf("Pixel (%d,%d,%d), p1=%g p2=%g p3=%g\n",
634 pi, yi, xi, p1, p2, p3);
635 if(verbose>10) dftPrint(&tac);
636 }
637
638 /* Calculate WSS */
639 for(m=0, wss=0.0; m<M; m++) {
640 f=p1*tac.voi[0].y[m] + p2*bf.voi[bi_min].y[m];
641 f-=img.m[pi][yi][xi][m]; wss+=tac.w[m]*f*f;
642 }
643 /* Put results to output images */
644 bpimg.m[pi][yi][xi][0]=BP;
645 if(bp_plus_one!=0) bpimg.m[pi][yi][xi][0]+=1.0;
646 if(k2file[0]) k2img.m[pi][yi][xi][0]=k2;
647 if(r1file[0]) r1img.m[pi][yi][xi][0]=p1;
648 if(wssfile[0]) wssimg.m[pi][yi][xi][0]=wss;
649 if(errfile[0]) {
650 if(bi_min==0) ret=1; else if(bi_min==bf.voiNr-1) ret=2; else ret=0;
651 errimg.m[pi][yi][xi][0]=(float)ret;
652 }
653 } /* next column */
654 } /* next row */
655 } /* next plane */
656 fitFinish=clock();
657 if(verbose>0) fprintf(stdout, "done.\n");
658 if(verbose>1 || thresholded_nr>0)
659 fprintf(stdout, "%d pixels were not fitted due to threshold.\n",
660 thresholded_nr);
661 if(verbose>1 || nosolution_nr>0)
662 fprintf(stdout, "no QR solution for %d pixels.\n", nosolution_nr);
663
664 /* No need for dynamic image or ref tac anymore */
665 imgEmpty(&img); dftEmpty(&tac);
666 /* Free memory of QR */
667 free(chain); free(B); free(residual); free(A); free(wwschain);
668 free(wws); free(qrweight); free(mem);
669
670 /*
671 * Save basis functions if required;
672 * this is done not before, so that also the number of optimal fits
673 * achieved with each BF can be saved as the "size".
674 */
675 if(bffile[0]) {
676 for(bi=0; bi<bf.voiNr; bi++)
677 sprintf(bf.voi[bi].place, "%d", bf_opt_nr[bi]);
678 if(dftWrite(&bf, bffile)) {
679 fprintf(stderr, "Error in writing %s: %s\n", bffile, dfterrmsg);
680 imgEmpty(&bpimg); imgEmpty(&k2img); imgEmpty(&r1img);
681 imgEmpty(&wssimg); imgEmpty(&errimg);
682 free(bf_opt_nr); return(11);
683 }
684 if(verbose>0) fprintf(stdout, "basis functions were written in %s\n", bffile);
685 }
686
687 /* No need for basis functions anymore */
688 dftEmpty(&bf); free(bf_opt_nr);
689
690 /*
691 * Set negative BP values to zero, if required
692 */
693 if(nonnegativity_constraint!=0) {
694 if(verbose>1) printf("setting negative BP values to zero\n");
695 imgCutoff(&bpimg, 0.0, 1);
696 }
697
698
699 /*
700 * Save parametric image(s)
701 */
702 ret=imgWrite(bpfile, &bpimg);
703 if(ret) fprintf(stderr, "Error: %s\n", bpimg.statmsg);
704 else if(verbose>0) {
705 if(bp_plus_one==0) fprintf(stdout, "BP image %s saved.\n", bpfile);
706 else fprintf(stdout, "DVR image %s saved.\n", bpfile);
707 }
708 if(ret==0 && r1file[0]) {
709 ret=imgWrite(r1file, &r1img);
710 if(ret) fprintf(stderr, "Error: %s\n", r1img.statmsg);
711 else if(verbose>0) fprintf(stdout, "R1 image %s saved.\n", r1file);
712 }
713 if(ret==0 && k2file[0]) {
714 ret=imgWrite(k2file, &k2img);
715 if(ret) fprintf(stderr, "Error: %s\n", k2img.statmsg);
716 else if(verbose>0) fprintf(stdout, "k2 image %s saved.\n", k2file);
717 }
718 if(ret==0 && wssfile[0]) {
719 ret=imgWrite(wssfile, &wssimg);
720 if(ret) fprintf(stderr, "Error: %s\n", wssimg.statmsg);
721 else if(verbose>0) fprintf(stdout, "WSS image %s saved.\n", wssfile);
722 }
723 if(ret==0 && errfile[0]) {
724 ret=imgWrite(errfile, &errimg);
725 if(ret) fprintf(stderr, "Error: %s\n", errimg.statmsg);
726 else if(verbose>0) fprintf(stdout, "Error image %s saved.\n", errfile);
727 }
728
729 imgEmpty(&bpimg); imgEmpty(&r1img); imgEmpty(&k2img);
730 imgEmpty(&wssimg); imgEmpty(&errimg);
731
732 /* How long did the fitting take */
733 if(verbose>1) fprintf(stdout, "parameter estimation time := %.1f [s]\n",
734 (double)(fitFinish-fitStart) / CLOCKS_PER_SEC );
735
736 return(0);
737}
738/*****************************************************************************/
739
740/*****************************************************************************/
int bf_srtm(double *t, double *cr, int n, int bfNr, double t3min, double t3max, DFT *bf)
Definition bf_model.c:16
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
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 dftAddmem(DFT *dft, int voiNr)
Definition dft.c:107
void dftEmpty(DFT *data)
Definition dft.c:20
int dftDecayCorrection(DFT *dft, double hl, int mode, int y, int y2, int y3, char *status, int verbose)
Definition dftdecayc.c:16
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
double hl2lambda(double halflife)
Definition halflife.c:84
int IMG_TEST
Definition img.c:6
unsigned long long imgNaNs(IMG *img, int fix)
Definition img.c:658
int imgAllocateWithHeader(IMG *image, int planes, int rows, int columns, int frames, IMG *image_from)
Definition img.c:279
void imgEmpty(IMG *image)
Definition img.c:121
void imgInit(IMG *image)
Definition img.c:60
int imgDecayCorrection(IMG *image, int mode)
Definition imgdecayc.c:16
int imgAverageTAC(IMG *img, float *tac)
Definition imgeval.c:15
int imgWrite(const char *fname, IMG *img)
Definition imgfile.c:136
int imgReadModelingData(char *petfile, char *siffile, char *inputfile1, char *inputfile2, char *inputfile3, double *fitdur, int *fitframeNr, IMG *img, DFT *inp, DFT *iinp, int verifypeak, FILE *loginfo, int verbose, char *status)
Definition imginput.c:24
void imgCutoff(IMG *image, float cutoff, int mode)
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
Header file for libtpccurveio.
#define DFT_DECAY_UNKNOWN
#define DFT_DECAY_CORRECTED
Header file for libtpcimgio.
void sifModerateTrues(SIF *sif, double limit)
Definition weight.c:131
int sifWrite(SIF *data, char *filename)
Definition sifio.c:145
#define IMG_DC_UNKNOWN
#define IMG_DC_CORRECTED
void sifInit(SIF *data)
Definition sif.c:17
int SIF_TEST
Definition sif.c:6
void sifPrint(SIF *data)
Definition sifio.c:234
int sifExistentCounts(SIF *sif)
Definition weight.c:207
void sifWeight(SIF *data, double halflife)
Calculate weights for frames in SIF data based on true counts. Weights are normalized to have an aver...
Definition weight.c:28
int sifSetmem(SIF *data, int frameNr)
Definition sif.c:56
void sifEmpty(SIF *data)
Definition sif.c:33
int sifRead(char *filename, SIF *data)
Definition sifio.c:21
char siferrmsg[128]
Definition sif.c:7
Header file for libtpcimgp.
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
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 qr_solve(double **QR, int M, int N, double *tau, double *b, double *x, double *residual, double *resNorm, double **cchain, double *chain)
Definition qr.c:492
int qr_decomp(double **a, int M, int N, double *tau, double **cchain, double *chain)
Definition qr.c:427
Header file for libtpcmodext.
int dftWeightByFreq(DFT *dft)
char decayCorrected
Voi * voi
double * w
double * x1
int voiNr
double * x2
int frameNr
int isweight
double * x
unsigned short int dimx
float **** m
char decayCorrection
char unit
time_t scanStart
int * planeNumber
float * weight
float * start
unsigned short int dimz
unsigned short int dimy
float * end
const char * statmsg
float isotopeHalflife
char isWeight
double * x1
double * prompts
int frameNr
double * x2
int version
time_t scantime
char isotope_name[8]
double * weights
int colNr
double * randoms
double * trues
double size
double * y2
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
char place[MAX_REGIONSUBNAME_LEN+1]