TPCCLIB
Loading...
Searching...
No Matches
fit_av.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <math.h>
14/*****************************************************************************/
15#include "tpcextensions.h"
16#include "tpcift.h"
17#include "tpctac.h"
18#include "tpcpar.h"
19#include "tpcli.h"
20#include "tpccm.h"
21#include "tpctacmod.h"
22#include "tpclinopt.h"
23#include "tpcrand.h"
24#include "tpcnlopt.h"
25/*****************************************************************************/
26
27/*****************************************************************************/
28/* Local functions */
29double func_av(int parNr, double *p, void*);
30/*****************************************************************************/
31typedef struct FITDATA {
33 unsigned int in;
35 double *ix;
37 double *iy;
39 double *kernel;
41 double *cy;
42
44 unsigned int n;
46 double *x;
48 double *y;
50 double *ysim;
52 double *w;
54 int verbose;
55} FITDATA;
56/*****************************************************************************/
57
58/*****************************************************************************/
59static char *info[] = {
60 "Non-linear fitting of the parameters of compartmental model for",
61 "A-V difference.",
62 " ",
63 "Usage: @P [Options] arterytac venatac [parfile]",
64 " ",
65 "Options:",
66 " -w1",
67 " All weights are set to 1.0 (no weighting); by default, weights in",
68 " output data file are used, if available.",
69 " -wf",
70 " Weight by output TAC sampling interval.",
71 " -svg=<Filename>",
72 " Fitted and measured TACs are plotted in specified SVG file.",
73 " -stdoptions", // List standard options like --help, -v, etc
74 " ",
75 "If TAC files contain more than one TAC, only the first is used.",
76 " ",
77 "See also: sim_av, fit_xexp, convexpf",
78 " ",
79 "Keywords: input, curve fitting",
80 0};
81/*****************************************************************************/
82
83/*****************************************************************************/
84/* Turn on the globbing of the command line, since it is disabled by default in
85 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
86 In Unix&Linux wildcard command line processing is enabled by default. */
87/*
88#undef _CRT_glob
89#define _CRT_glob -1
90*/
91int _dowildcard = -1;
92/*****************************************************************************/
93
94/*****************************************************************************/
96
111 double *t,
113 double *cab,
115 const int nr,
117 double f,
119 double k1,
121 double k2,
123 double k3,
125 double k4,
127 double k5,
129 double k6,
131 double *cvb,
133 double *ct
134) {
135 int i;
136 double b, c, d, w, z, dt2;
137 double cai, ca_last, t_last;
138 double ct1, ct1_last, ct2, ct2_last, ct3, ct3_last;
139 double ct1i, ct1i_last, ct2i, ct2i_last, ct3i, ct3i_last;
140
141
142 /* Check for data */
143 if(nr<2) return 1;
144 if(cvb==NULL) return 2;
145
146 /* Check actual parameter number */
147 if(!(f>=0.0) || !(k1>=0.0) || k1>f) return 3;
148 if(k3<=0.0) {k3=0.0; if(k2<=0.0) k2=0.0;}
149 else if(k5<=0.0) {k5=0.0; if(k4<=0.0) k4=0.0;}
150 else {if(k6<=0.0) k6=0.0;}
151
152 /* Calculate curves */
153 t_last=0.0; if(t[0]<t_last) t_last=t[0];
154 cai=ca_last=0.0;
155 ct1_last=ct2_last=ct3_last=ct1i_last=ct2i_last=ct3i_last=0.0;
156 ct1=ct2=ct3=ct1i=ct2i=ct3i=0.0;
157 for(i=0; i<nr; i++) {
158 /* delta time / 2 */
159 dt2=0.5*(t[i]-t_last);
160 /* calculate values */
161 if(dt2<0.0) {
162 return 5;
163 } else if(dt2>0.0) {
164 /* arterial integral */
165 cai+=(cab[i]+ca_last)*dt2;
166 /* partial results */
167 b=ct1i_last+dt2*ct1_last;
168 c=ct2i_last+dt2*ct2_last;
169 d=ct3i_last+dt2*ct3_last;
170 w=k4 + k5 - (k5*k6*dt2)/(1.0+k6*dt2);
171 z=1.0+w*dt2;
172 /* 1st tissue compartment and its integral */
173 ct1 = (
174 + k1*z*cai + (k3*k4*dt2 - (k2+k3)*z)*b
175 + k4*c + k4*k6*dt2*d/(1.0+k6*dt2)
176 ) / ( z*(1.0 + dt2*(k2+k3)) - k3*k4*dt2*dt2 );
177 ct1i = ct1i_last + dt2*(ct1_last+ct1);
178 /* 2nd tissue compartment and its integral */
179 ct2 = (k3*ct1i - w*c + k6*d/(1.0+k6*dt2)) / z;
180 ct2i = ct2i_last + dt2*(ct2_last+ct2);
181 /* 3rd tissue compartment and its integral */
182 ct3 = (k5*ct2i - k6*d) / (1.0 + k6*dt2);
183 ct3i = ct3i_last + dt2*(ct3_last+ct3);
184 }
185 if(f>0.0) {
186 double dct = k1*cab[i] - k2*ct1;
187 cvb[i] = cab[i] - dct/f;
188 } else
189 cvb[i]=cab[i];
190
191 /* copy values to argument arrays; set very small values to zero */
192 if(ct!=NULL) {ct[i]=ct1+ct2+ct3; if(fabs(ct[i])<1.0e-12) ct[i]=0.0;}
193
194 /* prepare to the next loop */
195 t_last=t[i]; ca_last=cab[i];
196 ct1_last=ct1; ct1i_last=ct1i;
197 ct2_last=ct2; ct2i_last=ct2i;
198 ct3_last=ct3; ct3i_last=ct3i;
199 }
200
201 return 0;
202}
203
204/*****************************************************************************/
205
206/*****************************************************************************/
210int main(int argc, char **argv)
211{
212 int ai, help=0, version=0, verbose=1;
213 char afile[FILENAME_MAX], vfile[FILENAME_MAX], parfile[FILENAME_MAX], svgfile[FILENAME_MAX];
214 int weights=0; // 0=default, 1=no weighting, 2=frequency
215 int model=0;
216 int ret;
217
218
219 /*
220 * Get arguments
221 */
222 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
223 afile[0]=vfile[0]=parfile[0]=svgfile[0]=(char)0;
224 /* Options */
225 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
226 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
227 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
228 if(strcasecmp(cptr, "W1")==0) {
229 weights=1; continue;
230 } else if(strcasecmp(cptr, "WF")==0) {
231 weights=2; continue;
232 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
233 strlcpy(svgfile, cptr+4, FILENAME_MAX); continue;
234 } else if(strcasecmp(cptr, "SER2")==0) {
235 model=1; continue;
236 } else if(strcasecmp(cptr, "MET")==0) {
237 model=2; continue;
238 }
239 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
240 return(1);
241 } else break;
242
243 TPCSTATUS status; statusInit(&status);
244 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
245 status.verbose=verbose-3;
246
247 /* Print help or version? */
248 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
249 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
250 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
251
252 /* Process other arguments, starting from the first non-option */
253 if(ai<argc) strlcpy(afile, argv[ai++], FILENAME_MAX);
254 if(ai<argc) strlcpy(vfile, argv[ai++], FILENAME_MAX);
255 if(ai<argc) strlcpy(parfile, argv[ai++], FILENAME_MAX);
256 if(ai<argc) {
257 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
258 return(1);
259 }
260 /* Did we get all the information that we need? */
261 if(!vfile[0]) { // note that parameter file is optional
262 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
263 return(1);
264 }
265
266 /* In verbose mode print arguments and options */
267 if(verbose>1) {
268 printf("afile := %s\n", afile);
269 printf("vfile := %s\n", vfile);
270 if(parfile[0]) printf("parfile := %s\n", parfile);
271 if(svgfile[0]) printf("svgfile := %s\n", svgfile);
272 printf("weights := %d\n", weights);
273 printf("model := %d\n", model);
274 fflush(stdout);
275 }
276
277
278 /*
279 * Read input and output data
280 */
281 if(verbose>1) printf("reading TAC data\n");
282 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
283 TAC atac, vtac; tacInit(&atac); tacInit(&vtac);
284 int fitSampleNr;
285 double fitdur=1.0E+12;
286 ret=tacReadModelingData(afile, vfile, NULL, NULL, &fitdur, 0,
287 &fitSampleNr, &atac, &vtac, &status);
288 if(ret!=TPCERROR_OK) {
289 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
290 tacFree(&atac); tacFree(&vtac); return(2);
291 }
292 if(verbose>2) {
293 printf("fileformat := %s\n", tacFormattxt(atac.format));
294 printf("a.sampleNr := %d\n", atac.sampleNr);
295 printf("v.sampleNr := %d\n", vtac.sampleNr);
296 printf("fitSampleNr := %d\n", fitSampleNr);
297 printf("xunit := %s\n", unitName(atac.tunit));
298 printf("yunit := %s\n", unitName(atac.cunit));
299 printf("fitdur := %g s\n", fitdur);
300 }
301 if(fitSampleNr<4 || atac.sampleNr<4) {
302 fprintf(stderr, "Error: too few samples.\n");
303 tacFree(&atac); tacFree(&vtac); return(2);
304 }
305 /* Set places for simulated and fitted TACs */
306 atac.tacNr=vtac.tacNr=1;
307 if(tacAllocateMore(&atac, 1)!=TPCERROR_OK || tacAllocateMore(&vtac, 1)!=TPCERROR_OK) {
308 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
309 tacFree(&atac); tacFree(&vtac); return(2);
310 }
311 /* Check and set weights */
312 if(weights==0) {
313 if(!tacIsWeighted(&vtac)) {
315 for(int i=0; i<vtac.sampleNr; i++) vtac.w[i]=1.0;
316 }
317 } else if(weights==1) {
319 for(int i=0; i<vtac.sampleNr; i++) vtac.w[i]=1.0;
320 } else if(weights==2) {
321 ret=tacWByFreq(&vtac, ISOTOPE_UNKNOWN, &status);
322 if(ret!=TPCERROR_OK) {
323 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
324 tacFree(&atac); tacFree(&vtac); return(2);
325 }
326 }
327
328
329 /*
330 * Fitting
331 */
332 if(verbose>1) printf("preparing for fitting\n");
333
334 /* Set data pointers for the fit */
335 FITDATA fitdata;
336 fitdata.verbose=0;
337 //fitdata.kernel=kernel;
338 fitdata.in=atac.sampleNr;
339 fitdata.ix=atac.x;
340 fitdata.iy=atac.c[0].y;
341 fitdata.cy=atac.c[1].y;
342
343 fitdata.n=vtac.sampleNr;
344 fitdata.x=vtac.x;
345 fitdata.y=vtac.c[0].y;
346 fitdata.ysim=vtac.c[1].y;
347 fitdata.w=vtac.w;
348
349
350
351 /* Set parameters for nonlinear optimization */
352 if(verbose>2) printf("process initial parameter values\n");
353 int parNr=4; if(model==1) parNr=6;
354 NLOPT nlo; nloptInit(&nlo);
355 ret=nloptAllocate(&nlo, parNr);
356 if(ret!=TPCERROR_OK) {
357 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
358 tacFree(&atac); tacFree(&vtac); return(3);
359 }
360 /* Set function */
361 nlo._fun=func_av;
362 nlo.fundata=&fitdata;
363 nlo.totalNr=parNr; // delay, f, K1/f, K1/k2; k3, k3/k4
364 { // delay [min]
365 nlo.xlower[0]=-0.03*fitdur;
366 nlo.xupper[0]=0.1*fitdur;
367 nlo.xfull[0]=0.0;
368 nlo.xdelta[0]=0.1;
369 nlo.xtol[0]=0.005;
370 }
371 { // f [mL/(mL*min)]
372 nlo.xlower[1]=0.01;
373 nlo.xupper[1]=3.0;
374 nlo.xfull[1]=0.10;
375 nlo.xdelta[1]=0.05;
376 nlo.xtol[1]=0.01;
377 }
378 { // K1/f
379 nlo.xlower[2]=0.01;
380 nlo.xupper[2]=1.0;
381 nlo.xfull[2]=0.50;
382 nlo.xdelta[2]=0.10;
383 nlo.xtol[2]=0.01;
384 }
385 { // K1/k2
386 nlo.xlower[3]=0.01;
387 nlo.xupper[3]=100.0;
388 nlo.xfull[3]=1.0;
389 nlo.xdelta[3]=0.1;
390 nlo.xtol[3]=0.01;
391 }
392 if(model==1) {
393 // k3
394 nlo.xlower[4]=0.0;
395 nlo.xupper[4]=1.0;
396 nlo.xfull[4]=0.1;
397 nlo.xdelta[4]=0.05;
398 nlo.xtol[4]=0.01;
399 // k3/k4
400 nlo.xlower[5]=1.0E-03;
401 nlo.xupper[5]=10.0;
402 nlo.xfull[5]=1.0;
403 nlo.xdelta[5]=0.1;
404 nlo.xtol[5]=0.02;
405 }
406 nlo.maxFunCalls=20000;
407
408 /* Get nr of fixed parameters */
409 unsigned int fixedNr=nloptFixedNr(&nlo);
410 if(verbose>2) printf("fixedNr := %d\n", fixedNr);
411
412#if(0)
413 // call function for testing
414 fitdata.verbose=10;
415 func_av(nlo.totalNr, nlo.xfull, &fitdata);
416
417 nloptFree(&nlo);
418 tacFree(&atac); tacFree(&vtac);
419
420#else
421
422 /* Fit */
423 drandSeed(1);
424 if(verbose>2) nloptWrite(&nlo, stdout);
425 if(verbose>0) printf("fitting\n");
426 if(nloptITGO2(&nlo, 1, 0, 0, 0, &status)!=TPCERROR_OK) {
427 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
428 tacFree(&atac); tacFree(&vtac); nloptFree(&nlo); return(5);
429 }
430 nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
431 if(verbose>4) {
432 printf("measured and fitted TAC:\n");
433 for(int i=0; i<vtac.sampleNr; i++)
434 printf("\t%g\t%g\t%g\n", vtac.x[i], vtac.c[0].y[i], vtac.c[1].y[i]);
435 }
436 if(verbose>2) nloptWrite(&nlo, stdout);
437 if(verbose>2) printf(" wss := %g\n", nlo.funval);
438
439
440 /*
441 * Plot measured and fitted data, if requested
442 */
443 if(svgfile[0]) {
444 if(verbose>1) printf("plotting measured and fitted data\n");
445 for(int i=0; i<atac.sampleNr; i++) atac.c[0].y[i]=atac.c[1].y[i];
446 /* Plot */
447 ret=tacPlotFitSVG(&vtac, &atac, "", nan(""), nan(""), nan(""), nan(""), svgfile, &status);
448 if(ret!=TPCERROR_OK) {
449 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
450 tacFree(&atac); tacFree(&vtac); nloptFree(&nlo); //parFree(&par);
451 return(24);
452 }
453
454 if(verbose>0) printf("Measured and fitted data plotted in %s\n", svgfile);
455 }
456
457
458
459 nloptFree(&nlo); //parFree(&par);
460 tacFree(&atac); tacFree(&vtac);
461
462#endif
463 return(0);
464}
465/*****************************************************************************/
466
467/*****************************************************************************
468 *
469 * Functions to be minimized
470 *
471 *****************************************************************************/
472double func_av(int parNr, double *p, void *fdata)
473{
474 FITDATA *d=(FITDATA*)fdata;
475
476 if(d->verbose>0) {printf("%s()\n", __func__); fflush(stdout);}
477 if(d->verbose>20) printf("p[]: %g %g %g %g\n", p[0], p[1], p[2], p[3]);
478
479 /* Process parameters */
480 double delay, f, K1, k2, k3=0.0, k4=0.0;
481 delay=p[0];
482 f=p[1];
483 K1=f*p[2];
484 k2=K1/p[3];
485 if(parNr==6) {
486 k3=p[4];
487 k4=k3/p[5];
488 }
489
490 /* Delay corrected sample times */
491 double dx[d->in];
492 for(unsigned int i=0; i<d->in; i++) dx[i]=d->ix[i]+delay;
493
494 /* Simulate venous TAC */
495 if(simC3vb(d->ix, d->iy, d->in, f, K1, k2, k3, k4, 0.0, 0.0, d->cy, NULL)) {
496 fprintf(stderr, "Error: cannot simulate.\n");
497 return(nan(""));
498 }
499
500 /* Interpolate to venous sample times */
501 if(d->verbose>3) {fprintf(stdout, "interpolation...\n"); fflush(stdout);}
502 if(liInterpolate(dx, d->cy, d->in, d->x, d->ysim, NULL, NULL, d->n, 0, 1, 0)!=0) {
503 fprintf(stderr, "Error: cannot interpolate.\n");
504 return(nan(""));
505 }
506 if(d->verbose>3) {
507 printf("\nData x\ty\tSimulated\n");
508 for(unsigned int i=0; i<d->n; i++)
509 printf("%g\t%g\t%g\n", d->x[i], d->y[i], d->ysim[i]);
510 }
511
512 /* Calculate the weighted SS */
513 if(d->verbose>2) {fprintf(stdout, "computing WSS...\n"); fflush(stdout);}
514 double wss=0.0;
515 for(unsigned i=0; i<d->n; i++) {
516 double v=d->ysim[i] - d->y[i];
517 wss+=d->w[i]*v*v;
518 }
519 if(d->verbose>1) {
520 for(int i=0; i<parNr; i++) printf(" %g", p[i]);
521 printf(" -> %g\n", wss);
522 }
523
524 return(wss);
525}
526/*****************************************************************************/
527
528/*****************************************************************************/
int simC3vb(double *t, double *cab, const int nr, double f, double k1, double k2, double k3, double k4, double k5, double k6, double *cvb, double *ct)
Definition fit_av.c:109
unsigned int drandSeed(short int seed)
Make and optionally set the seed for rand(), drand, drandRange, and drandGaussian().
Definition gaussdev.c:27
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.
void nloptInit(NLOPT *nlo)
Definition nlopt.c:25
int nloptAllocate(NLOPT *nlo, unsigned int parNr)
Definition nlopt.c:74
unsigned int nloptFixedNr(NLOPT *d)
Definition nlopt.c:354
void nloptFree(NLOPT *nlo)
Definition nlopt.c:52
void nloptWrite(NLOPT *d, FILE *fp)
Definition nlopt.c:302
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
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
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 * xdelta
Definition tpcnlopt.h:36
double * xtol
Definition tpcnlopt.h:39
unsigned int totalNr
Definition tpcnlopt.h:27
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
TACC * c
Definition tpctac.h:117
weights weighting
Definition tpctac.h:115
unit tunit
Definition tpctac.h:109
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
void tacFree(TAC *tac)
Definition tac.c:106
void tacInit(TAC *tac)
Definition tac.c:24
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
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacReadModelingData(const char *tissuefile, const char *inputfile1, const char *inputfile2, const char *inputfile3, double *fitdur, int cutInput, int *fitSampleNr, TAC *tis, TAC *inp, TPCSTATUS *status)
Read tissue and input data for modelling.
int tacIsWeighted(TAC *tac)
Definition tacw.c:24
int tacWByFreq(TAC *tac, isotope isot, TPCSTATUS *status)
Definition tacw.c:134
int nloptITGO2(NLOPT *nlo, const int doLocal, unsigned int tgoNr, unsigned int sampleNr, unsigned int neighNr, TPCSTATUS *status)
Definition tgo.c:342
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).
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
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.
Header file for libtpcrand.
Header file for library libtpctac.
Header file for libtpctacmod.