TPCCLIB
Loading...
Searching...
No Matches
fitk2di.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 labeled metabolite):",
29 " ",
30 " _____ K1p _____ ",
31 " | Cap | ----> | Ctp | ",
32 " |_____| <---- |_____| ",
33 " k2p | ",
34 " km| ",
35 " v ",
36 " _____ K1m _____ ",
37 " | Cam | ----> | Ctm | ",
38 " |_____| <---- |_____| ",
39 " k2m ",
40 " ",
41 "Sample times must be in minutes.",
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 " -ref=<Reference region name or filename>",
63 " Specified reference region is fitted using different set of model",
64 " parameter constraints; not necessary if reference region is given",
65 " with one of the following options -BPnd, -BPp, or -DVR.",
66 " -<BPnd|BPp|DVR>=<Reference region name or filename>",
67 " Optional reference region is used to calculate BPnd, BPp, or DVR;",
68 " BPnd=DVroi/DVref-1, BPp=DVroi-DVref, and DVR=DVroi/DVref",
69 " -refVfm=refVfp",
70 " In reference region Vfm is set to equal Vfp.",
71 " -mc=<Filename>",
72 " Fit-based metabolite corrected regional TACs are written in the file.",
73 " -fit=<Filename>",
74 " Fitted regional TACs are written in the file.",
75 " -svg=<Filename>",
76 " Fitted and measured TACs are plotted in specified SVG file.",
77 " -stdoptions", // List standard options like --help, -v, etc
78 " ",
79 "Example 1: fitting with default settings",
80 " @P ia919apc.kbq ia919apm.kbq ia919ab.kbq ia919.dft 60 a919k2di.res",
81 " ",
82 "Example 2: Vb is constrained to 0%; DVRs are calculated by dividing DVs",
83 "by the DV of region 'cer'",
84 " @P -Vb=0 -R=cer p25apc.bld p25apm.bld none p25.tac 60 p25k2di.res",
85 " ",
86 "See also: fitk2, fitk4di, logan, fitk4, p2t_di, tacweigh, taccbv",
87 " ",
88 "Keywords: TAC, modelling, distribution volume, reversible uptake, dual-input",
89 0};
90/*****************************************************************************/
91
92/*****************************************************************************/
93/* Turn on the globbing of the command line, since it is disabled by default in
94 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
95 In Unix&Linux wildcard command line processing is enabled by default. */
96/*
97#undef _CRT_glob
98#define _CRT_glob -1
99*/
100int _dowildcard = -1;
101/*****************************************************************************/
102
103/*****************************************************************************/
104const int parNr=6, parVb=5;
105DFT input, dft, fit;
106double *petmeas, *petsim;
107double fVb=-1.0;
108int is_this_ref=0;
109int fixed_ref_Vfm_eq_Vfp=0; // If <>0 then Ref region Vfm = Ref region Vfp
110double pmin[MAX_PARAMETERS], pmax[MAX_PARAMETERS];
111int fitframeNr;
112// Parameter names in the limit file and in actual fitting
113static char *parName[] = {"K1p", "Vfp", "R1m", "Vfm", "km", "Vb", 0};
114/*****************************************************************************/
115/* Local functions */
116double func1TCMdi(int parNr, double *p, void*);
117/*****************************************************************************/
118
119/*****************************************************************************/
123int main(int argc, char **argv)
124{
125 int ai, help=0, version=0, verbose=1;
126 int ri, fi, pi, n, ret;
127 int ref=-1, refAdded=0, inputtype;
128 int bp_type=0; // 0=no, 1=DVR, 2=BPnd, 3=BPp
129 char dfile[FILENAME_MAX], bfile[FILENAME_MAX],
130 pfile[FILENAME_MAX], mfile[FILENAME_MAX],
131 rfile[FILENAME_MAX], ffile[FILENAME_MAX],
132 mcfile[FILENAME_MAX],
133 limfile[FILENAME_MAX], svgfile[FILENAME_MAX];
134 char refname[FILENAME_MAX];
135 char *cptr, tmp[FILENAME_MAX];
136 double f, fitdur, wss;
137 RES res;
138 int doBootstrap=0, doSD=0, doCL=0; // 0=no, 1=yes
139 double *sd, *cl1, *cl2;
140 double def_pmin[MAX_PARAMETERS], def_pmax[MAX_PARAMETERS];
141 double def_pmin_ref[MAX_PARAMETERS], def_pmax_ref[MAX_PARAMETERS];
142 int tgoNr=0, neighNr=0, iterNr=0, fittedparNr=0;
143
144
145 /* Set parameter initial values and constraints */
146 /* K1p */ def_pmin[0]=0.0; def_pmax[0]=10.0;
147 /* Vfp=K1p/k2p */ def_pmin[1]=0.0; def_pmax[1]=500.0;
148 /* R1m=K1m/K1p */ def_pmin[2]=0.0; def_pmax[2]=10.0;
149 /* Vfm=K1m/k2m */ def_pmin[3]=0.0; def_pmax[3]=10.0;
150 /* km */ def_pmin[4]=0.0; def_pmax[4]=0.0;
151 /* Vb */ def_pmin[5]=0.0; def_pmax[5]=0.10;
152 /* Same for possible reference region */
153 /* K1p */ def_pmin_ref[0]=0.0; def_pmax_ref[0]=10.0;
154 /* Vfp=K1p/k2p */ def_pmin_ref[1]=0.0; def_pmax_ref[1]=2.0;
155 /* R1m=K1m/K1p */ def_pmin_ref[2]=0.0; def_pmax_ref[2]=10.0;
156 /* Vfm=K1m/k2m */ def_pmin_ref[3]=0.0; def_pmax_ref[3]=2.0;
157 /* km */ def_pmin_ref[4]=0.0; def_pmax_ref[4]=0.0;
158 /* Vb */ def_pmin_ref[5]=0.0; def_pmax_ref[5]=0.10;
159
160
161 /*
162 * Get arguments
163 */
164 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
165 dfile[0]=pfile[0]=mfile[0]=bfile[0]=refname[0]=(char)0;
166 rfile[0]=ffile[0]=limfile[0]=svgfile[0]=mcfile[0]=(char)0;
167 fitdur=fVb=-1.0;
168 resInit(&res); dftInit(&input); dftInit(&dft); dftInit(&fit);
169 /* Get options first, because it may affect what arguments are read */
170 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
171 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
172 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
173 if(strncasecmp(cptr, "CL", 2)==0) {
174 if(strlen(cptr)==2) {doCL=1; continue;}
175 cptr+=2; if(*cptr=='=') {
176 cptr++;
177 if(*cptr=='Y' || *cptr=='y') {doCL=1; continue;}
178 if(*cptr=='N' || *cptr=='n') {doCL=0; continue;}
179 }
180 } else if(strncasecmp(cptr, "SD", 2)==0) {
181 if(strlen(cptr)==2) {doSD=1; continue;}
182 cptr+=2; if(*cptr=='=') {
183 cptr++;
184 if(*cptr=='Y' || *cptr=='y') {doSD=1; continue;}
185 if(*cptr=='N' || *cptr=='n') {doSD=0; continue;}
186 }
187 } else if(strncasecmp(cptr, "LIM=", 4)==0 && strlen(cptr)>4) {
188 strlcpy(limfile, cptr+4, FILENAME_MAX); continue;
189 } else if(strcasecmp(cptr, "LIM")==0) {
190 strcpy(limfile, "stdout"); continue;
191 } else if(strncasecmp(cptr, "Vb=", 3)==0 && strlen(cptr)>3) {
192 fVb=0.01*atof_dpi(cptr+3);
193 if(fVb>=0.0 && fVb<1.0) {
194 if(fVb<0.01) fprintf(stderr, "Warning: Vb was set to %g%%\n", 100.*fVb);
195 def_pmin[parVb]=def_pmax[parVb]=fVb;
196 def_pmin_ref[parVb]=def_pmax_ref[parVb]=fVb;
197 continue;
198 }
199 fVb=-1.0;
200 } else if(strncasecmp(cptr, "REF=", 4)==0) {
201 strlcpy(refname, cptr+4, FILENAME_MAX); if(strlen(refname)>0.0) continue;
202 } else if(strncasecmp(cptr, "DVR=", 4)==0) {
203 bp_type=1; strlcpy(refname, cptr+4, FILENAME_MAX);
204 if(strlen(refname)>0.0) continue;
205 } else if(strncasecmp(cptr, "BPnd=", 5)==0) {
206 bp_type=2; strlcpy(refname, cptr+5, FILENAME_MAX);
207 if(strlen(refname)>0.0) continue;
208 } else if(strncasecmp(cptr, "BPp=", 4)==0) {
209 bp_type=3; strlcpy(refname, cptr+4, FILENAME_MAX);
210 if(strlen(refname)>0.0) continue;
211 } else if(strcasecmp(cptr, "refVfm=refVfp")==0) {
212 fixed_ref_Vfm_eq_Vfp=1; continue;
213 } else if(strncasecmp(cptr, "MC=", 3)==0) {
214 strlcpy(mcfile, cptr+3, FILENAME_MAX); if(strlen(mcfile)>0) continue;
215 } else if(strncasecmp(cptr, "FIT=", 4)==0) {
216 strlcpy(ffile, cptr+4, FILENAME_MAX); if(strlen(ffile)>0) continue;
217 } else if(strncasecmp(cptr, "SVG=", 4)==0) {
218 strlcpy(svgfile, cptr+4, FILENAME_MAX); if(strlen(svgfile)>0) continue;
219 }
220 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
221 return(1);
222 }
223
224
225 /* Print help or version? */
226 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
227 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
228 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
229
230 /* Process other arguments, starting from the first non-option */
231 for(ai=1; ai<argc; ai++) if(*argv[ai]!='-') {
232 if(!pfile[0]) {strlcpy(pfile, argv[ai], FILENAME_MAX); continue;}
233 else if(!mfile[0]) {strlcpy(mfile, argv[ai], FILENAME_MAX); continue;}
234 else if(!bfile[0]) {strlcpy(bfile, argv[ai], FILENAME_MAX); continue;}
235 else if(!dfile[0]) {strlcpy(dfile, argv[ai], FILENAME_MAX); continue;}
236 else if(fitdur<0) {fitdur=atof_dpi(argv[ai]); if(fitdur>0.0) continue;}
237 else if(!rfile[0]) {strlcpy(rfile, argv[ai], FILENAME_MAX); continue;}
238 /* we should never get this far */
239 fprintf(stderr, "Error: too many arguments: '%s'.\n", argv[ai]);
240 return(1);
241 }
242 if(doSD || doCL) doBootstrap=1; else doBootstrap=0;
243 /* User may not have blood file, and has entered 'none' instead */
244 if(strcasecmp(bfile, "NONE")==0) {strcpy(bfile, ""); fVb=0.0;}
245
246 /* If only filename for initial values was given, then write one
247 with default contents and exit */
248 if(limfile[0] && !pfile[0]) {
249 /* Check that initial value file does not exist */
250 if(strcasecmp(limfile, "stdout")!=0 && access(limfile, 0) != -1) {
251 fprintf(stderr, "Error: parameter constraint file %s exists.\n", limfile);
252 return(9);
253 }
254 if(verbose>1) printf("writing parameter constraints file\n");
255 IFT ift; iftInit(&ift);
256 /* Create parameter file */
257 for(pi=0; pi<parNr; pi++) {
258 sprintf(tmp, "%s_lower", parName[pi]);
259 iftPutDouble(&ift, tmp, def_pmin[pi], NULL, 0);
260 sprintf(tmp, "%s_upper", parName[pi]);
261 iftPutDouble(&ift, tmp, def_pmax[pi], NULL, 0);
262 }
263 for(pi=0; pi<parNr; pi++) {
264 sprintf(tmp, "ref_%s_lower", parName[pi]);
265 iftPutDouble(&ift, tmp, def_pmin_ref[pi], NULL, 0);
266 sprintf(tmp, "ref_%s_upper", parName[pi]);
267 iftPutDouble(&ift, tmp, def_pmax_ref[pi], NULL, 0);
268 }
269 if((ret=iftWrite(&ift, limfile, 0))!=0) {
270 fprintf(stderr, "Error in writing '%s': %s\n", limfile, ift.status);
271 iftEmpty(&ift); return(9);
272 }
273 if(strcasecmp(limfile, "stdout")!=0) fprintf(stdout,
274 "Parameter file %s with initial values written.\n", limfile);
275 iftEmpty(&ift); return(0);
276 }
277
278 /* Did we get all the information from user that we need? */
279 if(fitdur==0) fitdur=1.0E+100;
280 else if(fitdur<0) {tpcPrintUsage(argv[0], info, stderr); return(1);}
281 if(!rfile[0]) {
282 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
283 return(1);
284 }
285
286 /* In verbose mode print arguments and options */
287 if(verbose>1) {
288 printf("pfile := %s\n", pfile);
289 printf("mfile := %s\n", mfile);
290 printf("dfile :=%s\n", dfile);
291 printf("rfile := %s\n", rfile);
292 printf("mcfile := %s\n", mcfile);
293 printf("ffile := %s\n", ffile);
294 printf("svgfile := %s\n", svgfile);
295 printf("limfile := %s\n", limfile);
296 printf("bp_type := %d\n", bp_type);
297 printf("refname := %s\n", refname);
298 printf("fitdur := %g\n", fitdur);
299 printf("doBootstrap := %d\n", doBootstrap);
300 printf("doSD := %d\n", doSD);
301 printf("doCL := %d\n", doCL);
302 printf("fixed_ref_Vfm_eq_Vfp := %d\n", fixed_ref_Vfm_eq_Vfp);
303 }
304
305
306 /*
307 * Read model parameter initial values and upper and lower limits
308 * if file for that was given
309 */
310 if(limfile[0]) {
311 IFT ift; iftInit(&ift);
312 double v;
313 if(verbose>1) printf("reading %s\n", limfile);
314 ret=iftRead(&ift, limfile, 1, 0);
315 if(ret) {
316 fprintf(stderr, "Error in reading '%s': %s\n", limfile, ift.status);
317 return(9);
318 }
319 if(verbose>10) iftWrite(&ift, "stdout", 0);
320 int n=0;
321 for(pi=0; pi<parNr; pi++) {
322 sprintf(tmp, "%s_lower", parName[pi]);
323 if(iftGetDoubleValue(&ift, 0, tmp, &v, 0)>=0) {def_pmin[pi]=v; n++;}
324 sprintf(tmp, "%s_upper", parName[pi]);
325 if(iftGetDoubleValue(&ift, 0, tmp, &v, 0)>=0) {def_pmax[pi]=v; n++;}
326 }
327 for(pi=0; pi<parNr; pi++) {
328 sprintf(tmp, "ref_%s_lower", parName[pi]);
329 if(iftGetDoubleValue(&ift, 0, tmp, &v, 0)>=0) {def_pmin_ref[pi]=v; n++;}
330 sprintf(tmp, "ref_%s_upper", parName[pi]);
331 if(iftGetDoubleValue(&ift, 0, tmp, &v, 0)>=0) {def_pmax_ref[pi]=v; n++;}
332 }
333 iftEmpty(&ift);
334 if(n==0) {fprintf(stderr, "Error: invalid parameter file.\n"); return(9);}
335 }
336 /* Refine constraints based on command-line options */
337 if(fixed_ref_Vfm_eq_Vfp!=0) {
338 def_pmax_ref[3]=def_pmin_ref[3]=0.0;
339 }
340 /* Check that these are ok */
341 for(pi=n=0, ret=0; pi<parNr; pi++) {
342 if(def_pmin[pi]<0.0) ret++;
343 if(def_pmax[pi]<def_pmin[pi]) ret++;
344 if(def_pmax[pi]>def_pmin[pi]) n++;
345 }
346 if(ret>0) {
347 fprintf(stderr, "Error: invalid parameter constraints.\n");
348 return(9);
349 }
350 if(n==0) {
351 fprintf(stderr, "Error: no model parameters left free for fitting.\n");
352 return(9);
353 }
354 /* The same for reference region */
355 for(pi=n=0, ret=0; pi<parNr; pi++) {
356 if(def_pmin_ref[pi]<0.0) ret++;
357 if(def_pmax_ref[pi]<def_pmin_ref[pi]) ret++;
358 if(def_pmax_ref[pi]>def_pmin_ref[pi]) n++;
359 }
360 if(ret>0) {
361 fprintf(stderr, "Error: invalid reference region parameter constraints.\n");
362 return(9);
363 }
364 if(n==0) {
365 fprintf(stderr, "Error: no ref model parameters left free for fitting.\n");
366 return(9);
367 }
368
369 /* Fixed/fitted Vb */
370 if(fVb>=0.0)
371 def_pmin[parVb]=def_pmax[parVb]=def_pmin_ref[parVb]=def_pmax_ref[parVb]=fVb;
372 if(def_pmin[parVb]==def_pmax[parVb]) fVb=def_pmin[parVb];
373 if(fVb==0.0) strcpy(bfile, "");
374 if(verbose>1) {
375 printf("bfile := %s\n", bfile);
376 //if(fVb>=0.0) printf("fVb := %g\n", fVb);
377 }
378
379
380 /*
381 * Read tissue and input data
382 */
383 if(verbose>1) printf("reading tissue and input data\n");
384 ret=dftReadModelingData(dfile, pfile, mfile, bfile, &fitdur,
385 &fitframeNr, &dft, &input, stdout, verbose-2, tmp);
386 if(ret!=0) {
387 fprintf(stderr, "Error: %s\n", tmp);
388 dftEmpty(&dft); dftEmpty(&input); return(2);
389 }
390 if(fitframeNr<parNr+1 || input.frameNr<parNr+1) {
391 fprintf(stderr, "Error: too few samples in specified fit duration.\n");
392 dftEmpty(&input); dftEmpty(&dft); return(2);
393 }
394 if(input.voiNr<2) {
395 fprintf(stderr, "Error: valid plasma TACs must be provided.\n");
396 dftEmpty(&input); dftEmpty(&dft); return(2);
397 }
398 /* If there is no blood TAC, then create a zero blood TAC */
399 if(input.voiNr<3) {
400 if(verbose>2) printf("setting blood tac to zero\n");
401 ret=dftAddmem(&input, 1);
402 if(ret) {
403 fprintf(stderr, "Error: cannot allocate more memory.\n");
404 dftEmpty(&dft); dftEmpty(&input); return(3);
405 }
406 strcpy(input.voi[2].voiname, "blood");
407 for(fi=0; fi<input.frameNr; fi++) input.voi[2].y[fi]=0.0;
408 input.voiNr=3;
409 /* and make sure that Vb=0 */
410 def_pmin[parVb]=def_pmax[parVb]=fVb=0.0;
411 def_pmin_ref[parVb]=def_pmax_ref[parVb]=0.0;
412 }
413 if(verbose>1) {
414 if(fVb>=0.0) printf("fVb := %g\n", fVb);
415 }
416 if(verbose>10) dftPrint(&dft);
417 if(verbose>10) dftPrint(&input);
418 /* Print the weights */
419 if(verbose>2) {
420 fprintf(stdout, "common_data_weights := %g", dft.w[0]);
421 for(fi=1; fi<dft.frameNr; fi++) fprintf(stdout, ", %g", dft.w[fi]);
422 fprintf(stdout, "\n");
423 }
424
425
426 /*
427 * Read reference TAC
428 */
429 /* Check if user even wants any reference region */
430 if(!refname[0]) {
431 if(verbose>1) printf("no reference region data\n");
432 ref=-1;
433 } else {
434 if(verbose>1) printf("reading reference region data\n");
435 if((n=dftReadReference(&dft, refname, &inputtype, &ref, tmp, verbose-3))<1)
436 {
437 fprintf(stderr, "Error in reading '%s': %s\n", refname, tmp);
438 if(verbose>2) printf("dftReadReference()=%d\n", n);
439 dftEmpty(&dft); dftEmpty(&input); return(6);
440 }
441 if(verbose>30) dftPrint(&dft);
442 if(n>1)
443 fprintf(stderr, "Warning: %s selected of %d reference regions.\n", dft.voi[ref].name, n);
444 if(verbose>1)
445 fprintf(stdout, "selected reference region := %s\n", dft.voi[ref].name);
446 if(inputtype==5) { // Reference region name was given
447 refAdded=0; strcpy(refname, "");
448 } else { // reference file was given; ref TACs may have to be deleted later
449 refAdded=1;
450 }
451 if(verbose>15) dftPrint(&dft);
452 if(verbose>1) printf("Reference region: %s\n", dft.voi[ref].name );
453 }
454
455 /* Allocate an extra TAC for the bootstrap */
456 if(doBootstrap) {
457 ret=dftAddmem(&dft, 1); if(ret) {
458 fprintf(stderr, "Error: cannot allocate more memory.\n");
459 dftEmpty(&dft); dftEmpty(&input); return(9);
460 }
461 strcpy(dft.voi[dft.voiNr].voiname, "BS");
462 strcpy(dft.voi[dft.voiNr].name, "BS");
463 }
464 if(verbose>10) dftPrint(&dft);
465
466
467 /*
468 * Prepare the room for the results
469 */
470 if(verbose>1) printf("initializing result data\n");
471 ret=res_allocate_with_dft(&res, &dft); if(ret!=0) {
472 fprintf(stderr, "Error: cannot setup memory for results.\n");
473 dftEmpty(&input); dftEmpty(&dft); return(7);
474 }
475 /* Copy titles & file names */
476 tpcProgramName(argv[0], 1, 1, res.program, 256);
477 strcpy(res.datafile, dfile);
478 strcpy(res.plasmafile, pfile);
479 strcpy(res.plasmafile2, mfile);
480 strcpy(res.bloodfile, bfile);
481 if(ref>=0) sprintf(res.refroi, "%s", dft.voi[ref].name);
482 if(refname[0]) strcpy(res.reffile, refname);
483 strcpy(res.fitmethod, "TGO");
484 /* Constants */
485 if(fVb>=0.0) res.Vb=100.0*fVb; else res.Vb=-1.0;
486 res.isweight=dft.isweight;
487 /* Set data range */
488 sprintf(res.datarange, "%g - %g %s", 0.0, fitdur, dftTimeunit(dft.timeunit));
489 res.datanr=fitframeNr;
490 /* Set current time to results */
491 res.time=time(NULL);
492 /* Set parameter number, including also the extra "parameters"
493 and the parameter names and units */
494 res.parNr=parNr+1; if(bp_type>0) res.parNr++;
495 pi=0; strcpy(res.parname[pi], "K1p"); strcpy(res.parunit[pi], "ml/(min*ml)");
496 pi++; strcpy(res.parname[pi], "K1p/k2p"); strcpy(res.parunit[pi], "ml/ml");
497 pi++; strcpy(res.parname[pi], "K1m/K1p"); strcpy(res.parunit[pi], "");
498 pi++; strcpy(res.parname[pi], "K1m/k2m"); strcpy(res.parunit[pi], "ml/ml");
499 pi++; strcpy(res.parname[pi], "km"); strcpy(res.parunit[pi], "1/min");
500 pi++; strcpy(res.parname[pi], "Vb"); strcpy(res.parunit[pi], "%");
501 if(bp_type>0) {
502 pi++;
503 if(bp_type==1) {
504 strcpy(res.parname[pi], "DVR"); strcpy(res.parunit[pi], "ml/ml");
505 } else if(bp_type==2) {
506 strcpy(res.parname[pi], "BPnd"); strcpy(res.parunit[pi], "");
507 } else {strcpy(res.parname[pi], "BPp"); strcpy(res.parunit[pi], "");}
508 }
509 pi++; strcpy(res.parname[pi], "WSS"); strcpy(res.parunit[pi], "");
510
511 /*
512 * Allocate memory for fitted curves
513 */
514 ret=dftdup(&dft, &fit);
515 if(ret) {
516 fprintf(stderr, "Error %d in memory allocation for fitted curves.\n", ret);
517 dftEmpty(&input); dftEmpty(&dft); resEmpty(&res);
518 return(8);
519 }
520
521
522 /*
523 * Fit ROIs
524 */
525 if(verbose>0) {
526 fprintf(stdout, "fitting regional TACs: ");
527 if(verbose>1) fprintf(stdout, "\n");
528 }
529 fflush(stdout);
530 for(ri=0; ri<dft.voiNr; ri++) {
531 if(verbose>2) printf("\n %d %s\n", ri, dft.voi[ri].name);
532
533 /* Initiate values */
534 petmeas=dft.voi[ri].y; petsim=fit.voi[ri].y;
535
536 /* Set constraints */
537 if(ri!=ref) {
538 is_this_ref=0;
539 for(pi=0; pi<parNr; pi++) {pmin[pi]=def_pmin[pi]; pmax[pi]=def_pmax[pi];}
540 } else {
541 is_this_ref=1; if(verbose>2) printf("\n this is reference region\n");
542 for(pi=0; pi<parNr; pi++) {
543 pmin[pi]=def_pmin_ref[pi]; pmax[pi]=def_pmax_ref[pi];}
544 }
545 for(pi=fittedparNr=0; pi<parNr; pi++) if(pmax[pi]>pmin[pi]) fittedparNr++;
546 if(ri==0 && verbose>1) {
547 printf(" constraints :=");
548 for(pi=0; pi<parNr; pi++) printf(" [%g,%g]", pmin[pi], pmax[pi]);
549 printf("\n");
550 printf("fittedparNr := %d\n", fittedparNr);
551 }
552
553 /* Fit */
556 tgoNr=60+30*fittedparNr; /* 0, 100 */
557 neighNr=6*fittedparNr; /* 6, 10 */
558 iterNr=0;
559 ret=tgo(
560 pmin, pmax, func1TCMdi, NULL, parNr, neighNr,
561 &wss, res.voi[ri].parameter, tgoNr, iterNr, verbose-8);
562 if(ret>0) {
563 fprintf(stderr, "\nError in optimization (%d).\n", ret);
564 dftEmpty(&input); dftEmpty(&dft); dftEmpty(&fit); resEmpty(&res);
565 return(9);
566 }
567 /* Correct fitted parameters to match constraints like inside function */
568 (void)modelCheckParameters(parNr, pmin, pmax, res.voi[ri].parameter,
569 res.voi[ri].parameter, &f);
570 wss/=f; // remove any penalties from WSS
571
572 /* Bootstrap */
573 if(doBootstrap) {
574 if(verbose>2) printf("\n bootstrapping\n");
575 /* bootstrap changes measured and simulated data, therefore use copies */
576 petmeas=dft.voi[dft.voiNr].y2; petsim=dft.voi[dft.voiNr].y3;
577 if(doSD) sd=res.voi[ri].sd; else sd=NULL;
578 if(doCL) {cl1=res.voi[ri].cl1; cl2=res.voi[ri].cl2;} else cl1=cl2=NULL;
579 ret=bootstrap(
580 0, cl1, cl2, sd,
581 res.voi[ri].parameter, pmin, pmax, fitframeNr,
582 // measured original TAC, not modified
583 dft.voi[ri].y,
584 // fitted TAC, not modified
585 fit.voi[ri].y,
586 // tissue TAC noisy data is written to be used by objf
587 petmeas,
588 parNr, dft.w, func1TCMdi, tmp, verbose-4
589 );
590 if(ret) {
591 fprintf(stderr, "Error in bootstrap: %s\n", tmp);
592 for(pi=0; pi<parNr; pi++) {
593 if(doSD) sd[pi]=nan("");
594 if(doCL) cl1[pi]=cl2[pi]=nan("");
595 }
596 }
597 }
598
599 /* Set fixed parameter values */
600 if(is_this_ref && fixed_ref_Vfm_eq_Vfp!=0) {
601 res.voi[ri].parameter[3]=res.voi[ri].parameter[1];
602 }
603
604 /* Set results wss */
605 res.voi[ri].parameter[res.parNr-1]=wss;
606
607 /* done with this region */
608 if(dft.voiNr>2 && verbose==1) {fprintf(stdout, "."); fflush(stdout);}
609
610 } /* next region */
611 if(verbose>0) {fprintf(stdout, "\n"); fflush(stdout);}
612
613 /* Convert Vb fractions to percent's */
614 for(ri=0; ri<res.voiNr; ri++){
615 res.voi[ri].parameter[parVb]*=100.0;
616 if(!isnan(res.voi[ri].cl1[parVb])) res.voi[ri].cl1[parVb]*=100.;
617 if(!isnan(res.voi[ri].cl2[parVb])) res.voi[ri].cl2[parVb]*=100.;
618 if(!isnan(res.voi[ri].sd[parVb])) res.voi[ri].sd[parVb]*=100.;
619 }
620 /* Calculate DVR, BPnd or BPp */
621 if(bp_type==1 || bp_type==2) {
622 if(fabs(res.voi[ref].parameter[1])>1.0E-10)
623 for(ri=0; ri<res.voiNr; ri++) {
624 res.voi[ri].parameter[res.parNr-2]=
625 res.voi[ri].parameter[1]/res.voi[ref].parameter[1];
626 if(bp_type==2) res.voi[ri].parameter[res.parNr-2]-=1.0;
627 }
628 else
629 for(ri=0; ri<res.voiNr; ri++)
630 res.voi[ri].parameter[res.parNr-2]=0.0;
631 }
632 if(bp_type==3) {
633 for(ri=0; ri<res.voiNr; ri++)
634 res.voi[ri].parameter[res.parNr-2]=
635 res.voi[ri].parameter[1]-res.voi[ref].parameter[1];
636 }
637 /*
638 * Print results on screen
639 */
640 if(verbose>0) {resPrint(&res); fprintf(stdout, "\n");}
641
642
643 /*
644 * Save results
645 */
646 if(verbose>1) printf("saving results\n");
647 ret=resWrite(&res, rfile, verbose-3);
648 if(ret) {
649 fprintf(stderr, "Error in writing '%s': %s\n", rfile, reserrmsg);
650 dftEmpty(&dft); dftEmpty(&fit); dftEmpty(&input); resEmpty(&res);
651 return(11);
652 }
653 if(verbose>0) fprintf(stdout, "Model parameters written in %s\n", rfile);
654
655
656 /*
657 * Saving regional metabolite-corrected TACs
658 */
659 if(mcfile[0]) {
660 if(verbose>1) printf("calculating mc curves\n");
661
662 /* Create a duplicate DFT, to not mess up the original or fitted data */
663 DFT dft2;
664 dftInit(&dft2); ret=dftdup(&dft, &dft2);
665 if(ret) {
666 fprintf(stderr, "Error: cannot make mc curves.\n");
667 dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
668 return(31);
669 }
670 dft2.frameNr=fitframeNr;
671
672 /* Simulate total tissue TAC, excluding metabolite in tissue */
673 double K1p, k2p, K1m, k2m, km, Vb;
674 for(ri=0; ri<dft2.voiNr; ri++) {
675 /* Set necessary parameters */
676 Vb=0.01*res.voi[ri].parameter[parVb];
677 K1p=res.voi[ri].parameter[0];
678 if(res.voi[ri].parameter[1]>0.0) k2p=K1p/res.voi[ri].parameter[1];
679 else k2p=0.0;
680 K1m=res.voi[ri].parameter[2]*res.voi[ri].parameter[0];
681 if(res.voi[ri].parameter[3]>0.0) k2m=K1m/res.voi[ri].parameter[3];
682 else k2m=0.0;
683 km=res.voi[ri].parameter[4];
684 /* Simulate */
685 ret=simC4DIvp(
686 input.x, input.voi[0].y, input.voi[1].y, input.voi[2].y, input.frameNr,
687 K1p, k2p, 0, 0, 0, 0, 0, km, K1m, k2m,
688 0.0, Vb, 1.0, input.voi[0].y2, NULL, NULL, NULL, NULL, NULL, NULL,
689 verbose-20);
690 if(ret) {
691 if(verbose>1) printf("error %d in simulation\n", ret);
692 fprintf(stderr, "Error: cannot calculate metabolite-free curve.\n");
693 dftEmpty(&dft2); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
694 return(32);
695 }
696 /* Interpolate to measured PET frames */
698 ret=interpolate4pet(
699 input.x, input.voi[0].y2, input.frameNr,
700 dft2.x1, dft2.x2, dft2.voi[ri].y, NULL, NULL, dft2.frameNr);
701 else
702 ret=interpolate(
703 input.x, input.voi[0].y2, input.frameNr,
704 dft2.x, dft2.voi[ri].y, NULL, NULL, dft2.frameNr);
705 if(ret) {
706 if(verbose>1) printf("error %d in interpolation\n", ret);
707 fprintf(stderr, "Error: cannot interpolate metabolite-free curve.\n");
708 dftEmpty(&dft2); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
709 return(33);
710 }
711 } // next region
712
713 /* Save metabolite corrected TACs */
714 if(verbose>1) printf("saving mc curves\n");
715 char tmp[64];
716 tpcProgramName(argv[0], 1, 0, tmp, 64);
717 sprintf(dft2.comments, "# program := %s\n", tmp);
718 if(dftWrite(&dft2, mcfile)) {
719 fprintf(stderr, "Error in writing '%s': %s\n", mcfile, dfterrmsg);
720 dftEmpty(&dft2); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
721 return(34);
722 }
723 if(verbose>0) printf("MC TACs written in %s\n", mcfile);
724
725 dftEmpty(&dft2);
726 }
727
728
729 /*
730 * Saving and/or plotting of fitted TACs
731 */
732 if(svgfile[0] || ffile[0]) {
733
734 char tmp[64];
735 fit.frameNr=fitframeNr;
736
737 /* Save SVG plot of fitted and original data */
738 if(svgfile[0]) {
739 if(verbose>1) printf("saving SVG plot\n");
740 sprintf(tmp, "1TCM fit with dual input: ");
741 if(strlen(dft.studynr)>0) strcat(tmp, dft.studynr);
742 ret=plot_fitrange_svg(&dft, &fit, tmp, 0.0, 1.02*dft.x[fitframeNr-1],
743 0.0, nan(""), svgfile, verbose-5);
744 if(ret) {
745 fprintf(stderr, "Error (%d) in writing '%s'.\n", ret, svgfile);
746 dftEmpty(&fit); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
747 return(30+ret);
748 }
749 if(verbose>0) printf("Plots written in %s\n", svgfile);
750 }
751
752 /* Delete reference region(s) from the data */
753 if(refAdded!=0) {
754 for(ri=fit.voiNr-1; ri>=0; ri--) if(fit.voi[ri].sw!=0)
755 dftDelete(&fit, ri);
756 }
757
758 /* Save fitted TACs */
759 if(ffile[0]) {
760 if(verbose>1) printf("saving fitted curves\n");
761 tpcProgramName(argv[0], 1, 0, tmp, 64);
762 sprintf(fit.comments, "# program := %s\n", tmp);
763 if(dftWrite(&fit, ffile)) {
764 fprintf(stderr, "Error in writing '%s': %s\n", ffile, dfterrmsg);
765 dftEmpty(&fit); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
766 return(22);
767 }
768 if(verbose>0) printf("Fitted TACs written in %s\n", ffile);
769 }
770
771 }
772
773 dftEmpty(&dft); dftEmpty(&fit); dftEmpty(&input); resEmpty(&res);
774
775 return(0);
776}
777/*****************************************************************************/
778
779/*****************************************************************************
780 *
781 * Functions to be minimized
782 *
783 *****************************************************************************/
784double func1TCMdi(int parNr, double *p, void *fdata)
785{
786 int fi, ret;
787 double K1p, k2p, K1m, k2m, km, Vb, d, wss=0.0;
788 double pa[MAX_PARAMETERS], penalty=1.0;
789
790
791 /* Check parameters against the constraints */
792 ret=modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
793 if(fdata) {}
794
795 /* Calculate actual model parameters */
796 K1p=pa[0]; K1m=pa[2]*K1p; Vb=pa[parVb];
797 if(pa[1]>0.0) k2p=K1p/pa[1]; else k2p=0.0;
798 if(is_this_ref==0 || fixed_ref_Vfm_eq_Vfp==0) {
799 if(pa[3]>0.0) k2m=K1m/(pa[3]); else k2m=0.0;
800 } else { // Optionally, Vfm=Vfp in reference region
801 if(pa[1]>0.0) k2m=K1m/(pa[1]); else k2m=0.0;
802 }
803 km=pa[4];
804
805 /* Simulate the tissue PET TAC */
806 ret=simC4DIvp(
807 input.x, input.voi[0].y, input.voi[1].y, input.voi[2].y, input.frameNr,
808 K1p, k2p, 0, 0, 0, 0, 0, km, K1m, k2m,
809 0.0, Vb, 1.0, input.voi[0].y2, NULL, NULL, NULL, NULL, NULL, NULL, 0);
810 if(ret) {
811 printf("error %d in simulation\n", ret);
812 return(nan(""));
813 }
814
815 /* Interpolate & integrate to measured PET frames */
817 ret=interpolate4pet(
818 input.x, input.voi[0].y2, input.frameNr,
819 dft.x1, dft.x2, petsim, NULL, NULL, fitframeNr);
820 else
821 ret=interpolate(
822 input.x, input.voi[0].y2, input.frameNr,
823 dft.x, petsim, NULL, NULL, fitframeNr);
824 if(ret) {
825 printf("error %d in interpolation\n", ret);
826 return(nan(""));
827 }
828
829 /* Calculate error */
830 for(fi=0; fi<fitframeNr; fi++) if(dft.w[fi]>0.0) {
831 d=petmeas[fi]-petsim[fi];
832 wss+=dft.w[fi]*d*d;
833 }
834 wss*=penalty;
835 if(0) printf("%g %g %g %g %g => %g\n", K1p, k2p, K1m, k2m,Vb,wss);
836
837 return(wss);
838}
839/*****************************************************************************/
840
841/*****************************************************************************/
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
int dftDelete(DFT *dft, int voi)
Definition dft.c:538
void dftEmpty(DFT *data)
Definition dft.c:20
int dftReadReference(DFT *tissue, char *filename, int *filetype, int *ref_index, char *status, int verbose)
Definition dftinput.c:204
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
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 reffile[FILENAME_MAX]
char fitmethod[128]
char refroi[64]
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]
char sw
double * y
char name[MAX_REGIONNAME_LEN+1]
double * y3