TPCCLIB
Loading...
Searching...
No Matches
bfmsrtm.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 <string.h>
14#include <math.h>
15/*****************************************************************************/
16#include "tpcextensions.h"
17#include "tpcift.h"
18#include "tpctac.h"
19#include "tpcpar.h"
20#include "tpcbfm.h"
21#include "tpctacmod.h"
22#include "tpclinopt.h"
23/*****************************************************************************/
24
25/*****************************************************************************/
26static char *info[] = {
27 "Estimate the binding potential (BPnd) from simplified reference tissue",
28 "model (SRTM) (Lammertsma & Hume, 1996). The model is solved using",
29 "the basis function method (BFM; Gunn et al., 1997).",
30 " ",
31 "Radioactivity concentration in region(s)-of-interest is given in TTAC file;",
32 "data must be corrected for physical decay.",
33 "Radioactivity concentration in reference region (RTAC) is given in separate",
34 "file, or as name or number of the reference region inside the TTAC file.",
35 "Sample times must be in minutes in all data files, unless specified inside",
36 "the files. TTAC file should include weights.",
37 " ",
38 "Usage: @P [options] TTAC RTAC results",
39 " ",
40 "Options:",
41 " -i=<isotope>",
42 " To apply BFM to non-decay-corrected data, as proposed in the original",
43 " method publication, enter the isotope with this option, using codes",
44 " C-11, F-18, Ga-68, Cu-64, ...",
45 " -t3min=<value (1/min)>",
46 " Set minimum value for theta3; it must be >= k2min/(1+BPmax)+lambda;",
47 " it has to be > lambda. Default is lambda+0.001 min-1.",
48 " Lambda for F-18 is 0.0063 and for C-11 0.034;",
49 " If isotope is not given, then lambda=0.",
50 " -t3max=<value (1/min)>",
51 " Set maximum value for theta3; it must be <= k2max+lambda.",
52 " Default is 0.60 min-1.",
53 " -nr=<value>",
54 " Set number of basis functions; default is 5000.",
55 " -end=<Fit end time (min)>",
56 " Use data from 0 to end time; by default, model is fitted to all frames.",
57 " -DVR",
58 " Instead of BPnd, program saves the DVR (=BPnd+1) values.",
59 " -w1",
60 " All weights are set to 1.0 (no weighting); by default, weights in",
61 " data file are used, if available.",
62 " -wf",
63 " Weight by sampling interval.",
64 " -svg=<Filename>",
65 " Plots of original and fitted TTACs are written in specified file in",
66 " SVG format.",
67 " -fit=<Filename>",
68 " Fitted regional TTACs are written in specified file.",
69 " -bf=<filename>",
70 " Basis functions are written in specified DFT file.",
71 " -stdoptions", // List standard options like --help, -v, etc
72 " ",
73 "Example:",
74 " @P a4567.tac cer C-11 a4567bp.res",
75 " ",
76 "References:",
77 "1. Lammertsma AA, Hume SP. Simplified reference tissue model for PET",
78 " receptor studies. NeuroImage 1996;4:153-158.",
79 "2. Gunn RN, Lammertsma AA, Hume SP, Cunningham VJ. Parametric imaging of",
80 " ligand-receptor binding in PET using a simplified reference region",
81 " model. NeuroImage 1997;6:279-287.",
82 " ",
83 "See also: tacweigh, tacdecay, logan, imgbfbp, fit_srtm, lhsrtm, fitk2",
84 " ",
85 "Keywords: TAC, modelling, binding potential, SRTM, reference input",
86 0};
87/*****************************************************************************/
88
89/*****************************************************************************/
90/* Turn on the globbing of the command line, since it is disabled by default in
91 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
92 In Unix&Linux wildcard command line processing is enabled by default. */
93/*
94#undef _CRT_glob
95#define _CRT_glob -1
96*/
97int _dowildcard = -1;
98/*****************************************************************************/
99
100/*****************************************************************************/
104int main(int argc, char **argv)
105{
106 int ai, help=0, version=0, verbose=1;
107 char rtacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], resfile[FILENAME_MAX],
108 fitfile[FILENAME_MAX], svgfile[FILENAME_MAX], bffile[FILENAME_MAX];
109 int bfNr=5000;
110 int bp_plus_one=0; // 0=BPnd, 1=DVR
111 double t3min=nan(""), t3max=nan(""); // 1/min
113 double fitdur=nan("");
114 int weights=0; // 0=default, 1=no weighting, 2=frequency
115 char *cptr;
116 int ret;
117
118
119
120 /*
121 * Get arguments
122 */
123 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
124 rtacfile[0]=ttacfile[0]=resfile[0]=fitfile[0]=svgfile[0]=bffile[0]=(char)0;
125 /* Options */
126 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
127 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
128 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
129 if(strcasecmp(cptr, "DVR")==0) {
130 bp_plus_one=1; continue;
131 } else if(strncasecmp(cptr, "BPND", 2)==0) {
132 bp_plus_one=0; continue;
133 } else if(strncasecmp(cptr, "SVG=", 4)==0) {
134 strlcpy(svgfile, cptr+4, FILENAME_MAX); if(strlen(svgfile)>0) continue;
135 } else if(strncasecmp(cptr, "FIT=", 4)==0) {
136 strlcpy(fitfile, cptr+4, FILENAME_MAX); if(strlen(fitfile)>0) continue;
137 } else if(strncasecmp(cptr, "NR=", 3)==0) {
138 if(atoiCheck(cptr+3, &bfNr)==0 && bfNr>5) continue;
139 } else if(strncasecmp(cptr, "BF=", 3)==0) {
140 strlcpy(bffile, cptr+3, FILENAME_MAX); if(strlen(bffile)>0) continue;
141 } else if(strncasecmp(cptr, "min=", 4)==0) {
142 if(atofCheck(cptr+4, &t3min)==0 && t3min>=0.0) continue;
143 } else if(strncasecmp(cptr, "max=", 4)==0) {
144 if(atofCheck(cptr+4, &t3max)==0 && t3max>=0.0) continue;
145 } else if(strncasecmp(cptr, "t3min=", 6)==0) {
146 if(atofCheck(cptr+6, &t3min)==0 && t3min>=0.0) continue;
147 } else if(strncasecmp(cptr, "t3max=", 6)==0) {
148 if(atofCheck(cptr+6, &t3max)==0 && t3max>=0.0) continue;
149 } else if(strncasecmp(cptr, "end=", 4)==0) {
150 if(atofCheck(cptr+4, &fitdur)==0) {
151 if(fitdur<=0.0) fitdur=1.0E+99;
152 continue;
153 } else {
154 fprintf(stderr, "Error: invalid fit time '%s'.\n", argv[ai]);
155 return(1);
156 }
157 } else if(strcasecmp(cptr, "W1")==0) {
158 weights=1; continue;
159 } else if(strcasecmp(cptr, "WF")==0) {
160 weights=2; continue;
161 } else if(strncasecmp(cptr, "I=", 2)==0) {
162 isotope=isotopeIdentify(cptr+2);
164 fprintf(stderr, "Error: invalid isotope code '%s'\n", cptr+2);
165 return(1);
166 }
167 continue;
168 }
169 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
170 return(1);
171 } else break;
172
173 TPCSTATUS status; statusInit(&status);
174 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
175 status.verbose=verbose-3;
176
177 /* Print help or version? */
178 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
179 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
180 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
181
182 /* Process other arguments, starting from the first non-option */
183 if(ai<argc) strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
184 if(ai<argc) strlcpy(rtacfile, argv[ai++], FILENAME_MAX);
185 if(ai<argc) strlcpy(resfile, argv[ai++], FILENAME_MAX);
186 if(ai<argc) {
187 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
188 return(1);
189 }
190 /* Did we get all the information that we need? */
191 if(!resfile[0]) {
192 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
193 return(1);
194 }
195 if(isnan(fitdur)) fitdur=1.0E+99;
196 /* Set or check theta3 limits */
197 double lambda=0.0;
200 if(verbose>2) printf("lambda := %g\n", lambda);
201 if(isnan(t3min)) t3min=lambda+0.001;
202 if(isnan(t3max)) t3max=0.60;
203 if(t3min>=t3max || t3min<=lambda) {
204 fprintf(stderr, "Error: invalid theta3 bounds (%g - %g).\n", t3min, t3max);
205 return(1);
206 }
207
208 /* In verbose mode print arguments and options */
209 if(verbose>1) {
210 printf("ttacfile := %s\n", ttacfile);
211 printf("rtacfile := %s\n", rtacfile);
212 printf("resfile := %s\n", resfile);
213 printf("fitfile := %s\n", fitfile);
214 printf("svgfile := %s\n", svgfile);
215 printf("bffile := %s\n", bffile);
216 printf("bfNr := %d\n", bfNr);
217 printf("bp_plus_one := %d\n", bp_plus_one);
218 /*if(!isnan(t3min))*/ printf("t3min := %g min-1\n", t3min);
219 /*if(!isnan(t3max))*/ printf("t3max := %g min-1\n", t3max);
221 printf("isotope := %s\n", isotopeName(isotope));
222 printf("required_fittime := %g min\n", fitdur);
223 printf("weights := %d\n", weights);
224 }
225
226
227 /*
228 * Read TAC files
229 */
230 TAC ttac, rtac; tacInit(&ttac); tacInit(&rtac);
231
232 /* Read tissue TAC file */
233 if(verbose>1) printf("reading %s\n", ttacfile);
234 ret=tacRead(&ttac, ttacfile, &status);
235 if(ret!=TPCERROR_OK) {
236 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
237 tacFree(&ttac); return(2);
238 }
239 if(verbose>2) {
240 printf("fileformat := %s\n", tacFormattxt(ttac.format));
241 printf("tacNr := %d\n", ttac.tacNr);
242 printf("sampleNr := %d\n", ttac.sampleNr);
243 printf("xunit := %s\n", unitName(ttac.tunit));
244 printf("yunit := %s\n", unitName(ttac.cunit));
245 }
246 /* Set isotope into TTAC header */
248
249 /* Read reference tissue TAC file */
250 if(verbose>1) printf("reading %s\n", rtacfile);
251 int refindex;
252 ret=tacReadReference(&ttac, rtacfile, &rtac, &refindex, &status);
253 if(ret==0) {
254 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
255 tacFree(&ttac); tacFree(&rtac); return(2);
256 }
257 if(rtac.tacNr>1) {
258 fprintf(stderr, "Warning: several reference regions found: %s selected.\n",
259 rtac.c[refindex].name);
260 } else if(verbose>1) {
261 printf("reference_region := %s\n", rtac.c[refindex].name);
262 }
263 if(verbose>2) {
264 printf("ref_fileformat := %s\n", tacFormattxt(rtac.format));
265 printf("ref_tacNr := %d\n", rtac.tacNr);
266 printf("ref_sampleNr := %d\n", rtac.sampleNr);
267 printf("ref_xunit := %s\n", unitName(rtac.tunit));
268 printf("ref_yunit := %s\n", unitName(rtac.cunit));
269 }
270
271 /* Try to fix missing values, if any */
272 if(tacFixNaNs(&ttac) || tacFixNaNs(&rtac)) {
273 fprintf(stderr, "Error: missing sample(s) in data.\n");
274 tacFree(&ttac); tacFree(&rtac); return(2);
275 }
276
277 /* Convert sample times to minutes */
278 if(tacXUnitConvert(&ttac, UNIT_MIN, &status) ||
279 tacXUnitConvert(&rtac, UNIT_MIN, &status))
280 {
281 fprintf(stderr, "Warning: %s\n", errorMsg(status.error));
282 // Do not stop in error, assume that user has set units correctly
283 }
284
285 /* Remove small frame overlaps and gaps */
286 if(tacCorrectFrameOverlap(&ttac, &status) || tacCorrectFrameOverlap(&rtac, &status)) {
287 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
288 tacFree(&ttac); tacFree(&rtac); return(2);
289 }
290
291 /* Add data weights, if requested */
292 if(weights==1) {
294 for(int i=0; i<ttac.sampleNr; i++) ttac.w[i]=1.0;
295 } else if(weights==2) {
296 if(tacWByFreq(&ttac, ISOTOPE_UNKNOWN, &status)!=TPCERROR_OK) {
297 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
298 tacFree(&ttac); tacFree(&rtac); return(2);
299 }
300 } else if(!tacIsWeighted(&ttac)) {
301 fprintf(stderr, "Warning: data is not weighted.\n");
302 }
303
304 /* Set fit duration */
305 double starttime=0.0;
306 double endtime=fitdur;
307 int fitSampleNr;
308 fitSampleNr=tacFittime(&ttac, &starttime, &endtime, NULL, NULL, &status);
309 if(fitSampleNr<0) {
310 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
311 tacFree(&ttac); tacFree(&rtac); return(2);
312 } else if(fitSampleNr<4) {
313 fprintf(stderr, "Error: too few data points for a decent fit.\n");
314 tacFree(&ttac); tacFree(&rtac); return(2);
315 }
316 if(verbose>1) {
317 printf("starttime := %g\n", starttime);
318 printf("endtime := %g\n", endtime);
319 //printf("first := %d\n", first);
320 //printf("last := %d\n", last);
321 printf("fitSampleNr := %d\n", fitSampleNr);
322 }
323 fitdur=endtime;
324
325
326 /*
327 * Remove decay correction from TTACs and RTAC(s), if requested
328 */
330 if(verbose>1) printf("removing decay correction.\n");
331 ret=tacDecayCorrection(&ttac, isotope, 0, &status);
332 if(ret==TPCERROR_OK) ret=tacDecayCorrection(&rtac, isotope, 0, &status);
333 if(ret!=TPCERROR_OK) {
334 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
335 tacFree(&ttac); tacFree(&rtac); return(2);
336 }
337 }
338
339 /*
340 * Calculate the basis functions
341 */
342 if(verbose>1) printf("integrate reference region TAC for BF calculation\n");
343 TAC irtac; tacInit(&irtac);
344 ret=tacInterpolate(&rtac, &ttac, NULL, &irtac, NULL, &status);
345 if(ret!=TPCERROR_OK) {
346 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
347 tacFree(&ttac); tacFree(&rtac); tacFree(&irtac); return(3);
348 }
349
350 if(verbose>1) printf("calculating basis functions\n");
351 TAC bf; tacInit(&bf);
352 ret=bfmSRTM(ttac.x, irtac.c[refindex].y, fitSampleNr, bfNr,
353 t3min, t3max, &bf, &status);
354 if(ret!=TPCERROR_OK) {
355 if(verbose>1)
356 fprintf(stderr, "Error: cannot calculate basis functions.\n");
357 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
358 tacFree(&ttac); tacFree(&rtac); tacFree(&irtac); return(3);
359 }
360 tacFree(&irtac); // not needed anymore
361 bf.tunit=ttac.tunit;
362
363 /* Save basis functions if required */
364 if(bffile[0]) {
365 if(verbose>1) printf("writing %s\n", bffile);
366 FILE *fp; fp=fopen(bffile, "w");
367 if(fp==NULL) {
368 fprintf(stderr, "Error: cannot open file for writing (%s)\n", bffile);
369 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
370 return(3);
371 }
372 ret=tacWrite(&bf, fp, TAC_FORMAT_PMOD, 1, &status);
373 fclose(fp);
374 if(ret!=TPCERROR_OK) {
375 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
376 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
377 return(3);
378 }
379 if(verbose>0) printf("basis functions saved in %s.\n", bffile);
380 }
381
382
383
384 /*
385 * Prepare the room for results
386 */
387 if(verbose>1) printf("initializing result data\n");
388 PAR par; parInit(&par);
389 if(verbose<2) ret=parAllocateWithTAC(&par, &ttac, 3, &status);
390 else ret=parAllocateWithTAC(&par, &ttac, 5, &status);
391 if(ret!=TPCERROR_OK) {
392 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
393 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
394 return(4);
395 }
396 /* Copy titles & filenames */
397 {
398 int i;
399 char buf[256];
400 time_t t=time(NULL);
401 /* set program name */
402 tpcProgramName(argv[0], 1, 1, buf, 256);
403 iftPut(&par.h, "program", buf, 0, NULL);
404 /* set file names */
405 iftPut(&par.h, "datafile", ttacfile, 0, NULL);
406 iftPut(&par.h, "refname", rtac.c[refindex].name, 0, NULL);
407 /* set isotope, if given */
409 iftPut(&par.h, "isotope", isotopeName(isotope), 0, NULL);
410 /* Fit method */
411 iftPut(&par.h, "fitmethod", "BFM", 0, NULL);
412 /* Set current time to results */
413 iftPut(&par.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
414 /* Set fit times for each TAC */
415 for(i=0; i<par.tacNr; i++) {
416 par.r[i].dataNr=fitSampleNr;
417 par.r[i].start=starttime;
418 par.r[i].end=fitdur;
419 /* and nr of fitted parameters */
420 par.r[i].fitNr=3;
421 }
422 /* Set the parameter names and units */
423 i=0; strcpy(par.n[i].name, "R1"); par.n[i].unit=UNIT_UNITLESS;
424 i++; strcpy(par.n[i].name, "k2"); par.n[i].unit=UNIT_PER_MIN;
425 i++; par.n[i].unit=UNIT_UNITLESS;
426 if(bp_plus_one==0) strcpy(par.n[i].name, "BPnd");
427 else strcpy(par.n[i].name, "DVR");
428 if(par.parNr==5) {
429 i++; strcpy(par.n[i].name, "theta2"); par.n[i].unit=UNIT_UNITLESS;
430 i++; strcpy(par.n[i].name, "theta3"); par.n[i].unit=UNIT_UNITLESS;
431 }
432 }
433
434
435
436 /*
437 * Prepare the room for fitted TTACs, if requested
438 */
439 TAC ftac; tacInit(&ftac);
440 if(fitfile[0] || svgfile[0]) {
441 if(verbose>1) printf("allocating space for fitted TTACs\n");
442 ret=tacDuplicate(&ttac, &ftac);
443 if(ret!=TPCERROR_OK) {
444 fprintf(stderr, "Error: cannot allocate space for fitted TACs.\n");
445 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
446 parFree(&par);
447 return(4);
448 }
449 ftac.sampleNr=fitSampleNr;
450 }
451
452
453 /*
454 * Allocate memory for QR
455 */
456 if(verbose>1) printf("allocating memory for QR\n");
457 int colNr, rowNr;
458 colNr=2;
459 rowNr=fitSampleNr;
460 if(verbose>2) {
461 printf("QR_colNr := %d\n", colNr);
462 printf("QR_rowNr := %d\n", rowNr);
463 }
464 double *buf, **mat, *rhs, *sol, r2;
465 buf=(double*)calloc(colNr*rowNr+rowNr+colNr, sizeof(double));
466 mat=(double**)calloc(rowNr, sizeof(double*));
467 if(buf==NULL || mat==NULL) {
468 fprintf(stderr, "Error: cannot allocate memory for QR\n");
469 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
470 tacFree(&ftac); parFree(&par);
471 return(6);
472 }
473 for(int i=0; i<rowNr; i++) mat[i]=buf+(i*colNr);
474 rhs=buf+(rowNr*colNr); sol=buf+(rowNr*colNr+rowNr);
475
476
477 /*
478 * BF fitting to each regional TAC
479 */
480 if(verbose>1) printf("BFM fitting to TACs.\n");
481 double r2_min;
482 int bi, bi_min;
483 for(int i=0; i<ttac.tacNr; i++) {
484
485 if(verbose>1 && ttac.tacNr>1)
486 printf("Region %d %s\n", i+1, ttac.c[i].name);
487
488 /* Go through all basis functions */
489 bi_min=-1; r2_min=nan("");
490 for(bi=0; bi<bf.tacNr; bi++) {
491
492 if(verbose>5) printf("bi=%d\n", bi);
493
494 /* Initiate matrix */
495 for(int j=0; j<rowNr; j++) {
496 mat[j][0]=rtac.c[refindex].y[j];
497 mat[j][1]=bf.c[bi].y[j];
498 rhs[j]=ttac.c[i].y[j];
499 }
500 /* Apply data weights */
501 if(verbose>5) printf(" weighting\n");
502 /* Preallocate temp memory at some point */
503 if(tacIsWeighted(&ttac)) qrWeight(colNr, rowNr, mat, rhs, ttac.w, NULL);
504
505 /* Compute QR */
506 if(verbose>5) printf(" QR\n");
507 ret=qrLSQ(mat, rhs, sol, rowNr, colNr, &r2);
508 if(ret!=0) {
509 fprintf(stderr, "Error: no QR solution for BFM\n");
510 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
511 tacFree(&ftac); parFree(&par);
512 free(buf); free(mat);
513 return(6);
514 }
515 if(verbose>5) {
516 printf("solution (%d):", bi);
517 for(int j=0; j<colNr; j++) printf(" %g", sol[j]);
518 printf("\nR^2= %g R=%g\n", r2, sqrt(r2));
519 }
520 /* Check if this was best fit for now */
521 if((isnan(r2_min) || r2_min>r2) && bf.c[bi].size!=lambda) {
522 r2_min=r2; bi_min=bi;
523 }
524 } /* next basis function */
525 if(verbose>2)
526 printf("Min basis function nr %d with R2=%g\n", bi_min+1, r2_min);
527
528 /* Compute the best BF again to retrieve the solution */
529 bi=bi_min;
530 /* Initiate matrix */
531 for(int j=0; j<rowNr; j++) {
532 mat[j][0]=rtac.c[refindex].y[j];
533 mat[j][1]=bf.c[bi].y[j];
534 rhs[j]=ttac.c[i].y[j];
535 }
536 /* Apply data weights */
537 if(verbose>5) printf(" weighting\n");
538 /* Preallocate temp memory at some point */
539 if(tacIsWeighted(&ttac)) qrWeight(colNr, rowNr, mat, rhs, ttac.w, NULL);
540 /* Compute QR */
541 if(verbose>5) printf(" QR\n");
542 ret=qrLSQ(mat, rhs, sol, rowNr, colNr, &r2);
543 if(ret!=0) {
544 fprintf(stderr, "Error: no QR solution for BFM\n");
545 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
546 tacFree(&ftac); parFree(&par);
547 free(buf); free(mat);
548 return(6);
549 }
550 par.r[i].wss=r2;
551 if(verbose>5) {
552 printf("best_solution (%d):", bi);
553 for(int j=0; j<colNr; j++) printf(" %g", sol[j]);
554 printf("\nR^2= %g R=%g\n", r2, sqrt(r2));
555 }
556 /* Remove weights */
557 if(tacIsWeighted(&ttac)) qrWeightRm(colNr, rowNr, mat, rhs, ttac.w, NULL);
558 /* Fitted TTAC is in rhs[] */
559 if(fitfile[0] || svgfile[0]) {
560 for(int j=0; j<rowNr; j++) ftac.c[i].y[j]=rhs[j];
561 }
562
563 /* Solve final parameters */
564 double R1, k2, BPnd, DVR, theta2, theta3;
565 R1=sol[0]; theta2=sol[1]; theta3=bf.c[bi_min].size;
566 k2=R1*(theta3-lambda) + theta2;
567 DVR= R1 + theta2/(theta3-lambda); BPnd=DVR-1.0;
568
569 /* Put the final parameters in place */
570 par.r[i].p[0]=R1;
571 par.r[i].p[1]=k2;
572 if(bp_plus_one==0) par.r[i].p[2]=BPnd; else par.r[i].p[2]=DVR;
573 if(par.parNr==5) {
574 par.r[i].p[3]=theta2;
575 par.r[i].p[4]=theta3;
576 }
577
578 } /* next region */
579
580 /* Free the memory allocated for QR */
581 free(buf); free(mat);
582
583
584 /*
585 * Print results on screen
586 */
587 if(verbose>0 && par.tacNr<50)
588 parWrite(&par, stdout, PAR_FORMAT_RES, 0, &status);
589
590 /*
591 * Save results
592 */
593 if(resfile[0]) {
594 if(verbose>1) printf("writing %s\n", resfile);
595 par.format=parFormatFromExtension(resfile);
596 if(verbose>2)
597 printf("result file format := %s\n", parFormattxt(par.format));
599 FILE *fp; fp=fopen(resfile, "w");
600 if(fp==NULL) {
601 fprintf(stderr, "Error: cannot open file for writing (%s)\n", resfile);
602 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
603 tacFree(&ftac); parFree(&par);
604 return(11);
605 }
606 ret=parWrite(&par, fp, PAR_FORMAT_UNKNOWN, 1, &status);
607 fclose(fp);
608 //parFree(&par);
609 if(ret!=TPCERROR_OK) {
610 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
611 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
612 tacFree(&ftac); parFree(&par);
613 return(12);
614 }
615 if(verbose>0) printf("Results saved in %s.\n", resfile);
616 }
617
618
619
620
621 /*
622 * SVG plot of fitted and original data
623 */
624 if(svgfile[0]) {
625
626 if(verbose>1) printf("saving SVG plot\n");
627 int i;
628 char buf[128];
629 sprintf(buf, "SRTM-BFM fit");
630 i=iftFindKey(&ttac.h, "studynr", 0);
631 if(i<0) i=iftFindKey(&ttac.h, "study_number", 0);
632 if(i>=0) {strcat(buf, ": "); strcat(buf, ttac.h.item[i].value);}
633 ret=tacPlotFitSVG(&ttac, &ftac, buf, 0.0, nan(""), 0.0, nan(""),
634 svgfile, &status);
635 if(ret!=TPCERROR_OK) {
636 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
637 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
638 tacFree(&ftac); parFree(&par);
639 return(21);
640 }
641 if(verbose>0) printf("Plots written in %s.\n", svgfile);
642 }
643
644 /*
645 * Save fitted TTACs
646 */
647 if(fitfile[0]) {
648 /*
649 * Return decay correction, if needed
650 */
652 if(verbose>1) printf("decay correction for fitted TTACs.\n");
653 ret=tacDecayCorrection(&ftac, isotope, 1, &status);
654 if(ret==TPCERROR_OK) ret=tacDecayCorrection(&rtac, isotope, 0, &status);
655 if(ret!=TPCERROR_OK) {
656 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
657 tacFree(&ttac); tacFree(&rtac); return(31);
658 }
659 }
660 if(verbose>1) printf("writing %s\n", fitfile);
661 FILE *fp; fp=fopen(fitfile, "w");
662 if(fp==NULL) {
663 fprintf(stderr, "Error: cannot open file for writing (%s)\n", fitfile);
664 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
665 tacFree(&ftac); parFree(&par);
666 return(32);
667 }
668 ret=tacWrite(&ftac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
669 fclose(fp);
670 if(ret!=TPCERROR_OK) {
671 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
672 tacFree(&ttac); tacFree(&rtac); tacFree(&bf);
673 tacFree(&ftac); parFree(&par);
674 return(33);
675 }
676 if(verbose>0) printf("fitted TACs saved in %s.\n", fitfile);
677 }
678
679
680 tacFree(&ttac); tacFree(&rtac); tacFree(&bf); tacFree(&ftac);
681 parFree(&par);
682 return(0);
683}
684/*****************************************************************************/
685
686/*****************************************************************************/
int bfmSRTM(double *t, double *cri, const int n, const int bfNr, const double t3min, const double t3max, TAC *bf, TPCSTATUS *status)
Definition bf_srtm.c:26
char * ctime_r_int(const time_t *t, char *buf)
Convert calendar time t into a null-terminated string of the form YYYY-MM-DD hh:mm:ss,...
Definition datetime.c:119
double lambdaFromHalflife(double halflife)
Definition decay.c:47
int atofCheck(const char *s, double *v)
Definition decpoint.c:94
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
Definition ift.c:63
int iftFindKey(IFT *ift, const char *key, int start_index)
Definition iftfind.c:30
int atoiCheck(const char *s, int *v)
Definition intutil.c:25
char * isotopeName(int isotope_code)
Definition isotope.c:101
double isotopeHalflife(int isotope_code)
Definition isotope.c:62
int isotopeIdentify(const char *isotope)
Definition isotope.c:145
int tacInterpolate(TAC *inp, TAC *xinp, TAC *tac, TAC *itac, TAC *iitac, TPCSTATUS *status)
Interpolate and/or integrate TACs from one TAC structure into a new TAC structure,...
Definition litac.c:141
void parFree(PAR *par)
Definition par.c:75
void parInit(PAR *par)
Definition par.c:25
char * parFormattxt(parformat c)
Definition pario.c:59
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
Definition pario.c:148
int parFormatFromExtension(const char *s)
Definition pario.c:102
int parAllocateWithTAC(PAR *par, TAC *tac, int parNr, TPCSTATUS *status)
Allocate PAR based on data in TAC.
Definition partac.c:90
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
Definition proginfo.c:406
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:169
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:339
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:114
int qrWeightRm(int N, int M, double **A, double *b, double *weight, double *ws)
Definition qrlsq.c:796
int qrLSQ(double **mat, double *rhs, double *sol, const unsigned int rows, const unsigned int cols, double *r2)
QR least-squares solving routine.
Definition qrlsq.c:72
int qrWeight(int N, int M, double **A, double *b, double *weight, double *ws)
Definition qrlsq.c:745
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
char * errorMsg(tpcerror e)
Definition statusmsg.c:68
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
char * value
Definition tpcift.h:37
IFT_ITEM * item
Definition tpcift.h:57
Definition tpcpar.h:100
int format
Definition tpcpar.h:102
IFT h
Optional (but often useful) header information.
Definition tpcpar.h:147
int parNr
Definition tpcpar.h:108
int tacNr
Definition tpcpar.h:104
PARR * r
Definition tpcpar.h:114
PARN * n
Definition tpcpar.h:112
int unit
Definition tpcpar.h:86
char name[MAX_PARNAME_LEN+1]
Definition tpcpar.h:82
double wss
Definition tpcpar.h:72
int fitNr
Definition tpcpar.h:58
int dataNr
Definition tpcpar.h:62
double * p
Definition tpcpar.h:64
double start
Definition tpcpar.h:52
double end
Definition tpcpar.h:54
char name[MAX_TACNAME_LEN+1]
Definition tpctac.h:81
double * y
Definition tpctac.h:75
double size
Definition tpctac.h:71
Definition tpctac.h:87
double * x
Definition tpctac.h:97
unit cunit
Definition tpctac.h:105
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
IFT h
Optional (but often useful) header information.
Definition tpctac.h:141
double * w
Definition tpctac.h:111
TACC * c
Definition tpctac.h:117
weights weighting
Definition tpctac.h:115
unit tunit
Definition tpctac.h:109
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
void tacFree(TAC *tac)
Definition tac.c:106
int tacDuplicate(TAC *tac1, TAC *tac2)
Make a duplicate of TAC structure.
Definition tac.c:356
void tacInit(TAC *tac)
Definition tac.c:24
int tacDecayCorrection(TAC *tac, int isotope, int mode, TPCSTATUS *status)
Definition tacdc.c:59
void tacSetIsotope(TAC *tac, int isotope)
Definition tacdc.c:41
int tacPlotFitSVG(TAC *tac1, TAC *tac2, const char *main_title, const double x1, const double x2, const double y1, const double y2, const char *fname, TPCSTATUS *status)
Definition tacfitplot.c:27
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
int tacFittime(TAC *d, double *startTime, double *endTime, int *first, int *last, TPCSTATUS *status)
int tacReadReference(TAC *tis, const char *reference, TAC *ref, int *refIndex, TPCSTATUS *status)
Read reference tissue TAC.
int tacFixNaNs(TAC *tac)
Definition tacnan.c:121
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:23
int tacIsWeighted(TAC *tac)
Definition tacw.c:24
int tacWByFreq(TAC *tac, isotope isot, TPCSTATUS *status)
Definition tacw.c:134
int tacCorrectFrameOverlap(TAC *d, TPCSTATUS *status)
Correct PET frame start and end times if frames are slightly overlapping or have small gaps in betwee...
Definition tacx.c:65
Header file for libtpcbfm.
Header file for library libtpcextensions.
weights
Is data weighted, or are weight factors available with data?
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ UNIT_MIN
minutes
@ UNIT_UNITLESS
Unitless.
@ UNIT_PER_MIN
1/min
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.
isotope
Definition tpcisotope.h:50
@ ISOTOPE_UNKNOWN
Unknown.
Definition tpcisotope.h:51
Header file for libtpclinopt.
Header file for libtpcpar.
@ PAR_FORMAT_RES
Model result format of Turku PET Centre.
Definition tpcpar.h:29
@ PAR_FORMAT_UNKNOWN
Unknown format.
Definition tpcpar.h:28
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Definition tpcpar.h:35
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28
@ TAC_FORMAT_PMOD
PMOD TAC format.
Definition tpctac.h:33
Header file for libtpctacmod.