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