TPCCLIB
Loading...
Searching...
No Matches
fit_wrlv.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#include "tpcbfm.h"
26/*****************************************************************************/
27
28/*****************************************************************************/
29/* Local functions */
30double func_disp(int parNr, double *p, void*);
31double func_wrlv(int parNr, double *p, void*);
32/*****************************************************************************/
33typedef struct FITDATA {
35 unsigned int n;
37 double *x;
39 double *x1;
41 double *x2;
43 double *yrv;
45 double *ylv;
47 double *w;
48
50 double *fyrv;
52 double *fylv;
53
55 int verbose;
56} FITDATA;
57/*****************************************************************************/
58
59/*****************************************************************************/
60static char *info[] = {
61 "Non-linear fitting of exponential input function with paired, repeated",
62 "eigenvalues, incorporating injection schedule, to RV and LV cavity BTACs",
63 "from a radiowater PET study, where LV BTAC is modelled with simple",
64 "delay and dispersion of the RV BTAC.",
65 " ",
66 "Usage: @P [Options] tacfile [parfile]",
67 " ",
68 "Options:",
69 " -Ti=<infusion time>",
70 " Duration of intravenous infusion in seconds; 0, if short bolus.",
71 " -w1",
72 " All weights are set to 1.0 (no weighting); by default, weights in",
73 " output data file are used, if available.",
74 " -wf",
75 " Weight by output TAC sampling interval.",
76 " -svg=<Filename>",
77 " Fitted and measured TACs are plotted in specified SVG file.",
78 " -stdoptions", // List standard options like --help, -v, etc
79 " ",
80 "TAC file must contain two TACs, for RV and LV, in this order.",
81 "Sample times must be in seconds, unless units are specified in the file.",
82 " ",
83 "See also: fit_disp, fit_sinf, fit_wpul, disp4dft, convexpf",
84 " ",
85 "Keywords: input, curve fitting, myocardium, radiowater",
86 0};
87/*****************************************************************************/
88
89/*****************************************************************************/
90/* Turn on the globbing of the command line, since it is disabled by default in
91 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
92 In Unix&Linux wildcard command line processing is enabled by default. */
93/*
94#undef _CRT_glob
95#define _CRT_glob -1
96*/
97int _dowildcard = -1;
98/*****************************************************************************/
99
100/*****************************************************************************/
104int main(int argc, char **argv)
105{
106 int ai, help=0, version=0, verbose=1;
107 char tacfile[FILENAME_MAX], parfile[FILENAME_MAX], svgfile[FILENAME_MAX];
108 int weights=0; // 0=default, 1=no weighting, 2=frequency
109 double fixedTi=nan("");
110 int ret;
111
112
113 drandSeed(1);
114
115
116 /*
117 * Get arguments
118 */
119 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
120 tacfile[0]=parfile[0]=svgfile[0]=(char)0;
121 /* Options */
122 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
123 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
124 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
125 if(strcasecmp(cptr, "W1")==0) {
126 weights=1; continue;
127 } else if(strcasecmp(cptr, "WF")==0) {
128 weights=2; continue;
129 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
130 strlcpy(svgfile, cptr+4, FILENAME_MAX); continue;
131 } else if(strncasecmp(cptr, "Ti=", 3)==0) {
132 fixedTi=atofVerified(cptr+3); if(fixedTi>=0.0) continue;
133 }
134 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
135 return(1);
136 } else break;
137
138 TPCSTATUS status; statusInit(&status);
139 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
140 status.verbose=verbose-3;
141
142 /* Print help or version? */
143 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
144 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
145 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
146
147 /* Process other arguments, starting from the first non-option */
148 if(ai<argc) strlcpy(tacfile, argv[ai++], FILENAME_MAX);
149 if(ai<argc) strlcpy(parfile, argv[ai++], FILENAME_MAX);
150 if(ai<argc) {
151 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
152 return(1);
153 }
154 /* Did we get all the information that we need? */
155 if(!tacfile[0]) { // note that parameter file is optional
156 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
157 return(1);
158 }
159
160 /* In verbose mode print arguments and options */
161 if(verbose>1) {
162 printf("tacfile := %s\n", tacfile);
163 if(parfile[0]) printf("parfile := %s\n", parfile);
164 if(svgfile[0]) printf("svgfile := %s\n", svgfile);
165 if(!isnan(fixedTi)) printf("fixedTi := %g\n", fixedTi);
166 printf("weights := %d\n", weights);
167 fflush(stdout);
168 }
169
170
171 /*
172 * Read the data
173 */
174 if(verbose>1) printf("reading BTAC data\n");
175 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
176 TAC tac; tacInit(&tac);
177 if(tacRead(&tac, tacfile, &status)!=TPCERROR_OK) {
178 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
179 tacFree(&tac); return(2);
180 }
181 if(verbose>1) {
182 printf("fileformat := %s\n", tacFormattxt(tac.format));
183 printf("tacNr := %d\n", tac.tacNr);
184 printf("sampleNr := %d\n", tac.sampleNr);
185 printf("xunit := %s\n", unitName(tac.tunit));
186 printf("yunit := %s\n", unitName(tac.cunit));
187 printf("isframe := %d\n", tac.isframe);
188 }
189 if(tac.tacNr<2) {
190 fprintf(stderr, "Error: file does not contain RV and LV TACs.\n");
191 tacFree(&tac); return(2);
192 } else if(tac.tacNr>2) {
193 if(verbose>0) fprintf(stderr, "Warning: file contains more than two TACs.\n");
194 tac.tacNr=2;
195 }
196 if(tac.sampleNr<8) {
197 fprintf(stderr, "Error: too few samples.\n");
198 tacFree(&tac); return(2);
199 }
200 /* Check NaNs */
201 if(tacNaNs(&tac)>0) {
202 fprintf(stderr, "Error: data contains missing values.\n");
203 tacFree(&tac); return(2);
204 }
205 /* Sort data by sample time */
206 tacSortByTime(&tac, &status);
207 /* Get x range */
208 double xmin, xmax;
209 if(tacXRange(&tac, &xmin, &xmax)!=0) {
210 fprintf(stderr, "Error: invalid data sample times.\n");
211 tacFree(&tac); return(2);
212 }
213 if(verbose>2) {
214 printf("orig_xmin := %g\n", xmin);
215 printf("orig_xmax := %g\n", xmax);
216 }
217 if(!(xmin>=0.0)) {
218 fprintf(stderr, "Error: negative sample times.\n");
219 tacFree(&tac); return(2);
220 }
221 /* Convert sample times into seconds */
222 if(tac.tunit==UNIT_UNKNOWN) {
223 if(xmax<10.0) tac.tunit=UNIT_MIN; else tac.tunit=UNIT_SEC;
224 }
225 if(tacXUnitConvert(&tac, UNIT_SEC, &status)!=TPCERROR_OK) {
226 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
227 tacFree(&tac); return(2);
228 }
229 if(tacXRange(&tac, &xmin, &xmax)!=0) {
230 fprintf(stderr, "Error: invalid data sample times.\n");
231 tacFree(&tac); return(2);
232 }
233 if(verbose>1) {
234 printf("xmin := %g\n", xmin);
235 printf("xmax := %g\n", xmax);
236 printf("final_xunit := %s\n", unitName(tac.tunit));
237 }
238
239 /* Find the sample time and index of max RV concentration */
240 double ymin, ymax; int imax;
241 ret=tacYRange(&tac, 0, &ymin, &ymax, NULL, &imax, NULL, NULL);
242 if(ret!=0) {
243 fprintf(stderr, "Error: invalid contents in %s\n", tacfile);
244 tacFree(&tac); return(2);
245 }
246 double tmax=tac.x[imax];
247 if(verbose>1) {
248 printf("peak_x := %g\n", tmax);
249 printf("peak_y := %g\n", ymax);
250 printf("peak_index := %d\n", imax);
251 }
252 if((tac.sampleNr-imax)<3 || !(ymin<0.5*ymax)) {
253 fprintf(stderr, "Error: invalid TAC shape in %s\n", tacfile);
254 tacFree(&tac); return(2);
255 }
256
257 /* Find the sample time of max LV concentration */
258 double lv_tmax;
259 {
260 int imax;
261 ret=tacYRange(&tac, 1, NULL, NULL, NULL, &imax, NULL, NULL);
262 if(ret!=0) {
263 fprintf(stderr, "Error: invalid contents in %s\n", tacfile);
264 tacFree(&tac); return(2);
265 }
266 lv_tmax=tac.x[imax];
267 if(verbose>1) {
268 printf("LV_peak_x := %g\n", lv_tmax);
269 }
270 }
271
272 /* Set places for fitted TACs */
273 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
274 if(tacAllocateMore(&tac, 2)!=TPCERROR_OK) {
275 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
276 tacFree(&tac); return(2);
277 }
278
279 /* Check and set weights */
280 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
281 if(weights==0) {
282 if(!tacIsWeighted(&tac)) {
284 for(int i=0; i<tac.sampleNr; i++) tac.w[i]=1.0;
285 }
286 } else if(weights==1) {
288 for(int i=0; i<tac.sampleNr; i++) tac.w[i]=1.0;
289 } else if(weights==2) {
290 if(tacWByFreq(&tac, ISOTOPE_UNKNOWN, &status)!=TPCERROR_OK) {
291 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
292 tacFree(&tac); return(2);
293 }
294 }
295
296
297 /*
298 * Fit delay and dispersion between RV and LV TACs
299 */
300 double delay, tau;
301 {
302 if(verbose>1) printf("fitting dispersion and delay between RV and LV TACs\n");
303 FITDATA fitdata;
304 /* Set data pointers for the fit */
305 fitdata.n=tac.sampleNr;
306 fitdata.x=tac.x;
307 fitdata.yrv=tac.c[0].y;
308 fitdata.ylv=tac.c[1].y;
309 fitdata.fyrv=tac.c[2].y;
310 fitdata.fylv=tac.c[3].y;
311 fitdata.w=tac.w;
312 if(verbose>10) fitdata.verbose=verbose-10; else fitdata.verbose=0;
313 /* Set NLLS options */
314 NLOPT nlo; nloptInit(&nlo);
315 if(nloptAllocate(&nlo, 2)!=TPCERROR_OK) {
316 fprintf(stderr, "Error: cannot initiate NLLS.\n");
317 tacFree(&tac); return(3);
318 }
319 nlo._fun=func_disp;
320 nlo.fundata=&fitdata;
321 nlo.totalNr=2;
322 /* Set initial values and limits */
323 double peakdif=lv_tmax-tmax;
324 if(!(peakdif>0.0)) peakdif=0.0;
325 if(peakdif>50.0) peakdif=50.0;
326 nlo.xlower[0]=0.0; nlo.xupper[0]=60.0; nlo.xfull[0]=10.0; nlo.xdelta[0]=1.0; nlo.xtol[0]=0.001;
327 nlo.xlower[1]=0.0; nlo.xupper[1]=60.0; nlo.xfull[1]=peakdif; nlo.xdelta[1]=0.5; nlo.xtol[1]=0.001;
328
329 if(verbose>2) printf("non-linear optimization\n");
330 if(nloptSimplex(&nlo, 0, &status)!=TPCERROR_OK) {
331 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
332 tacFree(&tac); nloptFree(&nlo); return(3);
333 }
334 if(verbose>3) {
335 nloptWrite(&nlo, stdout);
336 (void)func_disp(nlo.totalNr, nlo.xfull, nlo.fundata);
337 double wss=0.0;
338 for(unsigned int i=0; i<fitdata.n; i++) {
339 double v=fitdata.fylv[i]-fitdata.ylv[i];
340 wss+=fitdata.w[i]*v*v;
341 }
342 printf(" wss := %g\n", wss);
343 }
344 tau=nlo.xfull[0];
345 delay=nlo.xfull[1];
346 if(verbose>1) {
347 printf(" fitted_tau := %g\n", tau);
348 printf(" fitted_delay := %g\n", delay);
349 }
350 nloptFree(&nlo);
351 }
352
353
354 /*
355 * Get initial estimates for radiowater appearance time based on highest RV TAC slope
356 */
357 if(verbose>1) printf("slope method for estimating appearance time\n");
358 double Ta=nan("");
359 {
360 double slope;
361 if(highestSlope(tac.x, tac.c[0].y, tac.sampleNr, 3, 0.0, &slope, NULL, &Ta, NULL) || !(slope>0.0))
362 {
363 fprintf(stderr, "Error: invalid TAC shapes.\n");
364 tacFree(&tac); return(2);
365 }
366 if(verbose>1) printf(" initial_Ta := %g\n", Ta);
367 }
368
369
370 /*
371 * Get initial estimates for exponential function parameters from the descending part
372 * of the RV BTAC
373 */
374 if(verbose>1) printf("initial exponential fitting\n");
375 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
376 int enr=2;
377 double init_a[enr], init_k[enr];
378 /* Get the shortest frame length or sampling interval */
379 double sdist;
380 if(tacGetSampleInterval(&tac, 1.0E-03, &sdist, NULL)!=0) {
381 fprintf(stderr, "Error: invalid sample times.\n");
382 tacFree(&tac); return(2);
383 }
384 if(verbose>1) printf("shortest frame length := %g\n", sdist);
385 {
386 /* Get the data after the peak */
387 int sampleNr=tac.sampleNr-imax-1;
388 double *y=tac.c[0].y+imax+1;
389 double *w=tac.w+imax+1;
390 double x[sampleNr]; for(int i=0; i<sampleNr; i++) x[i]=tac.x[i+imax+1]-tmax;
391 if(verbose>3) {
392 printf("\n\tRV data for decaying exponential fitting\n");
393 for(int i=0; i<sampleNr; i++) printf("\t%g\t%g\t%g\n", x[i], y[i], w[i]);
394 printf("\n"); fflush(stdout);
395 }
396 /* Spectral analysis to find better range of parameters */
397 if(verbose>4) printf("estimating initial k value range\n");
398 int bfNr=100;
399 double kmin, kmax; // kmin must be >0
400 double xmin, xmax; doubleRange(x, sampleNr, &xmin, &xmax);
401 kmin=1.0E-06/xmax; kmax=3.0/(xmin+sdist); if(kmax<100.0*kmin) kmax=100.0*kmin;
402/*
403 kmin=0.000001/sdist; kmax=10.0/sdist; if(kmax>100.) kmax=100.;
404*/
405 if(verbose>2) printf(" kmin := %g\n kmax := %g\n", kmin, kmax);
406 double pa[bfNr], pk[bfNr], yfit[sampleNr];
407 ret=spectralDExp(x, y, w, sampleNr, kmin, kmax, bfNr, pk, pa, yfit, &status);
408 if(ret!=TPCERROR_OK) {
409 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
410 tacFree(&tac); return(3);
411 }
412 if(verbose>5) {
413 printf("\n\tSolutions for each k:\n");
414 for(int bi=0; bi<bfNr; bi++) printf("\t%g\t%g\n", pk[bi], pa[bi]);
415 }
416 /* Set better k value range, if necessary */
417 if(!(pa[0]>0.0 && pa[bfNr-1]>0.0)) {
418 if(verbose>4) printf("refine k value range\n");
419 ret=spectralKRange(pk, pa, bfNr, &kmin, &kmax, &status);
420 if(ret!=TPCERROR_OK) {
421 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
422 tacFree(&tac); return(3);
423 }
424 ret=spectralDExp(x, y, w, sampleNr, kmin, kmax, bfNr, pk, pa, yfit, &status);
425 if(ret!=TPCERROR_OK) {
426 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
427 tacFree(&tac); return(3);
428 }
429 if(verbose>5) {
430 printf("solutions for each k:\n");
431 for(int bi=0; bi<bfNr; bi++) printf("\t%g\t%g\n", pk[bi], pa[bi]);
432 }
433 }
434 if(verbose>5) {
435 printf("\n\tMeasured and fitted TAC:\n");
436 for(int i=0; i<sampleNr; i++) printf("\t%g\t%g\n", y[i], yfit[i]);
437 printf("\n"); fflush(stdout);
438 }
439 /* Copy the parameter clusters, combining some of those if necessary */
440 ret=spectralBFExtract(pk, pa, bfNr, init_k, init_a, enr);
441 if(ret==0) {
442 fprintf(stderr, "Error: cannot estimate initial parameters.\n");
443 tacFree(&tac); return(3);
444 }
445 if(verbose>3) {
446 printf("\n\tInitial a and k values\n");
447 for(int i=0; i<enr; i++) printf("\t%g\t%g\n", init_a[i], init_k[i]);
448 printf("\n"); fflush(stdout);
449 }
450 }
451
452
453
454 /*
455 * Fitting
456 */
457 if(verbose>1) printf("preparing for fitting\n");
458
459 /* Set data pointers for the fit */
460 FITDATA fitdata;
461 fitdata.verbose=verbose-10;
462 fitdata.n=tac.sampleNr;
463 fitdata.x=tac.x;
464 if(tac.isframe) {fitdata.x1=tac.x1; fitdata.x2=tac.x2;} else {fitdata.x1=NULL; fitdata.x1=NULL;}
465 fitdata.yrv=tac.c[0].y;
466 fitdata.ylv=tac.c[1].y;
467 fitdata.fyrv=tac.c[2].y;
468 fitdata.fylv=tac.c[3].y;
469 fitdata.w=tac.w;
470
471
472 /* Set parameters for nonlinear optimization */
473 if(verbose>2) printf("process initial parameter values\n");
474 int parNr=8;
475 NLOPT nlo; nloptInit(&nlo);
476 ret=nloptAllocate(&nlo, parNr);
477 if(ret!=TPCERROR_OK) {
478 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
479 tacFree(&tac); return(3);
480 }
481 /* Set function */
482 nlo._fun=func_wrlv;
483 nlo.fundata=&fitdata;
484 nlo.totalNr=parNr; // Ta, Ti, A1, L1, A2, L2, dT, tau
485 nlo.maxFunCalls=50000;
486 { // Appearance time Ta
487 nlo.xlower[0]=0.8*Ta;
488 nlo.xupper[0]=1.2*Ta;
489 nlo.xfull[0]=Ta;
490 nlo.xdelta[0]=0.01*(nlo.xupper[0]-nlo.xlower[0]);
491 nlo.xtol[0]=0.02;
492 }
493 if(fixedTi>=0.0) { // Infusion duration Ti
494 nlo.xlower[1]=nlo.xupper[1]=nlo.xfull[1]=fixedTi;
495 nlo.xdelta[1]=0.0;
496 nlo.xtol[1]=0.0;
497 } else {
498 nlo.xlower[1]=1.0;
499 nlo.xfull[1]=tmax-Ta; if(nlo.xfull[1]<2.0) nlo.xfull[1]=2.0;
500 nlo.xupper[1]=1.5*nlo.xfull[1];
501 nlo.xdelta[1]=0.01*(nlo.xupper[1]-nlo.xlower[1]);
502 nlo.xtol[1]=0.1*nlo.xdelta[1];
503 }
504 { // Delay between RV and LV
505 nlo.xlower[6]=1.0;
506 nlo.xupper[6]=10.0;
507 nlo.xfull[6]=delay;
508 if(nlo.xfull[6]<=nlo.xlower[6] || nlo.xfull[6]>=nlo.xupper[6]) nlo.xfull[6]=0.5*(nlo.xlower[6]+nlo.xupper[6]);
509 nlo.xdelta[6]=0.02;
510 nlo.xtol[6]=0.001;
511 }
512 { // Dispersion between RV and LV
513 nlo.xlower[7]=1.0;
514 nlo.xupper[7]=15.0;
515 nlo.xfull[7]=tau;
516 if(nlo.xfull[7]<=nlo.xlower[7] || nlo.xfull[7]>=nlo.xupper[7]) nlo.xfull[7]=0.5*(nlo.xlower[7]+nlo.xupper[7]);
517 nlo.xdelta[7]=0.02;
518 nlo.xtol[7]=0.001;
519 }
520 { // Exponent function parameters
521 for(int i=0; i<2; i++) {
522 int ai=2+2*i;
523 int ki=ai+1;
524
525 nlo.xfull[ai]=init_a[i];
526 nlo.xlower[ai]=0.02*init_a[i];
527 nlo.xupper[ai]=10.0*init_a[i];
528 nlo.xdelta[ai]=1.0E-02*init_a[i];
529 nlo.xtol[ai]=1.0E-04*init_a[i];
530
531 nlo.xfull[ki]=init_k[i];
532 nlo.xlower[ki]=0.011*init_k[i];
533 nlo.xupper[ki]=1.5*init_k[i];
534 nlo.xdelta[ki]=1.0E-02*init_k[i]; if(!(nlo.xdelta[ki]>1.0E-05)) nlo.xdelta[ki]=1.0E-05;
535 nlo.xtol[ki]=1.0E-06*init_k[i]; if(!(nlo.xtol[ki]>1.0E-06)) nlo.xtol[ki]=1.0E-06;
536 }
537 }
538
539 /* Get nr of fixed parameters */
540 unsigned int fixedNr=nloptFixedNr(&nlo);
541 if(verbose>2) printf("fixedNr := %u\n", fixedNr);
542
543#if(0)
544 // call function for testing
545 fitdata.verbose=10;
546 double wss=func_wrlv(nlo.totalNr, nlo.xfull, &fitdata);
547 if(verbose>1) {
548 printf("\nTime\tRV\tLV\tsimRV\tsimLV\n");
549 for(unsigned int i=0; i<fitdata.n; i++) printf("%g\t%g\t%g\t%g\t%g\n", fitdata.x[i],
550 fitdata.yrv[i], fitdata.ylv[i], fitdata.fyrv[i], fitdata.fylv[i]);
551 printf("\n"); fflush(stdout);
552 }
553 if(verbose>1) {printf("\twss := %g\n", wss); fflush(stdout);}
554
555 nloptFree(&nlo);
556 tacFree(&tac);
557
558#else
559
560 /* Fit */
561 nlo.funval=nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
562 if(verbose>2) nloptWrite(&nlo, stdout);
563 if(verbose>0) {printf("fitting\n"); fflush(stdout);}
564
565 if(nloptSimplex(&nlo, 50000, &status)!=TPCERROR_OK) {
566 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
567 tacFree(&tac); nloptFree(&nlo); return(5);
568 }
569 nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
570 if(verbose>6) {
571 printf("\nTime\tRV\tLV\tsimRV\tsimLV\n");
572 for(int i=0; i<tac.sampleNr; i++) printf("%g\t%g\t%g\t%g\t%g\n", tac.x[i],
573 tac.c[0].y[i], tac.c[1].y[i], tac.c[2].y[i], tac.c[3].y[i]);
574 }
575 if(verbose>2) nloptWrite(&nlo, stdout);
576 if(verbose>2) printf(" wss := %g\n", nlo.funval);
577
578 /* Simplex again */
579 for(unsigned int i=0; i<nlo.totalNr; i++) {
580 nlo.xdelta[i]*=8.97E-02;
581 nlo.xtol[i]*=1.0E-02;
582 }
583 if(nloptSimplex(&nlo, 50000, &status)!=TPCERROR_OK) {
584 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
585 tacFree(&tac); nloptFree(&nlo); return(5);
586 }
587 nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
588 if(verbose>6) {
589 printf("\nTime\tRV\tLV\tsimRV\tsimLV\n");
590 for(int i=0; i<tac.sampleNr; i++) printf("%g\t%g\t%g\t%g\t%g\n", tac.x[i],
591 tac.c[0].y[i], tac.c[1].y[i], tac.c[2].y[i], tac.c[3].y[i]);
592 }
593 if(verbose>2) nloptWrite(&nlo, stdout);
594 if(verbose>2) printf(" wss := %g\n", nlo.funval);
595
596 /* Simplex once more */
597 for(unsigned int i=0; i<nlo.totalNr; i++) {
598 nlo.xdelta[i]*=1.23E-01;
599 nlo.xtol[i]*=1.5E-02;
600 }
601 if(nloptSimplex(&nlo, 50000, &status)!=TPCERROR_OK) {
602 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
603 tacFree(&tac); nloptFree(&nlo); return(5);
604 }
605 nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
606 if(verbose>6) {
607 printf("\nTime\tRV\tLV\tsimRV\tsimLV\n");
608 for(int i=0; i<tac.sampleNr; i++) printf("%g\t%g\t%g\t%g\t%g\n", tac.x[i],
609 tac.c[0].y[i], tac.c[1].y[i], tac.c[2].y[i], tac.c[3].y[i]);
610 }
611 if(verbose>2) nloptWrite(&nlo, stdout);
612 if(verbose>2) printf(" wss := %g\n", nlo.funval);
613
614
615
616 /*
617 * Copy function parameters into PAR structure for printing and saving
618 */
619 PAR par; parInit(&par);
620 ret=parAllocateWithTAC(&par, &tac, nlo.totalNr, &status);
621 if(ret!=TPCERROR_OK) {
622 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
623 tacFree(&tac); nloptFree(&nlo); return(10);
624 }
625 par.tacNr=2; par.parNr=nlo.totalNr;
627 {
628 char buf[256];
629 time_t t=time(NULL);
630 iftPut(&par.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
631 tpcProgramName(argv[0], 1, 1, buf, 256);
632 iftPut(&par.h, "program", buf, 0, NULL);
633 }
634 iftPut(&par.h, "datafile", tacfile, 0, NULL);
635 par.r[0].model=modelCodeIndex("ebolinf");
636 par.r[0].dataNr=tacWSampleNr(&tac);
637 par.r[0].start=xmin;
638 par.r[0].end=xmax;
639 par.r[0].wss=nlo.funval;
640 par.r[0].fitNr=nlo.totalNr-fixedNr;
641 par.r[1].model=modelCodeIndex("ebolinfdd");
642 par.r[1].dataNr=tacWSampleNr(&tac);
643 par.r[1].start=xmin;
644 par.r[1].end=xmax;
645 par.r[1].wss=nlo.funval;
646 par.r[1].fitNr=nlo.totalNr-fixedNr;
647 /* Set parameter names and units */
648 strcpy(par.n[0].name, "Ta"); par.n[0].unit=tac.tunit;
649 strcpy(par.n[1].name, "Ti"); par.n[1].unit=tac.tunit;
650 strcpy(par.n[2].name, "A1"); par.n[2].unit=tac.cunit;
651 strcpy(par.n[3].name, "L1"); par.n[3].unit=unitInverse(tac.tunit);
652 strcpy(par.n[4].name, "A2"); par.n[4].unit=tac.cunit;
653 strcpy(par.n[5].name, "L2"); par.n[5].unit=unitInverse(tac.tunit);
654 strcpy(par.n[6].name, "dT"); par.n[6].unit=tac.tunit;
655 strcpy(par.n[7].name, "tau"); par.n[7].unit=tac.tunit;
656 /* Set parameter values in correct order, and write lambda's as positive values */
657 par.r[0].p[0]=par.r[1].p[0]=nlo.xfull[0];
658 par.r[0].p[1]=par.r[1].p[1]=nlo.xfull[1];
659 par.r[0].p[2]=par.r[1].p[2]=nlo.xfull[2];
660 par.r[0].p[3]=par.r[1].p[3]=+nlo.xfull[3];
661 par.r[0].p[4]=par.r[1].p[4]=nlo.xfull[4];
662 par.r[0].p[5]=par.r[1].p[5]=+nlo.xfull[5];
663 par.r[0].p[6]=0.0; par.r[1].p[6]=nlo.xfull[6];
664 par.r[0].p[7]=0.0; par.r[1].p[7]=nlo.xfull[7];
665 /* Print and save */
666 if(verbose>0) parWrite(&par, stdout, PAR_FORMAT_TSV_UK, 1, NULL);
667 if(parfile[0]) {
668 par.format=parFormatFromExtension(parfile);
669 if(verbose>2) printf("parameter file format := %s\n", parFormattxt(par.format));
671 /* Save file */
672 if(verbose>1) printf(" saving %s\n", parfile);
673 FILE *fp=fopen(parfile, "w");
674 if(fp==NULL) {
675 fprintf(stderr, "Error: cannot open file for writing.\n");
676 tacFree(&tac); nloptFree(&nlo); parFree(&par); return(11);
677 }
678 ret=parWrite(&par, fp, PAR_FORMAT_UNKNOWN, 1, &status);
679 fclose(fp);
680 if(ret!=TPCERROR_OK) {
681 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
682 tacFree(&tac); nloptFree(&nlo); parFree(&par); return(12);
683 }
684 if(verbose>0) printf("parameters saved in %s\n", parfile);
685 }
686
687
688 /*
689 * Plot measured and fitted data, if requested
690 */
691 if(svgfile[0]) {
692 if(verbose>1) printf("plotting measured and fitted data\n");
693 TAC fit; tacInit(&fit);
694 (void)tacDuplicate(&tac, &fit);
695 for(int i=0; i<tac.sampleNr; i++) {fit.c[0].y[i]=tac.c[2].y[i]; fit.c[1].y[i]=tac.c[3].y[i];}
696 /* Plot */
697 ret=tacPlotFitSVG(&tac, &fit, "", nan(""), nan(""), nan(""), nan(""), svgfile, &status);
698 if(ret!=TPCERROR_OK) {
699 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
700 tacFree(&tac); tacFree(&fit); nloptFree(&nlo); parFree(&par);
701 return(21);
702 }
703 if(verbose>0) printf("Measured and fitted data plotted in %s\n", svgfile);
704 tacFree(&fit);
705 }
706
707 nloptFree(&nlo); parFree(&par);
708 tacFree(&tac);
709
710#endif
711 return(0);
712}
713/*****************************************************************************/
714
715/*****************************************************************************
716 *
717 * Functions to be minimized
718 *
719 *****************************************************************************/
720double func_disp(int parNr, double *p, void *fdata)
721{
722 FITDATA *d=(FITDATA*)fdata;
723
724 if(d->verbose>0) {printf("%s()\n", __func__); fflush(stdout);}
725 if(parNr!=2) return(nan(""));
726 if(d->verbose>20) printf("p[]: %g %g\n", p[0], p[1]);
727
728 /* Add dispersion to the input TAC */
729 double dtac[2*d->n];
730 double *buf=dtac+d->n;
731 for(unsigned int i=0; i<d->n; i++) dtac[i]=d->yrv[i];
732 if(simDispersion(d->x, dtac, d->n, p[0], 0.0, buf)) return(nan(""));
733
734 /* Add delay and interpolate to output sample times */
735 for(unsigned int i=0; i<d->n; i++) buf[i]=d->x[i]+p[1];
736 if(liInterpolate(buf, dtac, d->n, d->x, d->fylv, NULL, NULL, d->n, 0, 1, 0)!=0) return(nan(""));
737
738 /* Calculate the weighted SS */
739 double wss=0.0;
740 for(unsigned int i=0; i<d->n; i++) {
741 double v=d->fylv[i]-d->ylv[i];
742 wss+=d->w[i]*v*v;
743 }
744
745 return(wss);
746}
747
748/*****************************************************************************/
749
750
751double func_wrlv(int parNr, double *p, void *fdata)
752{
753 FITDATA *d=(FITDATA*)fdata;
754
755 if(d->verbose>0) {printf("%s()\n", __func__); fflush(stdout);}
756 if(parNr!=8 || p==NULL || fdata==NULL || d->n<1) return(nan(""));
757 if(d->verbose>20) {
758 printf("p[]: %g", p[0]);
759 for(int i=1; i<parNr; i++) printf(" %g", p[i]);
760 printf("\n"); fflush(stdout);
761 }
762
763 /* Process parameters */
764 double Ta=p[0];
765 double Ti=p[1];
766 double A[3], L[3], ApL[3];
767 A[0]=p[2]; L[0]=p[3]; A[1]=p[4]; L[1]=p[5]; A[2]=0.0; L[2]=0.0;
768 double deltaT=p[6];
769 double tau=p[7];
770 /* derived parameters */
771 double one_per_Ti; if(Ti>0.0) one_per_Ti=1.0/Ti; else one_per_Ti=1.0;
772 for(int i=0; i<3; i++) if(L[i]>1.0E-12) ApL[i]=A[i]/L[i]; else ApL[i]=A[i];
773
774 /* Compute function value at each sample time */
775 for(unsigned int fi=0; fi<d->n; fi++) {
776 double t=d->x[fi];
777 if(t<=Ta) {
778 d->fyrv[fi]=0.0;
779 } else if(t<Ta+Ti) {
780 double f=0.0;
781 for(int i=0; i<3; i++) {
782 double e2=-L[i]*(t-Ta);
783 if(e2>-0.000001) e2=1.0; else if(e2<-50) e2=0.0; else e2=exp(e2);
784 f+=ApL[i]*(1.0-e2);
785 }
786 if(Ti>0.0) f*=one_per_Ti;
787 d->fyrv[fi]=f;
788 } else {
789 double f=0.0;
790 for(int i=0; i<3; i++) {
791 double e1=-L[i]*(t-Ta-Ti);
792 if(e1>-0.000001) e1=1.0; else if(e1<-50) e1=0.0; else e1=exp(e1);
793 double e2=-L[i]*(t-Ta);
794 if(e2>-0.000001) e2=1.0; else if(e2<-50) e2=0.0; else e2=exp(e2);
795 f+=ApL[i]*(e1-e2);
796 }
797 if(Ti>0.0) f*=one_per_Ti;
798 d->fyrv[fi]=f;
799 }
800 }
801
802 /* Copy RV TAC to LV TAC with delay */
803 if(deltaT>0.0) {
804 double xt[d->n];
805 for(unsigned int fi=0; fi<d->n; fi++) xt[fi]=d->x[fi]+deltaT;
806 if(liInterpolate(xt, d->fyrv, d->n, d->x, d->fylv, NULL, NULL, d->n, 0, 1, 0)!=0) return(nan(""));
807 } else {
808 for(unsigned int fi=0; fi<d->n; fi++) d->fylv[fi]=d->fyrv[fi];
809 }
810
811 /* Add dispersion to LV TAC if required */
812 if(tau>0.0) (void)simDispersion(d->x, d->fylv, d->n, tau, 0.0, NULL);
813
814 /* Calculate the weighted SS */
815 if(d->verbose>2) {fprintf(stdout, "computing WSS...\n"); fflush(stdout);}
816 double wss=0.0;
817 for(unsigned i=0; i<d->n; i++) {
818 double v1=d->fyrv[i] - d->yrv[i];
819 double v2=d->fylv[i] - d->ylv[i];
820 wss+=d->w[i]*(v1*v1 + v2*v2);
821 }
822 if(d->verbose>1) {
823 for(int i=0; i<parNr; i++) printf(" %g", p[i]);
824 printf(" -> %g\n", wss); fflush(stdout);
825 }
826
827 return(wss);
828}
829/*****************************************************************************/
830
831/*****************************************************************************/
int spectralDExp(const double *x, const double *y, double *w, const int snr, const double kmin, const double kmax, const int bnr, double *k, double *a, double *yfit, TPCSTATUS *status)
Definition bf_dexp.c:28
int spectralKRange(double *k, double *a, const int n, double *kmin, double *kmax, TPCSTATUS *status)
Definition bf_dexp.c:145
int spectralBFExtract(double *k, double *a, const int n, double *ke, double *ae, const int ne)
Definition bf_dexp.c:227
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
double atofVerified(const char *s)
Definition decpoint.c:75
unsigned int doubleRange(double *a, const unsigned int n, double *amin, double *amax)
Definition doubleutil.c:174
unsigned int drandSeed(short int seed)
Make and optionally set the seed for rand(), drand, drandRange, and drandGaussian().
Definition gaussdev.c:27
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.
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
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
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 highestSlope(double *x, double *y, const int n, const int slope_n, double x_start, double *m, double *yi, double *xi, double *xh)
Definition regression.c:179
int simDispersion(double *x, double *y, const int n, const double tau1, const double tau2, double *tmp)
int nloptSimplex(NLOPT *nlo, unsigned int maxIter, TPCSTATUS *status)
Definition simplex.c:32
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
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 fitNr
Definition tpcpar.h:58
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
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
unit tunit
Definition tpctac.h:109
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 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 tacNaNs(TAC *tac)
Definition tacnan.c:71
int tacSortByTime(TAC *d, TPCSTATUS *status)
Definition tacorder.c:74
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 tacGetSampleInterval(TAC *d, double ilimit, double *minfdur, double *maxfdur)
Get the shortest and longest sampling intervals or frame lengths in TAC structure.
Definition tacx.c:832
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Definition tacx.c:124
int tacYRange(TAC *d, int i, double *ymin, double *ymax, int *smin, int *smax, int *imin, int *imax)
Get the range of y values (concentrations) in TAC struct.
Definition tacy.c:26
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_MIN
minutes
@ UNIT_UNKNOWN
Unknown unit.
@ UNIT_SEC
seconds
int unitInverse(int u)
Definition units.c:654
@ 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.
@ 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.
Header file for libtpctacmod.