TPCCLIB
Loading...
Searching...
No Matches
bfmh2o.c
Go to the documentation of this file.
1
9/*****************************************************************************/
10#include "tpcclibConfig.h"
11/*****************************************************************************/
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <math.h>
16/*****************************************************************************/
17#include "tpcextensions.h"
18#include "tpcift.h"
19#include "tpctac.h"
20#include "tpcpar.h"
21#include "tpcbfm.h"
22#include "tpctacmod.h"
23#include "tpclinopt.h"
24/*****************************************************************************/
25
26/*****************************************************************************/
27static char *info[] = {
28 "Basis function method (BFM) fitting of one-tissue compartmental water model",
29 "to regional PET [O-15]H2O study data (Koeppe et al., 1985; Boellaard et al.,",
30 "2005). The model parameters are blood flow (F), partition coefficient",
31 "(pWater), and arterial blood volume (Va). Venous radioactivity is assumed to",
32 "be the same as the tissue concentration.",
33 "Extraction factor of water is assumed to be 1.0.",
34 " ",
35 "The blood flow obtained using PET [O-15]H2O techniques reflects tissue",
36 "perfusion, since the method is dependent on the tissue exchange of",
37 "labelled water. Non-nutritive flow (blood flowing through arteriovenous",
38 "shunts) is not measured (Lammertsma & Jones, 1983).",
39 " ",
40 "Radioactivity concentration in arterial blood is given in BTAC file, and",
41 "data must be corrected for physical decay and time delay.",
42 "Radioactivity concentration in tissue region(s) is given in TTAC file, and",
43 "data must be corrected for physical decay.",
44 "Sample times must be in seconds in all data files, unless specified inside",
45 "the files. Fitting time must be given in sec.",
46 " ",
47 "Usage: @P [options] BTAC TTAC fittime results",
48 " ",
49 "Options:",
50 " -ml or -dl",
51 " In results the units of F and Va will be given per mL or per dL,",
52 " respectively. By default, units are per dL.",
53 " -fpt",
54 " Report blood flow (perfusion) per perfusable tissue volume",
55 " (PET volume minus vascular volume). By default perfusion is reported",
56 " per PET volume.",
57 " -Va=<Va(%)>",
58 " Enter a fixed Va; fitted by default.",
59 " -pH2O=<Partition coefficient for water>",
60 " Enter the true partition coefficient for water to report perfusion as",
61 " F=k2*pH2O instead of default F=K1; apparent pH2O is fitted in any case.",
62 " -svg=<Filename>",
63 " Plots of original and fitted TTACs are written in specified file in",
64 " SVG format.",
65 " -fit=<Filename>",
66 " Fitted regional TTACs are written in specified file.",
67 " -k2min=<Min k2> and -k2max=<Max k2>",
68 " Enter the minimum and maximum k2 for BFM in units 1/min (for example",
69 " 0.01 and 2.5).",
70 " -fmin=<Min K1> and -fmax=<Max K1>",
71 " Enter the minimum and maximum perfusion value for BFM; defaults are",
72 " 0.5 and 400 ml/(dl*min), respectively.",
73 " -pmin=<Min p> and -max=<pmax>",
74 " Enter the minimum and maximum value for apparent partition coefficient",
75 " for water; defaults are 0.3 and 1.0 ml/ml, respectively.",
76 " -nr=<value>",
77 " Set number of basis functions; default is 5000.",
78 " -bf=<filename>",
79 " Basis function curves are written in specified file.",
80 " -stdoptions", // List standard options like --help, -v, etc
81 " ",
82 "Example:",
83 " @P uo1234bl.bld uo1234.tac 999 uo1234f.res",
84 " ",
85 "References:",
86 "1. Koeppe RA et al. J Cereb Blood Flow metab. 1985;5:224-234.",
87 "2. Boellaard R et al. Mol Imaging Biol. 2005;7:273-285.",
88 "3. Lammertsma AA, Jones T. J Cereb Blood Flow Metab. 1983;3:416-424.",
89 " ",
90 "See also: fitdelay, b2t_h2o, fit_h2o, imgbfh2o, arlkup, fitk2",
91 " ",
92 "Keywords: TAC, modelling, perfusion, blood flow, radiowater, 1TCM",
93 0};
94/*****************************************************************************/
95
96/*****************************************************************************/
97/* Turn on the globbing of the command line, since it is disabled by default in
98 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
99 In Unix&Linux wildcard command line processing is enabled by default. */
100/*
101#undef _CRT_glob
102#define _CRT_glob -1
103*/
104int _dowildcard = -1;
105/*****************************************************************************/
106
107/*****************************************************************************/
111int main(int argc, char **argv)
112{
113 int ai, help=0, version=0, verbose=1;
114 char btacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], resfile[FILENAME_MAX],
115 fitfile[FILENAME_MAX], svgfile[FILENAME_MAX], bffile[FILENAME_MAX];
116 char *cptr;
117 int per_dl=1; // 0 or 1
118 double fVaFixed=nan("");
119 double fitdur=nan("");
120 double pWaterTrue=nan("");
121 double flowMin=0.005, flowMax=4.0; // mL/(min*mL)
122 double pWaterMin=0.3, pWaterMax=1.0; // mL/mL
123 double k2min=nan(""), k2max=nan("");; // 1/min
124 int bfNr=5000;
125 int flow_per_perfusable_tissue=0; // 0 or 1
126 int ret;
127
128
129 /*
130 * Get arguments
131 */
132 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
133 btacfile[0]=ttacfile[0]=resfile[0]=fitfile[0]=svgfile[0]=bffile[0]=(char)0;
134 /* Options */
135 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
136 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
137 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
138 if(strcasecmp(cptr, "DL")==0) {per_dl=1; continue;}
139 else if(strcasecmp(cptr, "ML")==0) {per_dl=0; continue;}
140 else if(strcasecmp(cptr, "FPT")==0) {
141 flow_per_perfusable_tissue=1; continue;
142 } else if(strncasecmp(cptr, "Va=", 3)==0) {
143 fVaFixed=0.01*atofVerified(cptr+3);
144 if(!isnan(fVaFixed) && fVaFixed>=0.0 && fVaFixed<1.0) {
145 if(fVaFixed>0.0 && fVaFixed<0.01)
146 fprintf(stderr, "Warning: Va was set to %g%%\n", 100.*fVaFixed);
147 continue;
148 }
149 } else if(strncasecmp(cptr, "pH2O=", 5)==0 && strlen(cptr)>5) {
150 pWaterTrue=atofVerified(cptr+5);
151 if(!isnan(pWaterTrue) && pWaterTrue>0.0 && pWaterTrue<=1.25) continue;
152 } else if(strncasecmp(cptr, "SVG=", 4)==0) {
153 strlcpy(svgfile, cptr+4, FILENAME_MAX); if(strlen(svgfile)>0) continue;
154 } else if(strncasecmp(cptr, "FIT=", 4)==0) {
155 strlcpy(fitfile, cptr+4, FILENAME_MAX); if(strlen(fitfile)>0) continue;
156 } else if(strncasecmp(cptr, "NR=", 3)==0) {
157 if(atoiCheck(cptr+3, &bfNr)==0 && bfNr>5) continue;
158 } else if(strncasecmp(cptr, "BF=", 3)==0) {
159 strlcpy(bffile, cptr+3, FILENAME_MAX); if(strlen(bffile)>0) continue;
160 } else if(strncasecmp(cptr, "k2min=", 6)==0) {
161 if(atofCheck(cptr+6, &k2min)==0 && k2min>=0.0) continue;
162 } else if(strncasecmp(cptr, "k2max=", 6)==0) {
163 if(atofCheck(cptr+6, &k2max)==0 && k2max>=0.0) continue;
164 } else if(strncasecmp(cptr, "fmin=", 5)==0) {
165 if(atofCheck(cptr+5, &flowMin)==0 && flowMin>=0.0) {flowMin*=0.01; continue;}
166 } else if(strncasecmp(cptr, "fmax=", 5)==0) {
167 if(atofCheck(cptr+5, &flowMax)==0 && flowMax>=0.0) {flowMax*=0.01; continue;}
168 } else if(strncasecmp(cptr, "pmin=", 5)==0) {
169 if(atofCheck(cptr+5, &pWaterMin)==0 && pWaterMin>0.0) continue;
170 } else if(strncasecmp(cptr, "pmax=", 5)==0) {
171 if(atofCheck(cptr+5, &pWaterMax)==0 && pWaterMax<1.25) continue;
172 }
173 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
174 return(1);
175 } else break;
176
177 TPCSTATUS status; statusInit(&status);
178 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
179 status.verbose=verbose-3;
180
181 /* Print help or version? */
182 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
183 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
184 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
185
186 /* Process other arguments, starting from the first non-option */
187 if(ai<argc) strlcpy(btacfile, argv[ai++], FILENAME_MAX);
188 if(ai<argc) strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
189 if(ai<argc) {
190 if(atofCheck(argv[ai], &fitdur)) {
191 fprintf(stderr, "Error: invalid fit time '%s'.\n", argv[ai]);
192 return(1);
193 }
194 if(fitdur<=0.0) fitdur=1.0E+99;
195 ai++;
196 }
197 if(ai<argc) strlcpy(resfile, argv[ai++], FILENAME_MAX);
198 if(ai<argc) {
199 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
200 return(1);
201 }
202 /* Did we get all the information that we need? */
203 if(!resfile[0]) {
204 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
205 return(1);
206 }
207
208
209 /* In verbose mode print arguments and options */
210 if(verbose>1) {
211 printf("btacfile := %s\n", btacfile);
212 printf("ttacfile := %s\n", ttacfile);
213 printf("resfile := %s\n", resfile);
214 printf("fitfile := %s\n", fitfile);
215 printf("svgfile := %s\n", svgfile);
216 printf("bffile := %s\n", bffile);
217 printf("per_dl := %d\n", per_dl);
218 printf("flow_per_perfusable_tissue := %d\n", flow_per_perfusable_tissue);
219 printf("required_fitdur := %g s\n", fitdur);
220 if(!isnan(fVaFixed)) printf("fVaFixed := %g%%\n", 100.*fVaFixed);
221 if(!isnan(pWaterTrue)) printf("pWaterTrue := %g mL/mL\n", pWaterTrue);
222 if(!isnan(k2min)) printf("k2min := %g min-1\n", k2min);
223 if(!isnan(k2max)) printf("k2max := %g min-1\n", k2max);
224 printf("flowMin := %g mL/(min*mL)\n", flowMin);
225 printf("flowMax := %g mL/(min*mL)\n", flowMax);
226 printf("pWaterMin := %g mL/mL\n", pWaterMin);
227 printf("pWaterMax := %g mL/mL\n", pWaterMax);
228 printf("bfNr := %d\n", bfNr);
229 }
230
231 /* Check user-defined parameter ranges and calculate range of k2 */
232 if(flowMin>=flowMax) {
233 fprintf(stderr, "Error: invalid range for perfusion (%g - %g).\n",
234 100.*flowMin, 100.*flowMax);
235 return(1);
236 }
237 if(pWaterMin>=pWaterMax) {
238 fprintf(stderr, "Error: invalid range for p (%g - %g).\n",
239 pWaterMin, pWaterMax);
240 return(1);
241 }
242 if(isnan(k2min)) {
243 k2min=flowMin/pWaterMax;
244 if(verbose>1) printf("k2min := %g min-1\n", k2min);
245 }
246 if(isnan(k2max)) {
247 k2max=flowMax/pWaterMin;
248 if(verbose>1) printf("k2max := %g min-1\n", k2max);
249 }
250 if(k2max<=k2min || k2min<=0.) {
251 fprintf(stderr, "Error: invalid range for k2 (%g - %g).\n", k2min, k2max);
252 return(1);
253 }
254 /* Convert k2 from 1/min to 1/sec */
255 k2min/=60.; k2max/=60.0;
256 if(verbose>2) {
257 printf("k2min := %g sec-1\n", k2min);
258 printf("k2max := %g sec-1\n", k2max);
259 }
260
261
262 /*
263 * Read tissue and input data
264 */
265 if(verbose>1) printf("reading tissue and input data\n");
266 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
267 TAC btac, ttac; tacInit(&btac); tacInit(&ttac);
268 int fitSampleNr;
269 fitdur/=60.0;
270 ret=tacReadModelingData(ttacfile, btacfile, NULL, NULL, &fitdur, 0,
271 &fitSampleNr, &ttac, &btac, &status);
272 if(ret!=TPCERROR_OK) {
273 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
274 tacFree(&ttac); tacFree(&btac); return(2);
275 }
276 fitdur*=60.0;
277 if(verbose>2) {
278 printf("fileformat := %s\n", tacFormattxt(ttac.format));
279 printf("tacNr := %d\n", ttac.tacNr);
280 printf("ttac.sampleNr := %d\n", ttac.sampleNr);
281 printf("btac.sampleNr := %d\n", btac.sampleNr);
282 printf("fitSampleNr := %d\n", fitSampleNr);
283 printf("xunit := %s\n", unitName(ttac.tunit));
284 printf("yunit := %s\n", unitName(ttac.cunit));
285 printf("fitdur := %g s\n", fitdur);
286 int i=iftFindKey(&ttac.h, "studynr", 0);
287 if(i<0) i=iftFindKey(&ttac.h, "study_number", 0);
288 if(i>=0) printf("%s := %s\n", ttac.h.item[i].key, ttac.h.item[i].value);
289
290 }
291 if(fitSampleNr<4 || btac.sampleNr<4) {
292 fprintf(stderr, "Error: too few samples in specified fit duration.\n");
293 tacFree(&ttac); tacFree(&btac); return(2);
294 }
295 /* Sample times should now be in minutes, change them to sec */
296 tacXUnitConvert(&ttac, UNIT_SEC, NULL);
297 tacXUnitConvert(&btac, UNIT_SEC, NULL);
298 /* Check weighting */
299 if(!tacIsWeighted(&ttac) && verbose>0) fprintf(stderr, "Note: data is not weighted.\n");
300
301 /* Interpolate BTAC to TTAC sample times; needed for Va correction */
302 if(verbose>1) printf("interpolating BTAC to TTAC sample times\n");
303 TAC tbtac; tacInit(&tbtac);
304 ret=tacInterpolate(&btac, &ttac, &tbtac, NULL, NULL, &status);
305 if(ret!=TPCERROR_OK) {
306 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
307 tacFree(&ttac); tacFree(&btac); return(2);
308 }
309
310 /* If fixed Va was given by user, then subtract it from the tissue data */
311 if(!isnan(fVaFixed) && fVaFixed>0.0) {
312 if(verbose>1) printf("subtracting Va*BTAC from TTACs\n");
313 for(int i=0; i<fitSampleNr; i++) {
314 if(isnan(tbtac.c[0].y[i])) continue;
315 for(int j=0; j<ttac.tacNr; j++) {
316 if(isnan(ttac.c[j].y[i])) continue;
317 ttac.c[j].y[i]-=fVaFixed*tbtac.c[0].y[i];
318 }
319 }
320 }
321
322
323 /*
324 * Calculate the basis functions
325 */
326 if(verbose>1) printf("calculating basis functions\n");
327 TAC bf; tacInit(&bf);
328 ret=bfm1TCM(&btac, &ttac, bfNr, k2min, k2max, 0, &bf, &status);
329 if(ret!=TPCERROR_OK) {
330 if(verbose>1) fprintf(stderr, "Error: cannot calculate basis functions.\n");
331 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
332 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); return(3);
333 }
334 /* Save basis functions if required */
335 if(bffile[0]) {
336 if(verbose>1) printf("writing %s\n", bffile);
337 FILE *fp; fp=fopen(bffile, "w");
338 if(fp==NULL) {
339 fprintf(stderr, "Error: cannot open file for writing (%s)\n", bffile);
340 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
341 return(3);
342 }
343 ret=tacWrite(&bf, fp, TAC_FORMAT_UNKNOWN, 1, &status);
344 fclose(fp);
345 if(ret!=TPCERROR_OK) {
346 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
347 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
348 return(3);
349 }
350 if(verbose>0) printf("basis functions saved in %s.\n", bffile);
351 }
352
353
354
355 /*
356 * Prepare the room for results
357 */
358 if(verbose>1) printf("initializing result data\n");
359 PAR par; parInit(&par);
360 ret=parAllocateWithTAC(&par, &ttac, 3, &status);
361 if(ret!=TPCERROR_OK) {
362 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
363 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
364 return(4);
365 }
366 /* Copy titles & filenames */
367 {
368 int i;
369 char buf[256];
370 time_t t=time(NULL);
371 /* set program name */
372 tpcProgramName(argv[0], 1, 1, buf, 256);
373 iftPut(&par.h, "program", buf, 0, NULL);
374 /* set file names */
375 iftPut(&par.h, "bloodfile", btacfile, 0, NULL);
376 iftPut(&par.h, "datafile", ttacfile, 0, NULL);
377 /* Fit method */
378 iftPut(&par.h, "fitmethod", "BFM", 0, NULL);
379 /* Constants */
380 if(fVaFixed>=0.0) {
381 sprintf(buf, "%g %%", 100.0*fVaFixed);
382 iftPut(&par.h, "Vb", buf, 0, NULL);
383 }
384 if(pWaterTrue>0) {
385 sprintf(buf, "%g", pWaterTrue);
386 iftPut(&par.h, "pH2O", buf, 0, NULL);
387 }
388 /* Set current time to results */
389 iftPut(&par.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
390 /* Set fit times for each TAC */
391 for(i=0; i<par.tacNr; i++) {
392 par.r[i].dataNr=fitSampleNr;
393 par.r[i].start=0.0;
394 par.r[i].end=fitdur/60.0;
395 /* and nr of fitted parameters */
396 par.r[i].fitNr=3; if(fVaFixed>0.0) par.r[i].fitNr--;
397 }
398 /* Set the parameter names and units */
399 i=0; strcpy(par.n[i].name, "Flow");
400 if(per_dl==0) par.n[i].unit=UNIT_ML_PER_ML_MIN;
401 else par.n[i].unit=UNIT_ML_PER_DL_MIN;
402 i++; strcpy(par.n[i].name, "pWater"); par.n[i].unit=UNIT_ML_PER_ML;
403 i++; strcpy(par.n[i].name, "Va");
404 if(per_dl==0) par.n[i].unit=UNIT_ML_PER_ML;
405 else par.n[i].unit=UNIT_PERCENTAGE;
406 }
407
408
409 /*
410 * Prepare the room for fitted TTACs, if requested
411 */
412 TAC ftac; tacInit(&ftac);
413 if(fitfile[0] || svgfile[0]) {
414 if(verbose>1) printf("allocating space for fitted TTACs\n");
415 ret=tacDuplicate(&ttac, &ftac);
416 if(ret!=TPCERROR_OK) {
417 fprintf(stderr, "Error: cannot allocate space for fitted TACs.\n");
418 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
419 parFree(&par);
420 return(4);
421 }
422 ftac.sampleNr=fitSampleNr;
423 }
424
425
426 /*
427 * Allocate memory for QR
428 */
429 if(verbose>1) printf("allocating memory for QR\n");
430 int colNr, rowNr;
431 colNr=2; if(fVaFixed>0.0) colNr--;
432 rowNr=fitSampleNr;
433 if(verbose>2) {
434 printf("QR_colNr := %d\n", colNr);
435 printf("QR_rowNr := %d\n", rowNr);
436 }
437 double *buf, **mat, *rhs, *sol, r2;
438 buf=(double*)calloc(colNr*rowNr+rowNr+colNr, sizeof(double));
439 mat=(double**)calloc(rowNr, sizeof(double*));
440 if(buf==NULL || mat==NULL) {
441 fprintf(stderr, "Error: cannot allocate memory for QR\n");
442 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
443 tacFree(&ftac); parFree(&par);
444 return(6);
445 }
446 for(int i=0; i<rowNr; i++) mat[i]=buf+(i*colNr);
447 rhs=buf+(rowNr*colNr); sol=buf+(rowNr*colNr+rowNr);
448
449 /*
450 * BF fitting to each regional TAC
451 */
452 if(verbose>1) printf("BFM fitting to TACs.\n");
453 double r2_min;
454 int bi, bi_min;
455 for(int i=0; i<ttac.tacNr; i++) {
456
457 if(verbose>1 && ttac.tacNr>1) printf("Region %d %s\n", i+1, ttac.c[i].name);
458
459 /* Go through all basis functions */
460 bi_min=-1; r2_min=nan("");
461 for(bi=0; bi<bf.tacNr; bi++) {
462
463 if(verbose>5) printf("bi=%d\n", bi);
464
465 /* Initiate matrix */
466 for(int j=0; j<rowNr; j++) {
467 mat[j][0]=bf.c[bi].y[j];
468 if(colNr>1) mat[j][1]=tbtac.c[0].y[j];
469 rhs[j]=ttac.c[i].y[j];
470 }
471 /* Apply data weights */
472 if(verbose>5) printf(" weighting\n");
473 /* Preallocate temp memory at some point */
474 if(tacIsWeighted(&ttac)) qrWeight(colNr, rowNr, mat, rhs, ttac.w, NULL);
475
476 /* Compute QR */
477 if(verbose>5) printf(" QR\n");
478 ret=qrLSQ(mat, rhs, sol, rowNr, colNr, &r2);
479 if(ret!=0) {
480 fprintf(stderr, "Error: no QR solution for BFM\n");
481 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
482 tacFree(&ftac); parFree(&par);
483 free(buf); free(mat);
484 return(6);
485 }
486 if(verbose>5) {
487 printf("solution (%d):", bi);
488 for(int j=0; j<colNr; j++) printf(" %g", sol[j]);
489 printf("\nR^2= %g R=%g\n", r2, sqrt(r2));
490 }
491 /* Check if this was best fit for now */
492 if(isnan(r2_min) || r2_min>r2) {
493 r2_min=r2; bi_min=bi;
494 }
495 } /* next basis function */
496 if(verbose>2) printf("Min basis function nr %d with R2=%g\n", bi_min+1, r2_min);
497
498 /* Compute the best BF again to retrieve the solution */
499 bi=bi_min;
500 /* Initiate matrix */
501 for(int j=0; j<rowNr; j++) {
502 mat[j][0]=bf.c[bi].y[j];
503 if(colNr>1) mat[j][1]=tbtac.c[0].y[j];
504 rhs[j]=ttac.c[i].y[j];
505 }
506 /* Apply data weights */
507 if(verbose>5) printf(" weighting\n");
508 /* Preallocate temp memory at some point */
509 if(tacIsWeighted(&ttac)) qrWeight(colNr, rowNr, mat, rhs, ttac.w, NULL);
510 /* Compute QR */
511 if(verbose>5) printf(" QR\n");
512 ret=qrLSQ(mat, rhs, sol, rowNr, colNr, &r2);
513 if(ret!=0) {
514 fprintf(stderr, "Error: no QR solution for BFM\n");
515 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
516 tacFree(&ftac); parFree(&par);
517 free(buf); free(mat);
518 return(6);
519 }
520 par.r[i].wss=r2;
521 if(verbose>5) {
522 printf("best_solution (%d):", bi);
523 for(int j=0; j<colNr; j++) printf(" %g", sol[j]);
524 printf("\nR^2= %g R=%g\n", r2, sqrt(r2));
525 }
526 /* Remove weights */
527 if(tacIsWeighted(&ttac)) qrWeightRm(colNr, rowNr, mat, rhs, ttac.w, NULL);
528 /* Fitted TTAC is in rhs[] */
529 if(fitfile[0] || svgfile[0]) {
530 for(int j=0; j<ftac.sampleNr; j++) ftac.c[i].y[j]=rhs[j];
531 }
532 /* Solve final parameters Flow, pH2O, and Va */
533 double Flow, pH2O, Va, k2;
534 k2=bf.c[bi_min].size; //printf("k2=%g\n", k2);
535 if(isnan(fVaFixed)) Va=sol[1]; else Va=fVaFixed; //printf("Va=%g\n", Va);
536 if(pWaterTrue>0) {
537 /* True p for radiowater is given, therefore lets calculate flow from k2 */
538 Flow=k2*pWaterTrue;
539 } else {
540 /* True p for radiowater is not given, therefore lets assume that flow=K1 */
541 Flow=sol[0]/(1.0-Va);
542 }
543 // printf("Flow=%g\n", Flow);
544 /* Apparent p for radiowater is K1/k2 */
545 pH2O=sol[0]/((1.0-Va)*k2); //printf("pH2O=%g\n", pH2O);
546
547 /* Put the final parameters in place */
548 if(flow_per_perfusable_tissue==0) Flow*=(1.0-Va);
549 if(per_dl!=0) {Flow*=100.0; Va*=100;}
550 par.r[i].p[0]=60.0*Flow; // 1/sec -> 1/min
551 par.r[i].p[1]=pH2O;
552 par.r[i].p[2]=Va;
553
554 } /* next region */
555
556 /* Free the memory allocated for QR */
557 free(buf); free(mat);
558
559
560 /*
561 * Print results on screen
562 */
563 if(verbose>0 && par.tacNr<50) parWrite(&par, stdout, PAR_FORMAT_RES, 0, &status);
564
565 /*
566 * Save results
567 */
568 if(resfile[0]) {
569 if(verbose>1) printf("writing %s\n", resfile);
570 par.format=parFormatFromExtension(resfile);
571 if(verbose>2)
572 printf("result file format := %s\n", parFormattxt(par.format));
574 FILE *fp; fp=fopen(resfile, "w");
575 if(fp==NULL) {
576 fprintf(stderr, "Error: cannot open file for writing (%s)\n", resfile);
577 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
578 tacFree(&ftac); parFree(&par);
579 return(11);
580 }
581 ret=parWrite(&par, fp, PAR_FORMAT_UNKNOWN, 1, &status);
582 fclose(fp);
583 //parFree(&par);
584 if(ret!=TPCERROR_OK) {
585 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
586 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
587 tacFree(&ftac); parFree(&par);
588 return(12);
589 }
590 if(verbose>0) printf("Results saved in %s.\n", resfile);
591 }
592
593
594 /*
595 * SVG plot of fitted and original data
596 */
597 if(svgfile[0]) {
598
599 if(verbose>1) printf("saving SVG plot\n");
600 int i;
601 char buf[128];
602 sprintf(buf, "Radiowater BFM fit");
603 i=iftFindKey(&ttac.h, "studynr", 0);
604 if(i<0) i=iftFindKey(&ttac.h, "study_number", 0);
605 if(i>=0) {strcat(buf, ": "); strcat(buf, ttac.h.item[i].value);}
606 ret=tacPlotFitSVG(&ttac, &ftac, buf, 0.0, nan(""), 0.0, nan(""), svgfile, &status);
607 if(ret!=TPCERROR_OK) {
608 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
609 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
610 tacFree(&ftac); parFree(&par);
611 return(21);
612 }
613 if(verbose>0) printf("Plots written in %s.\n", svgfile);
614 }
615
616 /*
617 * Save fitted TTACs
618 */
619 if(fitfile[0]) {
620 if(verbose>1) printf("writing %s\n", fitfile);
621 FILE *fp; fp=fopen(fitfile, "w");
622 if(fp==NULL) {
623 fprintf(stderr, "Error: cannot open file for writing (%s)\n", fitfile);
624 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
625 tacFree(&ftac); parFree(&par);
626 return(31);
627 }
628 ret=tacWrite(&ftac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
629 fclose(fp);
630 if(ret!=TPCERROR_OK) {
631 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
632 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
633 tacFree(&ftac); parFree(&par);
634 return(32);
635 }
636 if(verbose>0) printf("fitted TACs saved in %s.\n", fitfile);
637 }
638
639
640 tacFree(&ttac); tacFree(&btac); tacFree(&tbtac); tacFree(&bf);
641 tacFree(&ftac); parFree(&par);
642
643 return(0);
644}
645/*****************************************************************************/
646
647/*****************************************************************************/
int bfm1TCM(TAC *input, TAC *tissue, int bfNr, const double k2min, const double k2max, const int distr, TAC *bf, TPCSTATUS *status)
Definition bf_1tcm.c:27
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 atofVerified(const char *s)
Definition decpoint.c:75
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
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
char * key
Definition tpcift.h:32
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 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
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
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 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
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 tacReadModelingData(const char *tissuefile, const char *inputfile1, const char *inputfile2, const char *inputfile3, double *fitdur, int cutInput, int *fitSampleNr, TAC *tis, TAC *inp, TPCSTATUS *status)
Read tissue and input data for modelling.
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:23
int tacIsWeighted(TAC *tac)
Definition tacw.c:24
Header file for libtpcbfm.
Header file for library libtpcextensions.
@ UNIT_ML_PER_ML
mL/mL
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ UNIT_ML_PER_DL_MIN
mL/(dL*min)
@ UNIT_SEC
seconds
@ UNIT_PERCENTAGE
Percentage (%).
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.
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
Header file for libtpctacmod.