TPCCLIB
Loading...
Searching...
No Matches
fitk4di.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 <math.h>
14#include <unistd.h>
15#include <string.h>
16#include <time.h>
17/*****************************************************************************/
18#include "libtpcmisc.h"
19#include "libtpcmodel.h"
20#include "libtpccurveio.h"
21#include "libtpcsvg.h"
22#include "libtpcmodext.h"
23/*****************************************************************************/
24
25/*****************************************************************************/
26static char *info[] = {
27 "Non-linear fitting of dual input compartment model, with one tissue",
28 "compartment for each input (parent tracer and its labelled metabolite):",
29 " ",
30 " _____ K1p ______ k3p ______ ",
31 " | Cap | ----> | Ct1p | ----> | Ct2p | ",
32 " |_____| <---- |______| <---- |______| ",
33 " k2p k4p ",
34 " ",
35 " _____ K1m _____ ",
36 " | Cam | ----> | Ctm | ",
37 " |_____| <---- |_____| ",
38 " k2m ",
39 " ",
40 "Note that the model may be too complex to provide reliable parameter",
41 "estimates in most practical use cases.",
42 " ",
43 "Usage: @P [Options] ptacfile mtacfile btacfile ttacfile endtime resultfile",
44 " ",
45 "Options:",
46 " -lim[=<filename>]",
47 " Specify the constraints for model parameters;",
48 " This file with default values can be created by giving this",
49 " option as the only command-line argument to this program.",
50 " Without filename the default values are printed on screen.",
51 " -SD=<y|N>",
52 " Standard deviations are calculated and saved in results (y),",
53 " or not calculated (N, default).",
54 " Program runs a lot faster if SD and CL are not calculated.",
55 " -CL=<y|N>",
56 " 95% Confidence limits are calculated and saved in results (y), or",
57 " not calculated (N, default).",
58 " -Vb=<Vb(%)>",
59 " Enter a fixed Vb; fitted by default.",
60 " If Vb (vascular blood volume) is pre-corrected or to be ignored, set",
61 " it to 0; btacfile can be set to 'none'.",
62 " -mc=<Filename>",
63 " Fit-based metabolite corrected regional TACs are written in the file.",
64 " -fit=<Filename>",
65 " Fitted regional TACs are written in the file.",
66 " -svg=<Filename>",
67 " Fitted and measured TACs are plotted in specified SVG file.",
68 " -stdoptions", // List standard options like --help, -v, etc
69 " ",
70 "Sample times must be in minutes.",
71 " ",
72 "Example: fitting with default settings",
73 " @P ia919apc.kbq ia919apm.kbq ia919ab.kbq ia919.dft 60 a919k4di.res",
74 " ",
75 "See also: fitk2di, fitk2, fitk4, sim_3tcm, tacweigh, taccbv",
76 " ",
77 "Keywords: TAC, modelling, distribution volume, dual-input",
78 0};
79/*****************************************************************************/
80
81/*****************************************************************************/
82/* Turn on the globbing of the command line, since it is disabled by default in
83 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
84 In Unix&Linux wildcard command line processing is enabled by default. */
85/*
86#undef _CRT_glob
87#define _CRT_glob -1
88*/
89int _dowildcard = -1;
90/*****************************************************************************/
91
92/*****************************************************************************/
93const int parNr=7, parVb=6;
94DFT input, dft, fit;
95double *petmeas, *petsim;
96double fVb=-1.0;
97double pmin[MAX_PARAMETERS], pmax[MAX_PARAMETERS];
98int fitframeNr;
99// Parameter names in the limit file and in actual fitting
100static char *parName[] = {"K1p", "V1p", "k3p", "k4p", "K1m", "V1m", "Vb", 0};
101/*****************************************************************************/
102/* Local functions */
103double func2TCMdi(int parNr, double *p, void*);
104/*****************************************************************************/
105
106/*****************************************************************************/
110int main(int argc, char **argv)
111{
112 int ai, help=0, version=0, verbose=1;
113 int ri, fi, pi, n, ret;
114 char dfile[FILENAME_MAX], bfile[FILENAME_MAX],
115 pfile[FILENAME_MAX], mfile[FILENAME_MAX],
116 ffile[FILENAME_MAX], mcfile[FILENAME_MAX],
117 rfile[FILENAME_MAX], limfile[FILENAME_MAX], svgfile[FILENAME_MAX];
118 char *cptr, tmp[FILENAME_MAX];
119 int irrev=0; // 1 if k4p is fixed to zero
120 double f, fitdur, wss;
121 RES res;
122 int doBootstrap=0, doSD=0, doCL=0; // 0=no, 1=yes
123 double *sd, *cl1, *cl2;
124 double def_pmin[MAX_PARAMETERS], def_pmax[MAX_PARAMETERS];
125 int tgoNr=0, neighNr=0, iterNr=0, fittedparNr=0;
126
127
128
129 /* Set parameter initial values and constraints */
130 /* K1p */ def_pmin[0]=0.0; def_pmax[0]=10.0;
131 /* V1p=K1p/k2p */ def_pmin[1]=0.0; def_pmax[1]=500.0;
132 /* k3p */ def_pmin[2]=0.0; def_pmax[2]=1.0;
133 /* k4p */ def_pmin[3]=0.0; def_pmax[3]=1.0;
134 /* K1m */ def_pmin[4]=0.0; def_pmax[4]=10.0;
135 /* V1m=K1m/k2m */ def_pmin[5]=0.0; def_pmax[5]=5.0;
136 /* Vb */ def_pmin[6]=0.0; def_pmax[6]=0.10;
137
138
139 /*
140 * Get arguments
141 */
142 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
143 dfile[0]=pfile[0]=mfile[0]=bfile[0]=(char)0;
144 rfile[0]=ffile[0]=limfile[0]=svgfile[0]=mcfile[0]=(char)0;
145 fitdur=fVb=-1.0;
146 resInit(&res); dftInit(&input); dftInit(&dft); dftInit(&fit);
147 /* Get options first, because it may affect what arguments are read */
148 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
149 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
150 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
151 if(strncasecmp(cptr, "CL", 2)==0) {
152 if(strlen(cptr)==2) {doCL=1; continue;}
153 cptr+=2; if(*cptr=='=') {
154 cptr++;
155 if(*cptr=='Y' || *cptr=='y') {doCL=1; continue;}
156 if(*cptr=='N' || *cptr=='n') {doCL=0; continue;}
157 }
158 } else if(strncasecmp(cptr, "SD", 2)==0) {
159 if(strlen(cptr)==2) {doSD=1; continue;}
160 cptr+=2; if(*cptr=='=') {
161 cptr++;
162 if(*cptr=='Y' || *cptr=='y') {doSD=1; continue;}
163 if(*cptr=='N' || *cptr=='n') {doSD=0; continue;}
164 }
165 } else if(strncasecmp(cptr, "LIM=", 4)==0 && strlen(cptr)>4) {
166 strlcpy(limfile, cptr+4, FILENAME_MAX); continue;
167 } else if(strcasecmp(cptr, "LIM")==0) {
168 strcpy(limfile, "stdout"); continue;
169 } else if(strncasecmp(cptr, "Vb=", 3)==0 && strlen(cptr)>3) {
170 fVb=0.01*atof_dpi(cptr+3);
171 if(fVb>=0.0 && fVb<1.0) {
172 if(fVb<0.01) fprintf(stderr, "Warning: Vb was set to %g%%\n", 100.*fVb);
173 def_pmin[parVb]=def_pmax[parVb]=fVb;
174 continue;
175 }
176 fVb=-1.0;
177 } else if(strncasecmp(cptr, "MC=", 3)==0) {
178 strlcpy(mcfile, cptr+3, FILENAME_MAX); if(strlen(mcfile)>0) continue;
179 } else if(strncasecmp(cptr, "FIT=", 4)==0) {
180 strlcpy(ffile, cptr+4, FILENAME_MAX); if(strlen(ffile)>0) continue;
181 } else if(strncasecmp(cptr, "SVG=", 4)==0) {
182 strlcpy(svgfile, cptr+4, FILENAME_MAX); if(strlen(svgfile)>0) continue;
183 }
184 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
185 return(1);
186 }
187
188
189 /* Print help or version? */
190 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
191 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
192 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
193
194 /* Process other arguments, starting from the first non-option */
195 for(ai=1; ai<argc; ai++) if(*argv[ai]!='-') {
196 if(!pfile[0]) {strlcpy(pfile, argv[ai], FILENAME_MAX); continue;}
197 else if(!mfile[0]) {strlcpy(mfile, argv[ai], FILENAME_MAX); continue;}
198 else if(!bfile[0]) {strlcpy(bfile, argv[ai], FILENAME_MAX); continue;}
199 else if(!dfile[0]) {strlcpy(dfile, argv[ai], FILENAME_MAX); continue;}
200 else if(fitdur<0) {fitdur=atof_dpi(argv[ai]); if(fitdur>0.0) continue;}
201 else if(!rfile[0]) {strlcpy(rfile, argv[ai], FILENAME_MAX); continue;}
202 /* we should never get this far */
203 fprintf(stderr, "Error: too many arguments: '%s'.\n", argv[ai]);
204 return(1);
205 }
206 if(doSD || doCL) doBootstrap=1; else doBootstrap=0;
207 /* User may not have blood file, and has entered 'none' instead */
208 if(strcasecmp(bfile, "NONE")==0) {strcpy(bfile, ""); fVb=0.0;}
209
210 /* If only filename for initial values was given, then write one
211 with default contents and exit */
212 if(limfile[0] && !pfile[0]) {
213 /* Check that initial value file does not exist */
214 if(strcasecmp(limfile, "stdout")!=0 && access(limfile, 0) != -1) {
215 fprintf(stderr, "Error: parameter constraint file %s exists.\n", limfile);
216 return(9);
217 }
218 if(verbose>1) printf("writing parameter constraints file\n");
219 IFT ift; iftInit(&ift);
220 /* Create parameter file */
221 for(pi=0; pi<parNr; pi++) {
222 if(pi==1) iftPut(&ift, NULL, "V1p=K1p/k2p", "#", 0);
223 else if(pi==5) iftPut(&ift, NULL, "V1m=K1m/k2m", "#", 0);
224 sprintf(tmp, "%s_lower", parName[pi]);
225 iftPutDouble(&ift, tmp, def_pmin[pi], NULL, 0);
226 sprintf(tmp, "%s_upper", parName[pi]);
227 iftPutDouble(&ift, tmp, def_pmax[pi], NULL, 0);
228 }
229 if((ret=iftWrite(&ift, limfile, 0))!=0) {
230 fprintf(stderr, "Error in writing '%s': %s\n", limfile, ift.status);
231 iftEmpty(&ift); return(9);
232 }
233 if(strcasecmp(limfile, "stdout")!=0) fprintf(stdout,
234 "Parameter file %s with initial values written.\n", limfile);
235 iftEmpty(&ift); return(0);
236 }
237
238 /* Did we get all the information from user that we need? */
239 if(fitdur==0) fitdur=1.0E+100;
240 else if(fitdur<0) {tpcPrintUsage(argv[0], info, stderr); return(1);}
241 if(!rfile[0]) {
242 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
243 return(1);
244 }
245
246 /* In verbose mode print arguments and options */
247 if(verbose>1) {
248 printf("pfile := %s\n", pfile);
249 printf("mfile := %s\n", mfile);
250 printf("dfile :=%s\n", dfile);
251 printf("rfile := %s\n", rfile);
252 printf("mcfile := %s\n", mcfile);
253 printf("ffile := %s\n", ffile);
254 printf("svgfile := %s\n", svgfile);
255 printf("limfile := %s\n", limfile);
256 printf("fitdur := %g\n", fitdur);
257 printf("doBootstrap := %d\n", doBootstrap);
258 printf("doSD := %d\n", doSD);
259 printf("doCL := %d\n", doCL);
260 }
261
262
263 /*
264 * Read model parameter initial values and upper and lower limits
265 * if file for that was given
266 */
267 if(limfile[0]) {
268 IFT ift; iftInit(&ift);
269 if(verbose>1) printf("reading %s\n", limfile);
270 ret=iftRead(&ift, limfile, 1, 0);
271 if(ret) {
272 fprintf(stderr, "Error in reading '%s': %s\n", limfile, ift.status);
273 return(9);
274 }
275 if(verbose>10) iftWrite(&ift, "stdout", 0);
276 double v;
277 int n=0;
278 for(pi=0; pi<parNr; pi++) {
279 sprintf(tmp, "%s_lower", parName[pi]);
280 if(iftGetDoubleValue(&ift, 0, tmp, &v, 0)>=0) {def_pmin[pi]=v; n++;}
281 sprintf(tmp, "%s_upper", parName[pi]);
282 if(iftGetDoubleValue(&ift, 0, tmp, &v, 0)>=0) {def_pmax[pi]=v; n++;}
283 }
284 iftEmpty(&ift);
285 if(n==0) {fprintf(stderr, "Error: invalid parameter file.\n"); return(9);}
286 }
287 /* Check that these are ok */
288 for(pi=n=0, ret=0; pi<parNr; pi++) {
289 if(def_pmin[pi]<0.0) ret++;
290 if(def_pmax[pi]<def_pmin[pi]) ret++;
291 if(def_pmax[pi]>def_pmin[pi]) n++;
292 }
293 if(ret>0) {
294 fprintf(stderr, "Error: invalid parameter constraints.\n");
295 return(9);
296 }
297 if(n==0) {
298 fprintf(stderr, "Error: no model parameters left free for fitting.\n");
299 return(9);
300 }
301
302 /* Fixed/fitted Vb */
303 if(fVb>=0.0) def_pmin[parVb]=def_pmax[parVb]=fVb;
304 if(def_pmin[parVb]==def_pmax[parVb]) fVb=def_pmin[parVb];
305 if(fVb==0.0) strcpy(bfile, "");
306 if(verbose>1) {
307 printf("bfile := %s\n", bfile);
308 //if(fVb>=0.0) printf("fVb := %g\n", fVb);
309 }
310 /* Irreversible 1TCM (k2=0) ? */
311 if(def_pmax[1]==0.0) {
312 def_pmin[2]=def_pmax[2]=def_pmin[3]=def_pmax[3]=0.0;
313 if(def_pmax[0]>0.0) irrev=1;
314 }
315 /* Irreversible 2TCM (k4=0 but k3>0) ? */
316 if(def_pmax[3]==0.0 && def_pmax[2]>0.0) irrev=1;
317 /* Reversible 1TCM (k3=0) ? */
318 if(def_pmax[2]==0.0) def_pmin[3]=def_pmax[3]=0.0;
319 /* Metabolite: if K1m=0 then K1m/k2m=0 */
320 if(!(def_pmax[4]>0.0)) def_pmin[5]=def_pmax[5]=0.0;
321
322
323 /*
324 * Read tissue and input data
325 */
326 if(verbose>1) printf("reading tissue and input data\n");
327 ret=dftReadModelingData(dfile, pfile, mfile, bfile, &fitdur,
328 &fitframeNr, &dft, &input, stdout, verbose-2, tmp);
329 if(ret!=0) {
330 fprintf(stderr, "Error: %s\n", tmp);
331 dftEmpty(&dft); dftEmpty(&input); return(2);
332 }
333 if(fitframeNr<parNr+1 || input.frameNr<parNr+1) {
334 fprintf(stderr, "Error: too few samples in specified fit duration.\n");
335 dftEmpty(&input); dftEmpty(&dft); return(2);
336 }
337 if(input.voiNr<2) {
338 fprintf(stderr, "Error: valid plasma TACs must be provided.\n");
339 dftEmpty(&input); dftEmpty(&dft); return(2);
340 }
341 /* If there is no blood TAC, then create a zero blood TAC */
342 if(input.voiNr<3) {
343 if(verbose>2) printf("setting blood tac to zero\n");
344 ret=dftAddmem(&input, 1);
345 if(ret) {
346 fprintf(stderr, "Error: cannot allocate more memory.\n");
347 dftEmpty(&dft); dftEmpty(&input); return(3);
348 }
349 strcpy(input.voi[2].voiname, "blood");
350 for(fi=0; fi<input.frameNr; fi++) input.voi[2].y[fi]=0.0;
351 input.voiNr=3;
352 /* and make sure that Vb=0 */
353 def_pmin[parVb]=def_pmax[parVb]=fVb=0.0;
354 }
355 if(verbose>1) {
356 if(fVb>=0.0) printf("fVb := %g\n", fVb);
357 }
358 if(verbose>10) dftPrint(&dft);
359 if(verbose>10) dftPrint(&input);
360 /* Print the weights */
361 if(verbose>2) {
362 fprintf(stdout, "common_data_weights := %g", dft.w[0]);
363 for(fi=1; fi<dft.frameNr; fi++) fprintf(stdout, ", %g", dft.w[fi]);
364 fprintf(stdout, "\n");
365 }
366
367
368 /* Allocate an extra TAC for the bootstrap */
369 if(doBootstrap) {
370 ret=dftAddmem(&dft, 1); if(ret) {
371 fprintf(stderr, "Error: cannot allocate more memory.\n");
372 dftEmpty(&dft); dftEmpty(&input); return(9);
373 }
374 strcpy(dft.voi[dft.voiNr].voiname, "BS");
375 strcpy(dft.voi[dft.voiNr].name, "BS");
376 }
377 if(verbose>10) dftPrint(&dft);
378
379
380 /*
381 * Prepare the room for the results
382 */
383 if(verbose>1) printf("initializing result data\n");
384 ret=res_allocate_with_dft(&res, &dft); if(ret!=0) {
385 fprintf(stderr, "Error: cannot setup memory for results.\n");
386 dftEmpty(&input); dftEmpty(&dft); return(7);
387 }
388 /* Copy titles & file names */
389 tpcProgramName(argv[0], 1, 1, res.program, 256);
390 strcpy(res.datafile, dfile);
391 strcpy(res.plasmafile, pfile);
392 strcpy(res.plasmafile2, mfile);
393 strcpy(res.bloodfile, bfile);
394 strcpy(res.fitmethod, "TGO");
395 /* Constants */
396 if(fVb>=0.0) res.Vb=100.0*fVb; else res.Vb=-1.0;
397 res.isweight=dft.isweight;
398 /* Set data range */
399 sprintf(res.datarange, "%g - %g %s", 0.0, fitdur, dftTimeunit(dft.timeunit));
400 res.datanr=fitframeNr;
401 /* Set current time to results */
402 res.time=time(NULL);
403 /* Set parameter number, including also the extra "parameters"
404 and the parameter names and units */
405 res.parNr=parNr+2;
406 pi=0; strcpy(res.parname[pi], "K1p"); strcpy(res.parunit[pi], "ml/(min*ml)");
407 pi++; strcpy(res.parname[pi], "K1p/k2p"); strcpy(res.parunit[pi], "ml/ml");
408 pi++; strcpy(res.parname[pi], "k3p"); strcpy(res.parunit[pi], "1/min");
409 pi++; strcpy(res.parname[pi], "k4p"); strcpy(res.parunit[pi], "1/min");
410 pi++; strcpy(res.parname[pi], "K1m"); strcpy(res.parunit[pi], "ml/(min*ml)");
411 pi++; strcpy(res.parname[pi], "K1m/k2m"); strcpy(res.parunit[pi], "ml/ml");
412 pi++; strcpy(res.parname[pi], "Vb"); strcpy(res.parunit[pi], "%");
413 pi++;
414 if(irrev==0) {strcpy(res.parname[pi], "DV"); strcpy(res.parunit[pi], "ml/ml");}
415 else {strcpy(res.parname[pi], "Ki"); strcpy(res.parunit[pi], "ml/(min*ml)");}
416 pi++; strcpy(res.parname[pi], "WSS"); strcpy(res.parunit[pi], "");
417
418 /*
419 * Allocate memory for fitted curves
420 */
421 ret=dftdup(&dft, &fit);
422 if(ret) {
423 fprintf(stderr, "Error %d in memory allocation for fitted curves.\n", ret);
424 dftEmpty(&input); dftEmpty(&dft); resEmpty(&res);
425 return(8);
426 }
427
428
429 /*
430 * Fit ROIs
431 */
432 if(verbose>0) {
433 fprintf(stdout, "fitting regional TACs: ");
434 if(verbose>1) fprintf(stdout, "\n");
435 }
436 fflush(stdout);
437 for(ri=0; ri<dft.voiNr; ri++) {
438 if(verbose>2) printf("\n %d %s\n", ri, dft.voi[ri].name);
439
440 /* Initiate values */
441 petmeas=dft.voi[ri].y; petsim=fit.voi[ri].y;
442
443 /* Set constraints */
444 for(pi=0; pi<parNr; pi++) {pmin[pi]=def_pmin[pi]; pmax[pi]=def_pmax[pi];}
445 for(pi=fittedparNr=0; pi<parNr; pi++) if(pmax[pi]>pmin[pi]) fittedparNr++;
446 if(ri==0 && verbose>1) {
447 printf(" constraints :=");
448 for(pi=0; pi<parNr; pi++) printf(" [%g,%g]", pmin[pi], pmax[pi]);
449 printf("\n");
450 printf("fittedparNr := %d\n", fittedparNr);
451 }
452
453 /* Fit */
456 tgoNr=60+50*fittedparNr; /* 0, 100 */
457 neighNr=5*fittedparNr; /* 6, 10 */
458 iterNr=0;
459 ret=tgo(
460 pmin, pmax, func2TCMdi, NULL, parNr, neighNr,
461 &wss, res.voi[ri].parameter, tgoNr, iterNr, verbose-8);
462 if(ret>0) {
463 fprintf(stderr, "\nError in optimization (%d).\n", ret);
464 dftEmpty(&input); dftEmpty(&dft); dftEmpty(&fit); resEmpty(&res);
465 return(9);
466 }
467 /* Correct fitted parameters to match constraints like inside function */
468 (void)modelCheckParameters(parNr, pmin, pmax, res.voi[ri].parameter,
469 res.voi[ri].parameter, &f);
470 wss/=f; // remove any penalties from WSS
471
472 /* Bootstrap */
473 if(doBootstrap) {
474 if(verbose>2) printf("\n bootstrapping\n");
475 /* bootstrap changes measured and simulated data, therefore use copies */
476 petmeas=dft.voi[dft.voiNr].y2; petsim=dft.voi[dft.voiNr].y3;
477 if(doSD) sd=res.voi[ri].sd; else sd=NULL;
478 if(doCL) {cl1=res.voi[ri].cl1; cl2=res.voi[ri].cl2;} else cl1=cl2=NULL;
479 ret=bootstrap(
480 0, cl1, cl2, sd,
481 res.voi[ri].parameter, pmin, pmax, fitframeNr,
482 // measured original TAC, not modified
483 dft.voi[ri].y,
484 // fitted TAC, not modified
485 fit.voi[ri].y,
486 // tissue TAC noisy data is written to be used by objf
487 petmeas,
488 parNr, dft.w, func2TCMdi, tmp, verbose-4
489 );
490 if(ret) {
491 fprintf(stderr, "Error in bootstrap: %s\n", tmp);
492 for(pi=0; pi<parNr; pi++) {
493 if(doSD) sd[pi]=nan("");
494 if(doCL) cl1[pi]=cl2[pi]=nan("");
495 }
496 }
497 }
498
499 /* Set results wss */
500 res.voi[ri].parameter[res.parNr-1]=wss;
501
502 /* Set DV or Ki */
503 if(irrev==0) {
504 double k1k2=res.voi[ri].parameter[1];
505 double k3k4=res.voi[ri].parameter[2]/res.voi[ri].parameter[3];
506 res.voi[ri].parameter[res.parNr-2]=k1k2*(1.0+k3k4);
507 } else {
508 double k1=res.voi[ri].parameter[0];
509 double k2=res.voi[ri].parameter[0]/res.voi[ri].parameter[1];
510 double k3=res.voi[ri].parameter[2];
511 res.voi[ri].parameter[res.parNr-2]=k1*k3/(k2+k3);
512 }
513
514 /* done with this region */
515 if(dft.voiNr>2 && verbose==1) {
516 fprintf(stdout, "."); fflush(stdout);}
517
518 } /* next region */
519 if(verbose>0) {fprintf(stdout, "\n"); fflush(stdout);}
520
521 /* Convert Vb fractions to percent's */
522 for(ri=0; ri<res.voiNr; ri++) {
523 res.voi[ri].parameter[parVb]*=100.0;
524 if(!isnan(res.voi[ri].cl1[parVb])) res.voi[ri].cl1[parVb]*=100.;
525 if(!isnan(res.voi[ri].cl2[parVb])) res.voi[ri].cl2[parVb]*=100.;
526 if(!isnan(res.voi[ri].sd[parVb])) res.voi[ri].sd[parVb]*=100.;
527 }
528
529 /* Calculate DV or Ki */
530 for(ri=0; ri<res.voiNr; ri++) {
531 double macrop=0.0;
532 if(irrev==0) {
533 double k1k2=res.voi[ri].parameter[1];
534 double k3k4=res.voi[ri].parameter[2]/res.voi[ri].parameter[3];
535 macrop=k1k2; if(k3k4>0.0) macrop*=(1.0+k3k4);
536 } else {
537 double k1=res.voi[ri].parameter[0];
538 double k2=res.voi[ri].parameter[0]/res.voi[ri].parameter[1];
539 double k3=res.voi[ri].parameter[2];
540 macrop=k1*k3/(k2+k3);
541 }
542 res.voi[ri].parameter[res.parNr-2]=macrop;
543 }
544
545 /*
546 * Print results on screen
547 */
548 if(verbose>0) {resPrint(&res); fprintf(stdout, "\n");}
549
550
551 /*
552 * Save results
553 */
554 if(verbose>1) printf("saving results\n");
555 ret=resWrite(&res, rfile, verbose-3);
556 if(ret) {
557 fprintf(stderr, "Error in writing '%s': %s\n", rfile, reserrmsg);
558 dftEmpty(&dft); dftEmpty(&fit); dftEmpty(&input); resEmpty(&res);
559 return(11);
560 }
561 if(verbose>0) fprintf(stdout, "Model parameters written in %s\n", rfile);
562
563
564 /*
565 * Saving regional metabolite-corrected TACs
566 */
567 if(mcfile[0]) {
568 if(verbose>1) printf("calculating mc curves\n");
569
570 /* Create a duplicate DFT, to not mess up the original or fitted data */
571 DFT dft2;
572 dftInit(&dft2); ret=dftdup(&dft, &dft2);
573 if(ret) {
574 fprintf(stderr, "Error: cannot make mc curves.\n");
575 dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
576 return(31);
577 }
578 dft2.frameNr=fitframeNr;
579
580 /* Simulate total tissue TAC, excluding metabolite in tissue */
581 double K1p, k2p, k3p, k4p, Vb;
582 for(ri=0; ri<dft2.voiNr; ri++) {
583 /* Set necessary parameters */
584 Vb=0.01*res.voi[ri].parameter[parVb];
585 K1p=res.voi[ri].parameter[0];
586 if(res.voi[ri].parameter[1]>0.0) k2p=K1p/res.voi[ri].parameter[1]; else k2p=0.0;
587 k3p=res.voi[ri].parameter[2];
588 k4p=res.voi[ri].parameter[3];
589 /* Simulate */
590 ret=simC4DIvp(
591 input.x, input.voi[0].y, input.voi[1].y, input.voi[2].y, input.frameNr,
592 K1p, k2p, k3p, k4p, 0, 0, 0, 0, 0, 0,
593 0.0, Vb, 1.0, input.voi[0].y2, NULL, NULL, NULL, NULL, NULL, NULL, verbose-20);
594 if(ret) {
595 if(verbose>1) printf("error %d in simulation\n", ret);
596 fprintf(stderr, "Error: cannot calculate metabolite-free curve.\n");
597 dftEmpty(&dft2); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
598 return(32);
599 }
600 /* Interpolate to measured PET frames */
602 ret=interpolate4pet(
603 input.x, input.voi[0].y2, input.frameNr,
604 dft2.x1, dft2.x2, dft2.voi[ri].y, NULL, NULL, dft2.frameNr);
605 else
606 ret=interpolate(
607 input.x, input.voi[0].y2, input.frameNr,
608 dft2.x, dft2.voi[ri].y, NULL, NULL, dft2.frameNr);
609 if(ret) {
610 if(verbose>1) printf("error %d in interpolation\n", ret);
611 fprintf(stderr, "Error: cannot interpolate metabolite-free curve.\n");
612 dftEmpty(&dft2); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
613 return(33);
614 }
615 } // next region
616
617 /* Save metabolite corrected TACs */
618 if(verbose>1) printf("saving mc curves\n");
619 char tmp[64];
620 tpcProgramName(argv[0], 1, 0, tmp, 64);
621 sprintf(dft2.comments, "# program := %s\n", tmp);
622 if(dftWrite(&dft2, mcfile)) {
623 fprintf(stderr, "Error in writing '%s': %s\n", mcfile, dfterrmsg);
624 dftEmpty(&dft2); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
625 return(34);
626 }
627 if(verbose>0) printf("MC TACs written in %s\n", mcfile);
628
629 dftEmpty(&dft2);
630 }
631
632
633 /*
634 * Saving and/or plotting of fitted TACs
635 */
636 if(svgfile[0] || ffile[0]) {
637
638 char tmp[64];
639 fit.frameNr=fitframeNr;
640
641 /* Save SVG plot of fitted and original data */
642 if(svgfile[0]) {
643 if(verbose>1) printf("saving SVG plot\n");
644 sprintf(tmp, "2TCM fit with dual input: ");
645 if(strlen(dft.studynr)>0) strcat(tmp, dft.studynr);
646 ret=plot_fitrange_svg(&dft, &fit, tmp, 0.0, 1.02*dft.x[fitframeNr-1],
647 0.0, nan(""), svgfile, verbose-5);
648 if(ret) {
649 fprintf(stderr, "Error (%d) in writing '%s'.\n", ret, svgfile);
650 dftEmpty(&fit); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
651 return(30+ret);
652 }
653 if(verbose>0) printf("Plots written in %s\n", svgfile);
654 }
655
656 /* Save fitted TACs */
657 if(ffile[0]) {
658 if(verbose>1) printf("saving fitted curves\n");
659 tpcProgramName(argv[0], 1, 0, tmp, 64);
660 sprintf(fit.comments, "# program := %s\n", tmp);
661 if(dftWrite(&fit, ffile)) {
662 fprintf(stderr, "Error in writing '%s': %s\n", ffile, dfterrmsg);
663 dftEmpty(&fit); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
664 return(22);
665 }
666 if(verbose>0) printf("Fitted TACs written in %s\n", ffile);
667 }
668
669 }
670
671 dftEmpty(&dft); dftEmpty(&fit); dftEmpty(&input); resEmpty(&res);
672
673 return(0);
674}
675/*****************************************************************************/
676
677/*****************************************************************************
678 *
679 * Functions to be minimized
680 *
681 *****************************************************************************/
682double func2TCMdi(int parNr, double *p, void *fdata)
683{
684 int fi, ret;
685 double K1p, k2p, k3p, k4p, K1m, k2m, Vb, d, wss=0.0;
686 double pa[MAX_PARAMETERS], penalty=1.0;
687
688
689 /* Check parameters against the constraints */
690 ret=modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
691 if(fdata) {}
692
693 /* Get or calculate actual model parameters */
694 K1p=pa[0]; if(pa[1]>0.0 && K1p>0.0) k2p=K1p/pa[1]; else k2p=0.0;
695 if(k2p>0.0) {
696 k3p=pa[2]; k4p=pa[3]; if(k3p==0.0) k4p=0;
697 } else {
698 k3p=k4p=0.0;
699 }
700 K1m=pa[4]; if(pa[5]>0.0 && K1m>0.0) k2m=K1m/pa[5]; else k2m=0.0;
701 Vb=pa[parVb];
702
703 /* Simulate the tissue PET TAC */
704 ret=simC4DIvp(
705 input.x, input.voi[0].y, input.voi[1].y, input.voi[2].y, input.frameNr,
706 K1p, k2p, k3p, k4p, 0, 0, 0, 0, K1m, k2m,
707 0.0, Vb, 1.0, input.voi[0].y2, NULL, NULL, NULL, NULL, NULL, NULL, 0);
708 if(ret) {
709 printf("error %d in simulation\n", ret);
710 return(nan(""));
711 }
712
713 /* Interpolate & integrate to measured PET frames */
715 ret=interpolate4pet(
716 input.x, input.voi[0].y2, input.frameNr,
717 dft.x1, dft.x2, petsim, NULL, NULL, fitframeNr);
718 else
719 ret=interpolate(
720 input.x, input.voi[0].y2, input.frameNr,
721 dft.x, petsim, NULL, NULL, fitframeNr);
722 if(ret) {
723 printf("error %d in interpolation\n", ret);
724 return(nan(""));
725 }
726
727 /* Calculate error */
728 for(fi=0; fi<fitframeNr; fi++) if(dft.w[fi]>0.0) {
729 d=petmeas[fi]-petsim[fi];
730 wss+=dft.w[fi]*d*d;
731 }
732 wss*=penalty;
733 if(0) printf("%g %g %g %g %g => %g\n", K1p, k2p, K1m, k2m,Vb,wss);
734
735 return(wss);
736}
737/*****************************************************************************/
738
739/*****************************************************************************/
int bootstrap(int iterNr, double *cLim1, double *cLim2, double *SD, double *parameter, double *lowlim, double *uplim, int frameNr, double *origTac, double *fitTac, double *bsTac, int parNr, double *weight, double(*objf)(int, double *, void *), char *status, int verbose)
Definition bootstrap.c:55
int modelCheckParameters(int par_nr, double *lower_p, double *upper_p, double *test_p, double *accept_p, double *penalty)
Definition constraints.c:15
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
int dftAddmem(DFT *dft, int voiNr)
Definition dft.c:107
void dftEmpty(DFT *data)
Definition dft.c:20
int dftReadModelingData(char *tissuefile, char *inputfile1, char *inputfile2, char *inputfile3, double *fitdur, int *fitframeNr, DFT *tis, DFT *inp, FILE *loginfo, int verbose, char *status)
Definition dftinput.c:342
void dftPrint(DFT *data)
Definition dftio.c:538
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
int res_allocate_with_dft(RES *res, DFT *dft)
Definition dftres.c:14
int iftPutDouble(IFT *ift, char *key, double value, char *cmt_type, int verbose)
Definition ift.c:145
int iftPut(IFT *ift, char *key, char *value, char *cmt_type, int verbose)
Definition ift.c:82
void iftEmpty(IFT *ift)
Definition ift.c:60
void iftInit(IFT *ift)
Definition ift.c:45
int iftRead(IFT *ift, char *filename, int is_key_required, int verbose)
Definition iftfile.c:24
int iftWrite(IFT *ift, char *filename, int verbose)
Definition iftfile.c:282
int iftGetDoubleValue(IFT *ift, int si, const char *key, double *value, int verbose)
Definition iftsrch.c:268
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.
char reserrmsg[64]
Definition result.c:6
void resInit(RES *res)
Definition result.c:52
void resPrint(RES *res)
Definition result.c:186
int resWrite(RES *res, char *filename, int verbose)
Definition result.c:565
#define DFT_TIME_STARTEND
void resEmpty(RES *res)
Definition result.c:22
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
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
Definition proginfo.c:101
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 simC4DIvp(double *t, double *ca1, double *ca2, double *cb, int nr, double k1, double k2, double k3, double k4, double k5, double k6, double k7, double km, double k1b, double k2b, double f, double vb, double fa, double *scpet, double *sct1, double *sct2, double *sct3, double *sct1b, double *sctab, double *sctvb, int verbose)
Definition simulate.c:1533
int tgo(double *lowlim, double *uplim, double(*objf)(int, double *, void *), void *objfData, int dim, int neighNr, double *fmin, double *gmin, int samNr, int tgoNr, int verbose)
Definition tgo.c:39
int TGO_LOCAL_INSIDE
Definition tgo.c:29
#define MAX_PARAMETERS
Definition libtpcmodel.h:31
int TGO_SQUARED_TRANSF
Definition tgo.c:27
Header file for libtpcmodext.
int plot_fitrange_svg(DFT *dft1, DFT *dft2, char *main_title, double x1, double x2, double y1, double y2, char *fname, int verbose)
Definition plotfit.c:16
Header file for libtpcsvg.
int timetype
Voi * voi
int timeunit
char studynr[MAX_STUDYNR_LEN+1]
double * w
double * x1
char comments[_DFT_COMMENT_LEN+1]
int voiNr
double * x2
int frameNr
int isweight
double * x
const char * status
Definition libtpcmisc.h:277
char plasmafile2[FILENAME_MAX]
int parNr
char parname[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
int voiNr
int datanr
ResVOI * voi
double Vb
char program[1024]
char plasmafile[FILENAME_MAX]
char datarange[128]
int isweight
char datafile[FILENAME_MAX]
char fitmethod[128]
char parunit[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
char bloodfile[FILENAME_MAX]
time_t time
double parameter[MAX_RESPARAMS]
double cl2[MAX_RESPARAMS]
double cl1[MAX_RESPARAMS]
double sd[MAX_RESPARAMS]
double * y2
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
char name[MAX_REGIONNAME_LEN+1]
double * y3