TPCCLIB
Loading...
Searching...
No Matches
fit_wliv.c
Go to the documentation of this file.
1
9/*****************************************************************************/
10#include "tpcclibConfig.h"
11/*****************************************************************************/
12#ifdef HAVE_OMP_H
13#include <omp.h>
14#endif
15/*****************************************************************************/
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <math.h>
20/*****************************************************************************/
21#include "tpcextensions.h"
22#include "tpcift.h"
23#include "tpctac.h"
24#include "tpcpar.h"
25#include "tpcli.h"
26#include "tpccm.h"
27#include "tpctacmod.h"
28#include "tpclinopt.h"
29#include "tpcrand.h"
30#include "tpcnlopt.h"
31#include "tpcbfm.h"
32/*****************************************************************************/
33
34/*****************************************************************************/
35/* Local functions */
36double func_wliv(int parNr, double *p, void*);
37/*****************************************************************************/
38typedef struct FITDATA {
40 unsigned int ni;
42 double *xi;
44 double *yi;
45
47 unsigned int nt;
49 double *xt1;
51 double *xt2;
53 double *xt;
55 double *yt;
57 double *w;
59 double *syt;
60
62 int verbose;
63} FITDATA;
64/*****************************************************************************/
65
66/*****************************************************************************/
67static char *info[] = {
68 "Non-linear fitting of the liver radiowater model to TTACs using arterial",
69 "BTAC as the input function. Small delay of arterial input function is",
70 "fitted by default, as well as larger delay and dispersion representing",
71 "the portal vein input from GI system.",
72 " ",
73 "Usage: @P [Options] btacfile ttacfile [parfile]",
74 " ",
75 "Options:",
76 " -delay=<value>",
77 " Delay time (sec) between BTAC and liver is constrained to given value.",
78 " -delayp=<value>",
79 " Delay time (sec) in GI system is constrained to given value.",
80 " -kGI=<value>",
81 " Dispersion in GI system is constrained to given rate constant (1/min);",
82 " dispersion time constant tau=1/kGI.",
83 " -Vb=<value>",
84 " Blood volume is constrained to given value (mL/mL of liver).",
85 " -w1 | -wf",
86 " All weights are set to 1.0 (no weighting), or based on TTAC frame",
87 " lengths; by default, weights in TTAC file are used, if available.",
88 " -svg=<Filename>",
89 " Fitted and measured TACs are plotted in specified SVG file.",
90 " -sim=<Filename>",
91 " Fitted TTACs at BTAC sample times are saved in specified TAC file.",
92 " -stdoptions", // List standard options like --help, -v, etc
93 " ",
94 "Sample times must be in seconds, unless units are specified in the file.",
95 " ",
96 "See also: fit_h2o, bfmh2o, fitk2, sim_wliv, simdisp",
97 " ",
98 "Keywords: TAC, liver, modelling, perfusion, radiowater",
99 0};
100/*****************************************************************************/
101
102/*****************************************************************************/
103/* Turn on the globbing of the command line, since it is disabled by default in
104 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
105 In Unix&Linux wildcard command line processing is enabled by default. */
106/*
107#undef _CRT_glob
108#define _CRT_glob -1
109*/
110int _dowildcard = -1;
111/*****************************************************************************/
112
113/*****************************************************************************/
117int main(int argc, char **argv)
118{
119 int ai, help=0, version=0, verbose=1;
120 char btacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], parfile[FILENAME_MAX],
121 svgfile[FILENAME_MAX], simfile[FILENAME_MAX];
122 int weights=0; // 0=default, 1=no weighting, 2=frequency
123 double fixed_kgi=nan("");
124 double fixed_vb=nan("");
125 double fixed_dt_liver=nan("");
126 double fixed_dt_gi=nan("");
127
128 drandSeed(6789); //drandSeed(time(NULL));
129
130 /*
131 * Get arguments
132 */
133 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
134 btacfile[0]=ttacfile[0]=parfile[0]=svgfile[0]=simfile[0]=(char)0;
135 /* Options */
136 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
137 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
138 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
139 if(strcasecmp(cptr, "W1")==0) {
140 weights=1; continue;
141 } else if(strcasecmp(cptr, "WF")==0) {
142 weights=2; continue;
143 } else if(strncasecmp(cptr, "kGI=", 4)==0 && strlen(cptr)>4) {
144 if(!atofCheck(cptr+4, &fixed_kgi) && fixed_kgi>=0.0) continue;
145 } else if(strncasecmp(cptr, "VB=", 3)==0 && strlen(cptr)>3) {
146 if(!atofCheck(cptr+3, &fixed_vb) && fixed_vb>=0.0 && fixed_vb<1.0) continue;
147 } else if(strncasecmp(cptr, "DELAY=", 6)==0 && strlen(cptr)>6) {
148 if(!atofCheck(cptr+6, &fixed_dt_liver) && fixed_dt_liver>=0.0) continue;
149 } else if(strncasecmp(cptr, "DELAYL=", 7)==0 && strlen(cptr)>7) {
150 if(!atofCheck(cptr+7, &fixed_dt_liver) && fixed_dt_liver>=0.0) continue;
151 } else if(strncasecmp(cptr, "DELAYP=", 7)==0 && strlen(cptr)>7) {
152 if(!atofCheck(cptr+7, &fixed_dt_gi) && fixed_dt_gi>=0.0) continue;
153 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
154 strlcpy(svgfile, cptr+4, FILENAME_MAX); continue;
155 } else if(strncasecmp(cptr, "SIM=", 4)==0 && strlen(cptr)>4) {
156 strlcpy(simfile, cptr+4, FILENAME_MAX); continue;
157 }
158 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
159 return(1);
160 } else break;
161
162 TPCSTATUS status; statusInit(&status);
163 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
164 status.verbose=verbose-3;
165
166 /* Print help or version? */
167 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
168 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
169 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
170
171 /* Process other arguments, starting from the first non-option */
172 if(ai<argc) strlcpy(btacfile, argv[ai++], FILENAME_MAX);
173 if(ai<argc) strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
174 if(ai<argc) strlcpy(parfile, argv[ai++], FILENAME_MAX);
175 if(ai<argc) {
176 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
177 return(1);
178 }
179 /* Did we get all the information that we need? */
180 if(!ttacfile[0]) { // note that parameter file is optional
181 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
182 return(1);
183 }
184
185 /* In verbose mode print arguments and options */
186 if(verbose>1) {
187 printf("btacfile := %s\n", btacfile);
188 printf("ttacfile := %s\n", ttacfile);
189 if(parfile[0]) printf("parfile := %s\n", parfile);
190 if(svgfile[0]) printf("svgfile := %s\n", svgfile);
191 if(simfile[0]) printf("simfile := %s\n", simfile);
192 printf("weights := %d\n", weights);
193 if(!isnan(fixed_kgi)) printf("fixed_kGI := %g\n", fixed_kgi);
194 if(!isnan(fixed_vb)) printf("fixed_vb := %g\n", fixed_vb);
195 if(!isnan(fixed_dt_liver)) printf("fixed_dt_liver := %g\n", fixed_dt_liver);
196 if(!isnan(fixed_dt_gi)) printf("fixed_dt_gi := %g\n", fixed_dt_gi);
197 fflush(stdout);
198 }
199
200
201 /*
202 * Read the data
203 */
204 if(verbose>1) printf("reading TACs\n");
205 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
206 TAC ttac, btac; tacInit(&ttac); tacInit(&btac);
207
208 if(tacRead(&ttac, ttacfile, &status)!=TPCERROR_OK) {
209 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
210 tacFree(&ttac); tacFree(&btac); return(2);
211 }
212 if(verbose>2) {
213 printf("ttac.fileformat := %s\n", tacFormattxt(ttac.format));
214 printf("ttacNr := %d\n", ttac.tacNr);
215 printf("ttac.sampleNr := %d\n", ttac.sampleNr);
216 fflush(stdout);
217 }
218
219 if(tacRead(&btac, btacfile, &status)!=TPCERROR_OK) {
220 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
221 tacFree(&ttac); tacFree(&btac); return(2);
222 }
223 if(verbose>2) {
224 printf("btac.fileformat := %s\n", tacFormattxt(btac.format));
225 printf("btacNr := %d\n", btac.tacNr);
226 printf("btac.sampleNr := %d\n", btac.sampleNr);
227 fflush(stdout);
228 }
229 if(btac.tacNr>1) {
230 if(verbose>0) fprintf(stderr, "Warning: BTAC file contains more than one TAC.\n");
231 btac.tacNr=1;
232 }
233
234 if(ttac.sampleNr<7 || btac.sampleNr<7) {
235 fprintf(stderr, "Error: too few samples.\n");
236 tacFree(&ttac); tacFree(&btac); return(2);
237 }
238 /* Check NaNs */
239 if(tacNaNs(&ttac)>0 || tacNaNs(&btac)>0) {
240 fprintf(stderr, "Error: data contains missing values.\n");
241 tacFree(&ttac); tacFree(&btac); return(2);
242 }
243 /* Sort data by sample time */
244 tacSortByTime(&ttac, &status);
245 tacSortByTime(&btac, &status);
246 /* Convert sample times into seconds */
247 if(tacXUnitConvert(&ttac, UNIT_SEC, &status)!=TPCERROR_OK ||
248 tacXUnitConvert(&btac, UNIT_SEC, &status)!=TPCERROR_OK)
249 {
250 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
251 tacFree(&ttac); tacFree(&ttac); return(2);
252 }
253 /* Convert BTAC concentrations into TTAC units */
254 if(tacYUnitConvert(&btac, ttac.cunit, &status)!=TPCERROR_OK) {
255 fprintf(stderr, "Error: check and set the data units.\n");
256 tacFree(&ttac); tacFree(&ttac); return(2);
257 }
258 /* Get x range */
259 double xmin, xmax;
260 if(tacXRange(&ttac, &xmin, &xmax)!=0) {
261 fprintf(stderr, "Error: invalid data sample times.\n");
262 tacFree(&ttac); tacFree(&btac); return(2);
263 }
264 if(verbose>1) {
265 printf("xmin := %g\n", xmin);
266 printf("xmax := %g\n", xmax);
267 }
268
269
270 /* Set places for fitted TACs */
271 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
272 if(tacAllocateMore(&ttac, ttac.tacNr)!=TPCERROR_OK) {
273 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
274 tacFree(&ttac); tacFree(&ttac); return(2);
275 }
276
277 /* Check and set weights */
278 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
279 if(weights==0) {
280 if(!tacIsWeighted(&ttac)) {
282 for(int i=0; i<ttac.sampleNr; i++) ttac.w[i]=1.0;
283 }
284 } else if(weights==1) {
286 for(int i=0; i<ttac.sampleNr; i++) ttac.w[i]=1.0;
287 } else if(weights==2) {
288 if(tacWByFreq(&ttac, ISOTOPE_UNKNOWN, &status)!=TPCERROR_OK) {
289 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
290 tacFree(&ttac); tacFree(&btac); return(2);
291 }
292 }
293 /* Number of samples with positive weight is needed to calculate AIC */
294 unsigned int wsampleNr=tacWSampleNr(&ttac);
295 if(verbose>2) printf("wsampleNr := %u\n", wsampleNr);
296 if(wsampleNr<5) {
297 fprintf(stderr, "Error: too few samples for fitting.\n");
298 tacFree(&ttac); tacFree(&btac); return(2);
299 }
300
301
302 /*
303 * Prepare PAR structure for printing and saving model parameters
304 */
305 if(verbose>1) printf("preparing space for parameters\n");
306 PAR par; parInit(&par);
307 if(parAllocateWithTAC(&par, &ttac, 8, &status)!=TPCERROR_OK) {
308 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
309 tacFree(&ttac); tacFree(&btac); parFree(&par); return(3);
310 }
311 iftFree(&par.h); // remove stupid header info
312 /* set time and program name */
313 {
314 char buf[256];
315 time_t t=time(NULL);
316 iftPut(&par.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
317 tpcProgramName(argv[0], 1, 1, buf, 256);
318 iftPut(&par.h, "program", buf, 0, NULL);
319 }
320 par.tacNr=ttac.tacNr; par.parNr=8;
322 for(int i=0; i<par.tacNr; i++) {
323 par.r[i].model=modelCodeIndex("radiowater-liver");
324 par.r[i].dataNr=tacWSampleNr(&ttac);
325 par.r[i].start=xmin;
326 par.r[i].end=xmax;
327 }
328 /* Set parameter names */
329 strcpy(par.n[0].name, "K1a"); par.n[0].unit=UNIT_ML_PER_ML_MIN;
330 strcpy(par.n[1].name, "K1p"); par.n[1].unit=UNIT_ML_PER_ML_MIN;
331 strcpy(par.n[2].name, "k2"); par.n[2].unit=UNIT_PER_MIN;
332 strcpy(par.n[3].name, "Vb"); par.n[3].unit=UNIT_ML_PER_ML;
333 strcpy(par.n[4].name, "LdeltaT"); par.n[4].unit=UNIT_SEC;
334 strcpy(par.n[5].name, "PdeltaT"); par.n[5].unit=UNIT_SEC;
335 strcpy(par.n[6].name, "kGI"); par.n[6].unit=UNIT_PER_MIN;
336 strcpy(par.n[7].name, "p"); par.n[7].unit=UNIT_ML_PER_ML;
337 /* set file names */
338 iftPut(&par.h, "inputfile", btacfile, 0, NULL);
339 iftPut(&par.h, "datafile", ttacfile, 0, NULL);
340
341
342 /*
343 * Fit radiowater model for the TTACs
344 */
345 if(verbose==1) {printf("\nfitting...\n"); fflush(stdout);}
346 int failed=0;
347//#pragma omp parallel for
348 for(int ri=0; ri<ttac.tacNr; ri++) {
349 if(verbose>1) {printf("\nfitting %s\n", ttac.c[ri].name); fflush(stdout);}
350 /* Set data pointers for the fit */
351 FITDATA fitdata;
352 fitdata.ni=btac.sampleNr;
353 fitdata.xi=btac.x;
354 fitdata.yi=btac.c[0].y;
355 fitdata.nt=ttac.sampleNr;
356 if(ttac.isframe) {
357 fitdata.xt1=ttac.x1;
358 fitdata.xt2=ttac.x2;
359 fitdata.xt=NULL;
360 } else {
361 fitdata.xt=ttac.x;
362 fitdata.xt1=NULL;
363 fitdata.xt2=NULL;
364 }
365 fitdata.yt=ttac.c[ri].y;
366 fitdata.w=ttac.w;
367 fitdata.syt=ttac.c[ttac.tacNr+ri].y;
368 if(verbose>10) fitdata.verbose=verbose-10; else fitdata.verbose=0;
369 /* Set NLLS options */
370 NLOPT nlo; nloptInit(&nlo);
371 if(nloptAllocate(&nlo, 7)!=TPCERROR_OK) {
372 fprintf(stderr, "Error: cannot initiate NLLS.\n"); fflush(stderr); failed++;
373 nloptFree(&nlo); continue;
374 }
375 nlo._fun=func_wliv; nlo.maxFunCalls=50000;
376 nlo.fundata=&fitdata;
377 nlo.totalNr=7;
378 /* Set initial values and limits */
379 // Kudomi et al 2008: kGI 0.497+-0.153 1/min, PdeltaT 0.7 +- 5.1 s, fA+fP 1-2 mL/(min*mL)
380 // Slimani et al 2008: fA 0.15+-0.07, fP 1.11+-0.34, p 0.67 +- 0.03, Va 0.085+-0.054
381 // Rijzewijk et al 2010: fA+fP 0.5-1.5
382 nlo.xlower[0]=0.0; nlo.xupper[0]=3.0; nlo.xfull[0]=0.75; nlo.xtol[0]=0.00002;
383 nlo.xlower[1]=0.0; nlo.xupper[1]=9.0; nlo.xfull[1]=4.0; nlo.xtol[1]=0.00005;
384 nlo.xlower[2]=0.01; nlo.xupper[2]=20.0; nlo.xfull[2]=6.0; nlo.xtol[2]=0.0001;
385 nlo.xlower[3]=0.0; nlo.xupper[3]=0.80; nlo.xfull[3]=0.01; nlo.xtol[3]=0.00001;
386 nlo.xlower[4]=-30.0; nlo.xupper[4]=30.0; nlo.xfull[4]=11.0; nlo.xtol[4]=0.01;
387 nlo.xlower[5]=2.0; nlo.xupper[5]=30.0; nlo.xfull[5]=14.0; nlo.xtol[5]=0.01;
388 nlo.xlower[6]=0.05; nlo.xupper[6]=2.0; nlo.xfull[6]=1.0; nlo.xtol[6]=0.0001;
389 if(!isnan(fixed_vb)) {
390 nlo.xlower[3]=nlo.xupper[3]=nlo.xfull[3]=fixed_vb; nlo.xtol[3]=0.0;
391 }
392 if(!isnan(fixed_dt_liver)) {
393 nlo.xlower[4]=nlo.xupper[4]=nlo.xfull[4]=fixed_dt_liver; nlo.xtol[4]=0.0;
394 }
395 if(!isnan(fixed_dt_gi)) {
396 nlo.xlower[5]=nlo.xupper[5]=nlo.xfull[5]=fixed_dt_gi; nlo.xtol[5]=0.0;
397 }
398 if(!isnan(fixed_kgi)) {
399 nlo.xlower[6]=nlo.xupper[6]=nlo.xfull[6]=fixed_kgi; nlo.xtol[6]=0.0;
400 }
401
402
403#if(0)
404 // call function for testing
405 fitdata.verbose=10;
406 double wss=func_wliv(nlo.totalNr, nlo.xfull, &fitdata);
407 if(verbose>1) {
408 printf("\nTime\tTTAC\tsimTTAC\n");
409 for(unsigned int i=0; i<fitdata.nt; i++)
410 printf("%g\t%g\t%g\n", ttac.x[i], ttac.c[ri].y[i], ttac.c[ri+ttac.tacNr].y[i]);
411 printf("\n"); fflush(stdout);
412 }
413 if(verbose>1) {printf("\twss := %g\n", wss); fflush(stdout);}
414
415 /* Copy parameters */
416 par.r[ri].p[0]=nlo.xfull[0];
417 par.r[ri].p[1]=nlo.xfull[1];
418 par.r[ri].p[2]=nlo.xfull[2];
419 par.r[ri].p[3]=nlo.xfull[3];
420 par.r[ri].p[4]=nlo.xfull[4];
421 par.r[ri].p[5]=nlo.xfull[5];
422 par.r[ri].p[6]=nlo.xfull[6];
423 par.r[ri].p[7]=(nlo.xfull[0]+nlo.xfull[1])/nlo.xfull[2];
424 par.r[ri].wss=wss;
425
426#else
427
428 /* Fit */
429 if(verbose>2) {
430 printf("initial guess\n");
431 nlo.funval=nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
432 nloptWrite(&nlo, stdout);
433 fflush(stdout);
434 }
435 if(nloptSimplexARRS(&nlo, 0, &status)!=TPCERROR_OK) {
436 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr); failed++;
437 nloptFree(&nlo); continue;
438 }
439 double wss1=nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
440 if(verbose>6) {
441 printf("\nTime\tTTAC\tsimTTAC\n");
442 for(unsigned int i=0; i<fitdata.nt; i++)
443 printf("%g\t%g\t%g\n", ttac.x[i], ttac.c[ri].y[i], ttac.c[ri+ttac.tacNr].y[i]);
444 printf("\n"); fflush(stdout);
445 }
446 if(verbose>2) nloptWrite(&nlo, stdout);
447 if(verbose>2) printf(" wss1 := %g\n", wss1);
448 /* Calculate AIC */
449 double aic1=aicSS(wss1, wsampleNr, parFreeNr(nlo.totalNr, nlo.xlower, nlo.xupper));
450 if(verbose>2) printf(" AIC1 := %g\n", aic1);
451
452 /* Copy parameters */
453 par.r[ri].p[0]=nlo.xfull[0];
454 par.r[ri].p[1]=nlo.xfull[1];
455 par.r[ri].p[2]=nlo.xfull[2];
456 par.r[ri].p[3]=nlo.xfull[3];
457 par.r[ri].p[4]=nlo.xfull[4];
458 par.r[ri].p[5]=nlo.xfull[5];
459 par.r[ri].p[6]=nlo.xfull[6];
460 par.r[ri].p[7]=(nlo.xfull[0]+nlo.xfull[1])/nlo.xfull[2];
461 par.r[ri].wss=wss1;
462
463 /*
464 * Another fit, assuming only arterial input, in case tumours are included
465 */
466 nlo.xlower[0]=0.0; nlo.xupper[0]=8.0; nlo.xfull[0]=0.75; nlo.xtol[0]=0.00005;
467 nlo.xlower[1]=0.0; nlo.xupper[1]=0.0; nlo.xfull[1]=0.0; nlo.xtol[1]=0.0;
468 nlo.xlower[2]=0.01; nlo.xupper[2]=10.0; nlo.xfull[2]=1.0; nlo.xtol[2]=0.00002;
469 nlo.xlower[3]=0.0; nlo.xupper[3]=0.80; nlo.xfull[3]=0.01; nlo.xtol[3]=0.00001;
470 nlo.xlower[4]=-30.0; nlo.xupper[4]=30.0; nlo.xfull[4]=11.0; nlo.xtol[4]=0.01;
471 nlo.xlower[5]=0.0; nlo.xupper[5]=0.0; nlo.xfull[5]=0.0; nlo.xtol[5]=0.0;
472 nlo.xlower[6]=0.0; nlo.xupper[6]=0.0; nlo.xfull[6]=0.0; nlo.xtol[6]=0.0;
473 if(!isnan(fixed_vb)) {
474 nlo.xlower[3]=nlo.xupper[3]=nlo.xfull[3]=fixed_vb; nlo.xtol[3]=0.0;
475 }
476 if(!isnan(fixed_dt_liver)) {
477 nlo.xlower[4]=nlo.xupper[4]=nlo.xfull[4]=fixed_dt_liver; nlo.xtol[4]=0.0;
478 }
479 if(verbose>2) {
480 printf("initial guess\n");
481 nlo.funval=nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
482 nloptWrite(&nlo, stdout);
483 fflush(stdout);
484 }
485 if(nloptSimplexARRS(&nlo, 0, &status)!=TPCERROR_OK) {
486 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr); failed++;
487 nloptFree(&nlo); continue;
488 }
489 double wss2=nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
490 if(verbose>6) {
491 printf("\nTime\tTTAC\tsimTTAC\n");
492 for(unsigned int i=0; i<fitdata.nt; i++)
493 printf("%g\t%g\t%g\n", ttac.x[i], ttac.c[ri].y[i], ttac.c[ri+ttac.tacNr].y[i]);
494 printf("\n"); fflush(stdout);
495 }
496 if(verbose>2) nloptWrite(&nlo, stdout);
497 if(verbose>2) printf(" wss2 := %g\n", wss2);
498 /* Calculate AIC */
499 double aic2=aicSS(wss2, wsampleNr, parFreeNr(nlo.totalNr, nlo.xlower, nlo.xupper));
500 if(verbose>2) printf(" AIC2 := %g\n", aic2);
501
502 /* Use the results with better AIC */
503 if(!(aic1<aic2)) {
504 /* Copy parameters */
505 par.r[ri].p[0]=nlo.xfull[0];
506 par.r[ri].p[1]=nlo.xfull[1];
507 par.r[ri].p[2]=nlo.xfull[2];
508 par.r[ri].p[3]=nlo.xfull[3];
509 par.r[ri].p[4]=nlo.xfull[4];
510 par.r[ri].p[5]=nlo.xfull[5];
511 par.r[ri].p[6]=nlo.xfull[6];
512 par.r[ri].p[7]=(nlo.xfull[0]+nlo.xfull[1])/nlo.xfull[2];
513 par.r[ri].wss=wss2;
514 } else {
515 /* We need to compute the fitted TACs again with the results from the first fit */
516 nlo.xfull[0]=par.r[ri].p[0];
517 nlo.xfull[1]=par.r[ri].p[1];
518 nlo.xfull[2]=par.r[ri].p[2];
519 nlo.xfull[3]=par.r[ri].p[3];
520 nlo.xfull[4]=par.r[ri].p[4];
521 nlo.xfull[5]=par.r[ri].p[5];
522 nlo.xfull[6]=par.r[ri].p[6];
523 nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
524 }
525#endif
526
527 nloptFree(&nlo);
528 }
529 if(failed>0) {tacFree(&ttac); tacFree(&btac); parFree(&par); return(5);}
530
531
532 /* Print and save the parameters */
533 if(verbose>0) parWrite(&par, stdout, PAR_FORMAT_TSV_UK, 1, NULL);
534 if(parfile[0]) {
535 par.format=parFormatFromExtension(parfile);
536 if(verbose>2) printf("parameter file format := %s\n", parFormattxt(par.format));
538 /* Save file */
539 if(verbose>1) printf(" saving %s\n", parfile);
540 FILE *fp=fopen(parfile, "w");
541 if(fp==NULL) {
542 fprintf(stderr, "Error: cannot open file for writing.\n");
543 tacFree(&ttac); tacFree(&btac); parFree(&par); return(11);
544 }
545 int ret=parWrite(&par, fp, PAR_FORMAT_UNKNOWN, 1, &status);
546 fclose(fp);
547 if(ret!=TPCERROR_OK) {
548 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
549 tacFree(&ttac); tacFree(&btac); parFree(&par); return(12);
550 }
551 if(verbose>0) printf("parameters saved in %s\n", parfile);
552 }
553
554
555 /*
556 * Plot measured and fitted data, if requested
557 */
558 if(svgfile[0]) {
559 if(verbose>1) printf("plotting measured and fitted data\n");
560 TAC fit; tacInit(&fit);
561 (void)tacDuplicate(&ttac, &fit);
562 for(int r=0; r<ttac.tacNr; r++)
563 for(int i=0; i<ttac.sampleNr; i++)
564 fit.c[r].y[i]=ttac.c[r+ttac.tacNr].y[i];
565 /* Plot */
566 if(tacPlotFitSVG(&ttac, &fit, "", nan(""), nan(""), nan(""), nan(""), svgfile, NULL)!=TPCERROR_OK)
567 {
568 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
569 tacFree(&ttac); tacFree(&btac); parFree(&par); tacFree(&fit);
570 return(21);
571 }
572 if(verbose>0) printf("Measured and fitted data plotted in %s\n", svgfile);
573 tacFree(&fit);
574 }
575
576
577 /*
578 * Compute and save fitted TTACs at BTAC sample times, if requested
579 */
580 if(simfile[0]) {
581 if(verbose>1) printf("calculating simulated TTACs\n");
582
583 /* Allocate memory for simulated TTACs */
584 TAC sim; tacInit(&sim);
585 if(tacDuplicate(&ttac, &sim) || tacAllocateMoreSamples(&sim, btac.sampleNr-ttac.sampleNr)) {
586 fprintf(stderr, "Error: cannot allocate space for simulated TTACs\n");
587 tacFree(&ttac); tacFree(&btac); parFree(&par); tacFree(&sim);
588 return(31);
589 }
590 sim.sampleNr=btac.sampleNr;
591 sim.isframe=btac.isframe;
592 (void)tacXCopy(&btac, &sim, 0, sim.sampleNr-1);
594
595 /* Set data pointers for the function data structure */
596 FITDATA fitdata;
597 fitdata.ni=btac.sampleNr;
598 fitdata.xi=btac.x;
599 fitdata.yi=btac.c[0].y;
600 fitdata.nt=btac.sampleNr;
601 if(btac.isframe) {
602 fitdata.xt1=btac.x1;
603 fitdata.xt2=btac.x2;
604 fitdata.xt=NULL;
605 } else {
606 fitdata.xt=btac.x;
607 fitdata.xt1=NULL;
608 fitdata.xt2=NULL;
609 }
610 fitdata.w=btac.w;
611
612 /* Simulate one TAC at a time */
613 for(int i=0; i<sim.tacNr; i++) {
614 fitdata.yt=fitdata.syt=sim.c[i].y;
615 func_wliv(7, par.r[i].p, &fitdata);
616 }
617
618 /* Save simulated TTACs */
619 if(verbose>1) printf("writing %s\n", simfile);
620 FILE *fp; fp=fopen(simfile, "w");
621 if(fp==NULL) {
622 fprintf(stderr, "Error: cannot open file for writing (%s)\n", simfile);
623 tacFree(&ttac); tacFree(&btac); parFree(&par); tacFree(&sim); return(32);
624 }
625 int ret=tacWrite(&sim, fp, TAC_FORMAT_PMOD, 1, &status);
626 fclose(fp); tacFree(&sim);
627 if(ret!=TPCERROR_OK) {
628 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
629 tacFree(&ttac); tacFree(&btac); parFree(&par); return(33);
630 }
631 if(verbose>=0) {printf("%s saved.\n", simfile); fflush(stdout);}
632 }
633
634
635 tacFree(&ttac); tacFree(&btac); parFree(&par);
636 return(0);
637}
638/*****************************************************************************/
639
640/*****************************************************************************
641 *
642 * Functions to be minimized
643 *
644 *****************************************************************************/
645double func_wliv(int parNr, double *p, void *fdata)
646{
647 FITDATA *d=(FITDATA*)fdata;
648
649 if(d->verbose>0) {printf("%s()\n", __func__); fflush(stdout);}
650 if(parNr!=7 || p==NULL || fdata==NULL || d->ni<1 || d->nt<1) return(nan(""));
651 if(d->verbose>9) {
652 printf("p[]: %g", p[0]);
653 for(int i=1; i<parNr; i++) printf(" %g", p[i]);
654 printf("\n"); fflush(stdout);
655 }
656
657 /* Process parameters; data is in seconds, therefore rate constants are converted to per sec */
658 double K1a=p[0]/60.0;
659 double K1p=p[1]/60.0;
660 double k2=p[2]/60.0;
661 double Vb=p[3];
662 double LdT=p[4];
663 double PdT=p[5];
664 double kGI=p[6]/60.0;
665
666 /* Make arterial input TAC with delay */
667 double x[d->ni], *ca=d->yi;
668 for(unsigned int i=0; i<d->ni; i++) x[i]=d->xi[i]+LdT;
669
670 /* Make portal vein input TAC with both delays and dispersion */
671 double x2[d->ni], cp[d->ni], sy[d->ni];
672 for(unsigned int i=0; i<d->ni; i++) x2[i]=x[i]+PdT;
673 if(kGI<1.0E-20) { // nothing comes out of portal vein
674 for(unsigned int i=0; i<d->ni; i++) cp[i]=0.0;
675 } else {
676 for(unsigned int i=0; i<d->ni; i++) sy[i]=d->yi[i];
677 if(simDispersion(x2, sy, d->ni, 1.0/kGI, 0.0, cp)!=0) return(nan(""));
678 /* interpolate to the same sample times as the arterial input */
679 if(liInterpolate(x2, sy, d->ni, x, cp, NULL, NULL, d->ni, 3, 1, 0)) return(nan(""));
680 }
681
682 /* Simulate tissue curve at input sample times */
683 if(simC1DI(x, ca, cp, d->ni, K1a, K1p, k2, sy)!=0) return(nan(""));
684 /* Simulate vascular contribution */
685 for(unsigned int i=0; i<d->ni; i++) sy[i]*=(1.0-Vb);
686 if(K1a+K1p > 0.0)
687 for(unsigned int i=0; i<d->ni; i++) sy[i]+= Vb*(K1a*ca[i] + K1p*cp[i])/(K1a+K1p);
688 else
689 for(unsigned int i=0; i<d->ni; i++) sy[i]+= Vb*ca[i];
690
691 /* Interpolate simulated tissue curve to the sample times of measured tissue */
692 if(d->xt1==NULL || d->xt2==NULL) {
693 if(liInterpolate(x, sy, d->ni, d->xt, d->syt, NULL, NULL, d->nt, 3, 1, 0))
694 return(nan(""));
695 } else {
696 if(liInterpolateForPET(x, sy, d->ni, d->xt1, d->xt2, d->syt, NULL, NULL, d->nt, 3, 1, 0))
697 return(nan(""));
698 }
699
700 /* Calculate the weighted SS */
701 if(d->verbose>2) {fprintf(stdout, "computing WSS...\n"); fflush(stdout);}
702 double wss=0.0;
703 for(unsigned i=0; i<d->nt; i++) {
704 double v=d->syt[i] - d->yt[i];
705 wss+=d->w[i]*v*v;
706 }
707
708 return(wss);
709}
710/*****************************************************************************/
711
712/*****************************************************************************/
double aicSS(double ss, const unsigned int n, const unsigned int k)
Calculate corrected AIC.
Definition aic.c:29
unsigned int parFreeNr(const unsigned int n, double *pLower, double *pUpper)
Calculate the number of free parameters.
Definition aic.c:60
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
int atofCheck(const char *s, double *v)
Definition decpoint.c:94
unsigned int drandSeed(short int seed)
Make and optionally set the seed for rand(), drand, drandRange, and drandGaussian().
Definition gaussdev.c:27
void iftFree(IFT *ift)
Definition ift.c:37
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
Definition ift.c:63
int liInterpolate(double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear interpolation and/or integration with trapezoidal method.
int liInterpolateForPET(double *x, double *y, const int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear TAC interpolation and/or integration to PET frames.
unsigned int modelCodeIndex(const char *s)
Definition modell.c:237
void nloptInit(NLOPT *nlo)
Definition nlopt.c:25
int nloptAllocate(NLOPT *nlo, unsigned int parNr)
Definition nlopt.c:74
void nloptFree(NLOPT *nlo)
Definition nlopt.c:52
void nloptWrite(NLOPT *d, FILE *fp)
Definition nlopt.c:302
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 simC1DI(double *t, double *cba, double *cbb, const int nr, const double k1a, const double k1b, const double k2, double *ct)
Definition simdicm.c:30
int simDispersion(double *x, double *y, const int n, const double tau1, const double tau2, double *tmp)
int nloptSimplexARRS(NLOPT *nlo, unsigned int maxIter, TPCSTATUS *status)
Definition simplex.c:373
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
double(* _fun)(int, double *, void *)
Definition tpcnlopt.h:42
double funval
Definition tpcnlopt.h:50
unsigned int maxFunCalls
Definition tpcnlopt.h:46
double * xupper
Definition tpcnlopt.h:33
double * xlower
Definition tpcnlopt.h:31
void * fundata
Definition tpcnlopt.h:44
double * xfull
Definition tpcnlopt.h:29
double * xtol
Definition tpcnlopt.h:39
unsigned int totalNr
Definition tpcnlopt.h:27
Definition tpcpar.h:100
int format
Definition tpcpar.h:102
IFT h
Optional (but often useful) header information.
Definition tpcpar.h:147
int parNr
Definition tpcpar.h:108
int tacNr
Definition tpcpar.h:104
PARR * r
Definition tpcpar.h:114
PARN * n
Definition tpcpar.h:112
int unit
Definition tpcpar.h:86
char name[MAX_PARNAME_LEN+1]
Definition tpcpar.h:82
double wss
Definition tpcpar.h:72
int dataNr
Definition tpcpar.h:62
unsigned int model
Definition tpcpar.h:48
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
Definition tpctac.h:87
double * x
Definition tpctac.h:97
unit cunit
Definition tpctac.h:105
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
double * w
Definition tpctac.h:111
int isframe
Definition tpctac.h:95
TACC * c
Definition tpctac.h:117
weights weighting
Definition tpctac.h:115
double * x2
Definition tpctac.h:101
double * x1
Definition tpctac.h:99
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 tacAllocateMoreSamples(TAC *tac, int addNr)
Allocate memory for more samples in TAC data.
Definition tac.c:435
int tacAllocateMore(TAC *tac, int tacNr)
Definition tac.c:178
int tacPlotFitSVG(TAC *tac1, TAC *tac2, const char *main_title, const double x1, const double x2, const double y1, const double y2, const char *fname, TPCSTATUS *status)
Definition tacfitplot.c:27
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
int tacNaNs(TAC *tac)
Definition tacnan.c:71
int tacSortByTime(TAC *d, TPCSTATUS *status)
Definition tacorder.c:74
int tacYUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:72
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:23
int tacIsWeighted(TAC *tac)
Definition tacw.c:24
unsigned int tacWSampleNr(TAC *tac)
Definition tacw.c:219
int tacWByFreq(TAC *tac, isotope isot, TPCSTATUS *status)
Definition tacw.c:134
int tacXCopy(TAC *tac1, TAC *tac2, int i1, int i2)
Definition tacx.c:24
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Definition tacx.c:124
Header file for libtpcbfm.
Header file for libtpccm.
Header file for library libtpcextensions.
weights
Is data weighted, or are weight factors available with data?
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ UNIT_ML_PER_ML
mL/mL
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ UNIT_SEC
seconds
@ UNIT_PER_MIN
1/min
@ TPCERROR_OK
No error.
Header file for library libtpcift.
@ ISOTOPE_UNKNOWN
Unknown.
Definition tpcisotope.h:51
Header file for libtpcli.
Header file for libtpclinopt.
Header file for library libtpcnlopt.
Header file for libtpcpar.
@ PAR_FORMAT_FIT
Function fit format of Turku PET Centre.
Definition tpcpar.h:30
@ 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 libtpcrand.
Header file for library libtpctac.
@ TAC_FORMAT_PMOD
PMOD TAC format.
Definition tpctac.h:33
Header file for libtpctacmod.