TPCCLIB
Loading...
Searching...
No Matches
fit_dexp.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 "tpcbfm.h"
20#include "tpctacmod.h"
21#include "tpclinopt.h"
22#include "tpcrand.h"
23#include "tpcnlopt.h"
24/*****************************************************************************/
25
26/*****************************************************************************/
27/* Local functions */
28double func_exp(int parNr, double *p, void*);
29/*****************************************************************************/
30typedef struct FITDATA {
32 unsigned int n;
34 double *x;
36 double *ymeas;
38 double *ysim;
40 double *w;
41} FITDATA;
42/*****************************************************************************/
43
44/*****************************************************************************/
45static char *info[] = {
46 "Non-linear fitting of the sum of 1-5 exponential functions to decaying",
47 "time-activity curve (TAC).",
48 " ",
49 "Function:",
50 " ",
51 " f(x) = a1*exp(k1*x) + a2*exp(k2*x) + a3*exp(k3*x) + ...",
52 " ",
53 ", where a's > 0 and k's < 0.",
54 " ",
55 "Usage: @P [Options] tacfile [parfile]",
56 " ",
57 "Options:",
58 " -5 | -4 | -3 | -2 | -1 | -1BL",
59 " Fit to sum of specified number of exponential functions, or",
60 " monoexponential with baseline; by default determined automatically.",
61 " -w1",
62 " All weights are set to 1.0 (no weighting); by default, weights in",
63 " data file are used, if available.",
64 " -wf",
65 " Weight by sampling interval.",
66 " -svg=<Filename>",
67 " Fitted and measured TACs are plotted in specified SVG file.",
68 " -nr=<value>",
69 " Number of basis functions, used in determination of initial parameter",
70 " estimates and number of exponentials for nonlinear fitting;",
71 " default is 100.",
72 " -peak | -peak1",
73 " Fit is started only at the TAC peak, or at the next sample after peak.",
74 " -stdoptions", // List standard options like --help, -v, etc
75 " ",
76 "If TAC file contains more than one TAC, only the first is used.",
77 "Function parameters are written in fit format.",
78 " ",
79 "See also: extrapol, fit_exp, fit_fexp, fit2dat, fit2auc, paucinf, tacln",
80 " ",
81 "Keywords: TAC, curve fitting, extrapolation",
82 0};
83/*****************************************************************************/
84
85/*****************************************************************************/
86/* Turn on the globbing of the command line, since it is disabled by default in
87 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
88 In Unix&Linux wildcard command line processing is enabled by default. */
89/*
90#undef _CRT_glob
91#define _CRT_glob -1
92*/
93int _dowildcard = -1;
94/*****************************************************************************/
95
96/*****************************************************************************/
100int main(int argc, char **argv)
101{
102 int ai, help=0, version=0, verbose=1;
103 char tacfile[FILENAME_MAX], parfile[FILENAME_MAX], svgfile[FILENAME_MAX];
104 int weights=0; // 0=default, 1=no weighting, 2=frequency
105 int bfNr=100;
106 int expnr=0;
107 int peakMode=0; // 0=fit all, 1=fit from peak, 2=fit from peak+1
108 int ret;
109 unsigned int model=0;
110 int baseline=0; // last exponential term is freely fitted (0) or set to zero (1)
111
112
113 /*
114 * Get arguments
115 */
116 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
117 tacfile[0]=parfile[0]=svgfile[0]=(char)0;
118 /* Options */
119 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
120 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
121 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
122 if(strcasecmp(cptr, "W1")==0) {
123 weights=1; continue;
124 } else if(strcasecmp(cptr, "WF")==0) {
125 weights=2; continue;
126 } else if(strncasecmp(cptr, "NR=", 3)==0) {
127 if(atoiCheck(cptr+3, &bfNr)==0 && bfNr>5) continue;
128 } else if(strcasecmp(cptr, "5")==0 || strcasecmp(cptr, "5e")==0) {
129 expnr=5; model=modelCodeIndex("5exp"); continue;
130 } else if(strcasecmp(cptr, "4")==0 || strcasecmp(cptr, "4e")==0) {
131 expnr=4; model=modelCodeIndex("4exp"); continue;
132 } else if(strcasecmp(cptr, "3")==0 || strcasecmp(cptr, "3e")==0) {
133 expnr=3; model=modelCodeIndex("3exp"); continue;
134 } else if(strcasecmp(cptr, "2")==0 || strcasecmp(cptr, "2e")==0) {
135 expnr=2; model=modelCodeIndex("2exp"); continue;
136 } else if(strcasecmp(cptr, "1")==0 || strcasecmp(cptr, "1e")==0) {
137 expnr=1; model=modelCodeIndex("1exp"); continue;
138 } else if(strcasecmp(cptr, "1BL")==0 || strcasecmp(cptr, "1eBL")==0) {
139 expnr=2; model=modelCodeIndex("2exp"); baseline=1; continue;
140 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
141 strlcpy(svgfile, cptr+4, FILENAME_MAX); continue;
142 } else if(strcasecmp(cptr, "PEAK")==0) {
143 peakMode=1; continue;
144 } else if(strcasecmp(cptr, "PEAK1")==0) {
145 peakMode=2; continue;
146 }
147 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
148 return(1);
149 } else break;
150
151 TPCSTATUS status; statusInit(&status);
152 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
153 status.verbose=verbose-3;
154
155 /* Print help or version? */
156 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
157 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
158 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
159
160 /* Process other arguments, starting from the first non-option */
161 if(ai<argc) strlcpy(tacfile, argv[ai++], FILENAME_MAX);
162 if(ai<argc) strlcpy(parfile, argv[ai++], FILENAME_MAX);
163 if(ai<argc) {
164 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
165 return(1);
166 }
167 /* Did we get all the information that we need? */
168 if(!tacfile[0]) {
169 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
170 return(1);
171 }
172
173
174 /* In verbose mode print arguments and options */
175 if(verbose>1) {
176 printf("tacfile := %s\n", tacfile);
177 if(parfile[0]) printf("parfile := %s\n", parfile);
178 if(svgfile[0]) printf("svgfile := %s\n", svgfile);
179 if(expnr>0) printf("expnr := %d\n", expnr);
180 if(expnr==2) printf("baseline := %d\n", baseline);
181 printf("bfNr := %d\n", bfNr);
182 printf("weights := %d\n", weights);
183 printf("peakMode := %d\n", peakMode);
184 fflush(stdout);
185 }
186
187
188
189 /*
190 * Read TAC data
191 */
192 if(verbose>1) printf("reading %s\n", tacfile);
193 TAC tac; tacInit(&tac);
194 ret=tacRead(&tac, tacfile, &status);
195 if(ret!=TPCERROR_OK) {
196 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
197 tacFree(&tac); return(2);
198 }
199 if(verbose>1) {
200 printf("fileformat := %s\n", tacFormattxt(tac.format));
201 printf("tacNr := %d\n", tac.tacNr);
202 printf("sampleNr := %d\n", tac.sampleNr);
203 printf("xunit := %s\n", unitName(tac.tunit));
204 printf("yunit := %s\n", unitName(tac.cunit));
205 printf("isframe := %d\n", tac.isframe);
206 }
207 if(tac.tacNr<1) {
208 fprintf(stderr, "Error: file contains no data.\n");
209 tacFree(&tac); return(2);
210 }
211 if(tac.tacNr>1) {
212 fprintf(stderr, "Warning: file contains %d TACs; using the first one.\n", tac.tacNr);
213 tac.tacNr=1;
214 }
215 if(tac.sampleNr<3) {
216 fprintf(stderr, "Error: too few samples.\n");
217 tacFree(&tac); return(2);
218 }
219 /* Check NaNs */
220 if(tacNaNs(&tac)>0) {
221 fprintf(stderr, "Error: data contains missing values.\n");
222 tacFree(&tac); return(2);
223 }
224 if(tac.sampleNr<3) {
225 fprintf(stderr, "Error: too few samples.\n");
226 tacFree(&tac); return(2);
227 }
228 /* Sort data by sample time */
229 tacSortByTime(&tac, &status);
230 /* Check and set weights */
231 if(weights==0) {
232 if(!tacIsWeighted(&tac)) {
234 for(int i=0; i<tac.sampleNr; i++) tac.w[i]=1.0;
235 }
236 } else if(weights==1) {
238 for(int i=0; i<tac.sampleNr; i++) tac.w[i]=1.0;
239 } else if(weights==2) {
240 ret=tacWByFreq(&tac, ISOTOPE_UNKNOWN, &status);
241 if(ret!=TPCERROR_OK) {
242 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
243 tacFree(&tac); return(2);
244 }
245 }
246
247
248 /* Get the index of TAC peak */
249 {
250 TAC ptac; tacInit(&ptac);
251 /* Take average of any duplicate samples */
252 if(tacMultipleSamples(&tac, 1, &ptac, verbose-2)!=0) {
253 fprintf(stderr, "Error: cannot process possible duplicates.\n");
254 tacFree(&tac); tacFree(&ptac); return(2);
255 }
256 if(ptac.sampleNr<3) {
257 fprintf(stderr, "Error: too few sample times.\n");
258 tacFree(&tac); tacFree(&ptac); return(2);
259 }
260 /* Find peak value and its sample index */
261 double ymin, ymax; int imax;
262 if(tacYRange(&ptac, 0, &ymin, &ymax, NULL, &imax, NULL, NULL)!=0) {
263 fprintf(stderr, "Error: no maximum found for TAC.\n");
264 tacFree(&tac); tacFree(&ptac); return(2);
265 }
266 if(verbose>2) {
267 printf(" minv := %g\n", ymin);
268 printf(" maxv := %g\n", ymax);
269 printf(" maxx := %g\n", ptac.x[imax]);
270 }
271 if(imax>0 && peakMode==0 && verbose>0) {
272 fprintf(stderr, "Warning: TAC does not start with peak.\n");
273 }
274 if(!((ymax-ymin)>0.0) || !(ymax>0.0)) {
275 fprintf(stderr, "Error: invalid TAC value range.\n");
276 tacFree(&tac); tacFree(&ptac); return(2);
277 }
278 if(peakMode>0) {
279 if(imax>ptac.sampleNr-3) {
280 fprintf(stderr, "Error: too few sample times after the peak.\n");
281 tacFree(&tac); tacFree(&ptac); return(2);
282 }
283 /* Delete samples before the peak */
284 double tstart=ptac.x[imax]; if(peakMode==2) tstart=ptac.x[imax+1];
285 if(verbose>1) printf("starting fit from %g\n", tstart);
286 int ret=tacExtractRange(&tac, &tac, tstart, 1.1*ptac.x[ptac.sampleNr-1]);
287 if(ret!=TPCERROR_OK) {
288 fprintf(stderr, "Error: cannot exclude pre-peak data.\n");
289 tacFree(&tac); tacFree(&ptac); return(2);
290 }
291 }
292 tacFree(&ptac);
293 }
294
295
296 /*
297 * Get the first sample distance (that is > 0)
298 */
299 double sdist=0.0;
300 {
301 for(int i=1; i<tac.sampleNr; i++) {
302 sdist=tac.x[i]-tac.x[i-1];
303 if(sdist>0.0) break;
304 }
305 if(!(sdist>0.0)) {
306 fprintf(stderr, "Error: invalid sample times.\n");
307 tacFree(&tac); return(2);
308 }
309 }
310 if(verbose>1) {
311 printf("sdist := %g\n", sdist);
312 }
313
314 if(verbose>1) printf("determining initial parameter estimates\n");
315 double ymin, ymax, xmin, xmax;
316 tacYRange(&tac, 0, &ymin, &ymax, NULL, NULL, NULL, NULL);
317 tacXRange(&tac, &xmin, &xmax);
318 if(verbose>2) {
319 printf(" fitrange_minv := %g\n", ymin);
320 printf(" fitrange_maxv := %g\n", ymax);
321 printf(" fitrange_minx := %g\n", xmin);
322 printf(" fitrange_maxx := %g\n", xmax);
323 }
324
325 /*
326 * Spectral analysis to find better range of parameters
327 */
328 if(verbose>2) printf("estimating initial k value range\n");
329 double kmin, kmax; // kmin must be >0
330 kmin=1.0E-06/xmax; // e^(-k*xmax) still almost 1
331 kmax=3.0/(xmin+sdist); // e^(-k*(xmin+sdist) is about 0.01
332 if(kmax<100.0*kmin) kmax=100.0*kmin;
333
334// kmax=-log(yrange*1.0E-06)/tac.x[0]; if(kmax>100.) kmax=100.;
335
336
337 if(verbose>2) printf(" kmin := %g\n kmax := %g\n", kmin, kmax);
338 double pa[bfNr], pk[bfNr], yfit[tac.sampleNr];
339 ret=spectralDExp(tac.x, tac.c[0].y, tac.w, tac.sampleNr, kmin, kmax, bfNr,
340 pk, pa, yfit, &status);
341 if(ret!=TPCERROR_OK) {
342 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
343 tacFree(&tac); return(3);
344 }
345 if(verbose>2) {
346 printf("solutions for each k:\n");
347 for(int bi=0; bi<bfNr; bi++) printf("\t%g\t%g\n", pk[bi], pa[bi]);
348 }
349 if(verbose>5) {
350 printf("measured and fitted TAC:\n");
351 for(int i=0; i<tac.sampleNr; i++)
352 printf("\t%g\t%g\n", tac.c[0].y[i], yfit[i]);
353 }
354
355 /* Set better k value range */
356 if(!(pa[0]>0.0 && pa[bfNr-1]>0.0)) {
357 if(verbose>2) printf("refine k value range\n");
358 ret=spectralKRange(pk, pa, bfNr, &kmin, &kmax, &status);
359 if(ret!=TPCERROR_OK) {
360 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
361 tacFree(&tac); return(3);
362 }
363 if(kmax<2.0*kmin) {kmax=2.0*kmin; kmin*=0.5;}
364 if(verbose>2) printf(" refined kmin := %g\n kmax := %g\n", kmin, kmax);
365 ret=spectralDExp(tac.x, tac.c[0].y, tac.w, tac.sampleNr, kmin, kmax, bfNr,
366 pk, pa, yfit, &status);
367 if(ret!=TPCERROR_OK) {
368 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
369 tacFree(&tac); return(3);
370 }
371 if(verbose>4) {
372 printf("solutions for each k:\n");
373 for(int bi=0; bi<bfNr; bi++) printf("\t%g\t%g\n", pk[bi], pa[bi]);
374 }
375 if(verbose>3) {
376 printf("measured and fitted TAC:\n");
377 for(int i=0; i<tac.sampleNr; i++)
378 printf("\t%g\t%g\n", tac.c[0].y[i], yfit[i]);
379 }
380 }
381 if(verbose>2) {
382 double v, init_wss=0.0;
383 for(int i=0; i<tac.sampleNr; i++) {
384 v=tac.c[0].y[i]-yfit[i];
385 init_wss+=tac.w[i]*v*v;
386 }
387 printf(" initial_wss := %g\n", init_wss);
388 }
389
390 /* Get max a parameter to be used as basis of upper limit */
391 double amax=pa[doubleMaxIndex(pa, bfNr)];
392 if(verbose>3) printf("max_a := %g\n", amax);
393
394
395 /* Calculate how many zero-separated basis functions there really were */
396 int fbfNr=spectralBFNr(pk, pa, bfNr);
397 if(verbose>2) printf("fbfNr := %d\n", fbfNr);
398 if(fbfNr<1) {
399 fprintf(stderr, "Error: cannot estimate initial parameters.\n");
400 tacFree(&tac); return(3);
401 }
402
403
404 /* If user did not give the nr of exponentials, then set it here */
405 if(expnr==0) {
406 expnr=fbfNr;
407 if(expnr>5) expnr=5; // there should be no need for more
408 if(verbose>1) printf("expnr := %d\n", expnr);
409 char s[8]; sprintf(s, "%dexp", expnr);
410 model=modelCodeIndex(s);
411 }
412
413 /* Extract parameters for at most expnr exponentials */
414 double init_k[expnr], init_a[expnr];
415 ret=spectralBFExtract(pk, pa, bfNr, init_k, init_a, expnr);
416 if(ret<1) {
417 fprintf(stderr, "Error: cannot estimate initial parameters.\n");
418 tacFree(&tac); return(3);
419 }
420 if(verbose>2) {
421 printf("\n\tClustered a and k values\n");
422 for(int i=0; i<expnr; i++) printf("\t%g\t%g\n", init_a[i], init_k[i]);
423 printf("\n"); fflush(stdout);
424 }
425
426 /* Copy parameters as initial values for nonlinear optimization */
427 NLOPT ipar; nloptInit(&ipar);
428 ret=nloptAllocate(&ipar, 2*expnr); // a[0], k[0], a[1], k[1], a[2], ...
429 if(ret!=TPCERROR_OK) {
430 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
431 tacFree(&tac); return(3);
432 }
433 ipar.totalNr=2*expnr;
434 for(int ei=0; ei<expnr; ei++) {
435 /* A */
436 int pi=2*ei;
437 ipar.xfull[pi]=init_a[ei];
438 ipar.xlower[pi]=0.0;
439 ipar.xupper[pi]=10.0*init_a[ei];
440 ipar.xdelta[pi]=0.05*ipar.xfull[pi];
441 ipar.xtol[pi]=fabs(0.001*ipar.xdelta[pi]);
442 /* k */
443 pi++;
444 ipar.xfull[pi]=init_k[ei];
445 ipar.xlower[pi]=0.0;
446 ipar.xupper[pi]=10.0*ipar.xfull[pi]; if(ipar.xupper[pi]<10.0) ipar.xupper[pi]=10.0;
447 ipar.xdelta[pi]=0.05*ipar.xfull[pi];
448 ipar.xtol[pi]=fabs(0.001*ipar.xdelta[pi]);
449 }
450 if(expnr==2 && baseline!=0) {
451 int pi=3; if(fabs(ipar.xfull[1])<fabs(ipar.xfull[3])) pi=1;
452 ipar.xfull[pi]=ipar.xlower[pi]=ipar.xupper[pi]=ipar.xdelta[pi]=ipar.xtol[pi]=0.0;
453 }
454 nloptRemoveEmpties(&ipar);
455 if(verbose>2) {
456 printf("Initial parameters for optimization:\n");
457 nloptWrite(&ipar, stdout); fflush(stdout);
458 }
459
460
461 /* Get nr of fixed parameters before deltas are modified between fittings */
462 unsigned int fixedNr=nloptFixedNr(&ipar);
463
464
465 /*
466 * Nonlinear optimization:
467 * Simplex
468 */
469 if(verbose>1) printf("starting nonlinear optimization\n");
470 /* Set function */
471 ipar._fun=func_exp;
472 /* Set data pointers for the fit */
473 FITDATA fitdata;
474 fitdata.n=tac.sampleNr;
475 fitdata.x=tac.x;
476 fitdata.ymeas=tac.c[0].y;
477 fitdata.ysim=yfit;
478 fitdata.w=tac.w;
479 ipar.fundata=&fitdata;
480 if(verbose>2) printf("1st non-linear optimization\n");
481 ret=nloptSimplex(&ipar, 0, &status);
482 if(ret!=TPCERROR_OK) {
483 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
484 tacFree(&tac); nloptFree(&ipar); return(4);
485 }
486 if(verbose>3) nloptWrite(&ipar, stdout);
487 if(verbose>6) {
488 printf("measured and fitted TAC:\n");
489 for(int i=0; i<tac.sampleNr; i++)
490 printf("\t%g\t%g\n", tac.c[0].y[i], yfit[i]);
491 }
492 if(verbose>3) {
493 double v, final_wss=0.0;
494 for(int i=0; i<tac.sampleNr; i++) {
495 v=tac.c[0].y[i]-yfit[i];
496 final_wss+=tac.w[i]*v*v;
497 }
498 printf(" final_wss := %g\n", final_wss);
499 }
500 /* Simplex again, with new deltas */
501 for(unsigned int i=0; i<ipar.totalNr; i++) {
502 if(fabs(ipar.xdelta[i])<1.0E-100) continue;
503 if(ipar.xfull[i]>1.0E-06) ipar.xdelta[i]=0.0103*ipar.xfull[i];
504 else ipar.xdelta[i]*=0.0103;
505 }
506 if(verbose>2) printf("non-linear optimization, 2nd time\n");
507 ret=nloptSimplex(&ipar, 0, &status);
508 if(ret!=TPCERROR_OK) {
509 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
510 tacFree(&tac); nloptFree(&ipar); return(4);
511 }
512 if(verbose>3) nloptWrite(&ipar, stdout);
513 if(verbose>6) {
514 printf("measured and fitted TAC:\n");
515 for(int i=0; i<tac.sampleNr; i++)
516 printf("\t%g\t%g\n", tac.c[0].y[i], yfit[i]);
517 }
518 if(verbose>3) {
519 double v, final_wss=0.0;
520 for(int i=0; i<tac.sampleNr; i++) {
521 v=tac.c[0].y[i]-yfit[i];
522 final_wss+=tac.w[i]*v*v;
523 }
524 printf(" final_final_wss := %g\n", final_wss);
525 }
526 /* and Simplex again, with new deltas */
527 for(unsigned int i=0; i<ipar.totalNr; i++) {
528 ipar.xdelta[i]=0.093*ipar.xdelta[i];
529 }
530 if(verbose>2) printf("non-linear optimization, 3rd time\n");
531 ret=nloptSimplex(&ipar, 0, &status);
532 if(ret!=TPCERROR_OK) {
533 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
534 tacFree(&tac); nloptFree(&ipar); return(4);
535 }
536 /* Call objective function again with the final parameters */
537 (void)func_exp(ipar.totalNr, ipar.xfull, ipar.fundata);
538 if(verbose>3) nloptWrite(&ipar, stdout);
539 if(verbose>6) {
540 printf("measured and fitted TAC:\n");
541 for(int i=0; i<tac.sampleNr; i++)
542 printf("\t%g\t%g\n", tac.c[0].y[i], yfit[i]);
543 }
544 double final_wss=0.0;
545 {
546 double v;
547 for(int i=0; i<tac.sampleNr; i++) {
548 v=tac.c[0].y[i]-yfit[i];
549 final_wss+=tac.w[i]*v*v;
550 }
551 if(verbose>3) printf(" final_final_final_wss := %g\n", final_wss);
552 }
553
554
555 /*
556 * Copy function parameters into PAR struct for printing and saving
557 */
558 PAR par; parInit(&par);
559 ret=parAllocateWithTAC(&par, &tac, ipar.totalNr, &status);
560 if(ret!=TPCERROR_OK) {
561 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
562 tacFree(&tac); nloptFree(&ipar); return(6);
563 }
564 par.tacNr=1; par.parNr=ipar.totalNr;
566 par.r[0].model=model;
567 par.r[0].dataNr=tacWSampleNr(&tac);
568 par.r[0].start=tac.x[0];
569 par.r[0].end=tac.x[tac.sampleNr-1];
570 par.r[0].wss=final_wss;
571 par.r[0].fitNr=ipar.totalNr-fixedNr;
572 /* Set parameter names and units */
573 for(int i=0; i<par.parNr; i+=2) {
574 sprintf(par.n[i].name, "a%d", 1+i/2);
575 sprintf(par.n[i+1].name, "k%d", 1+i/2);
576 par.n[i].unit=tac.cunit;
577 par.n[i+1].unit=unitInverse(tac.tunit);
578 }
579 /* Set parameters in opposite order, and write k's as negatives */
580 for(unsigned int i=0; i<ipar.totalNr; i+=2) {
581 par.r[0].p[par.parNr-2-i]=ipar.xfull[i];
582 par.r[0].p[par.parNr-1-i]=-ipar.xfull[i+1];
583 }
584 /* Print and save */
585 if(verbose>0) parWrite(&par, stdout, PAR_FORMAT_TSV_UK, 1, NULL);
586 if(parfile[0]) {
587 /* Set file format */
588 par.format=parFormatFromExtension(parfile);
589 if(verbose>2) printf("parameter file format := %s\n", parFormattxt(par.format));
591 /* set header contents */
592 {
593 iftPut(&par.h, "datafile", tacfile, 0, NULL);
594 {
595 char buf[256];
596 time_t t=time(NULL);
597 iftPut(&par.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
598 tpcProgramName(argv[0], 1, 1, buf, 256);
599 iftPut(&par.h, "program", buf, 0, NULL);
600 }
601 }
602 /* Save file */
603 if(verbose>1) printf(" saving %s\n", parfile);
604 FILE *fp=fopen(parfile, "w");
605 if(fp==NULL) {
606 fprintf(stderr, "Error: cannot open file for writing.\n");
607 tacFree(&tac); nloptFree(&ipar); parFree(&par); return(11);
608 }
609 ret=parWrite(&par, fp, PAR_FORMAT_UNKNOWN, 1, &status);
610 fclose(fp);
611 if(ret!=TPCERROR_OK) {
612 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
613 tacFree(&tac); nloptFree(&ipar); parFree(&par); return(12);
614 }
615 if(verbose>0) printf("parameters saved in %s\n", parfile);
616 }
617
618
619 /*
620 * Plot measured and fitted data, if requested
621 */
622 if(svgfile[0]) {
623 if(verbose>1) printf("plotting measured and fitted data\n");
624 /* Prepare place for function TAC */
625 int snr;
626 snr=(int)simSamples(0.2*sdist, 0.0, par.r[0].end-par.r[0].start, 2, NULL);
627 TAC ftac; tacInit(&ftac);
628 ret=tacAllocate(&ftac, snr, 1);
629 if(ret!=TPCERROR_OK) {
630 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
631 tacFree(&tac); nloptFree(&ipar); parFree(&par); return(21);
632 }
633 ftac.tacNr=1; ftac.sampleNr=snr;
634 ret=tacCopyHdr(&tac, &ftac);
635 if(ret==TPCERROR_OK) ret=tacCopyTacchdr(tac.c, ftac.c);
636 if(ret!=TPCERROR_OK) {
637 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
638 tacFree(&tac); nloptFree(&ipar); parFree(&par); tacFree(&ftac);
639 return(22);
640 }
641 snr=(int)simSamples(0.2*sdist, 0.0, par.r[0].end-par.r[0].start, 2, ftac.x);
642 ftac.isframe=0;
643 for(int i=0; i<ftac.sampleNr; i++) ftac.x[i]+=par.r[0].start;
644 /* Compute function values at sample times */
645 ret=mfEvalY(modelCode(par.r[0].model), par.parNr, par.r[0].p,
646 ftac.sampleNr, ftac.x, ftac.c[0].y, verbose-2);
647 if(ret!=TPCERROR_OK) {
648 fprintf(stderr, "Error: cannot calculate function values.\n");
649 tacFree(&tac); nloptFree(&ipar); parFree(&par); tacFree(&ftac);
650 return(23);
651 }
652 if(verbose>10) tacWrite(&ftac, stdout, TAC_FORMAT_UNKNOWN, 1, NULL);
653 /* Plot */
654 ret=tacPlotFitSVG(&tac, &ftac, "", nan(""), nan(""), nan(""), nan(""), svgfile, &status);
655 if(ret!=TPCERROR_OK) {
656 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
657 tacFree(&tac); nloptFree(&ipar); parFree(&par); tacFree(&ftac);
658 return(24);
659 }
660 tacFree(&ftac);
661 if(verbose>0) printf("Measured and fitted data plotted in %s\n", svgfile);
662 }
663
664
665 nloptFree(&ipar);
666 tacFree(&tac);
667 parFree(&par);
668
669
670 return(0);
671}
672/*****************************************************************************/
673
674/*****************************************************************************
675 *
676 * Functions to be minimized
677 *
678 *****************************************************************************/
679double func_exp(int parNr, double *p, void *fdata)
680{
681 unsigned int i, ei;
682 double v, wss;
683 FITDATA *d=(FITDATA*)fdata;
684
685 /* Calculate the curve values and weighted SS */
686 for(i=0, wss=0.0; i<d->n; i++) {
687 d->ysim[i]=0.0;
688 if(isnan(d->ymeas[i]) || isnan(d->x[i])) continue;
689 for(ei=0; ei<(unsigned int)parNr/2; ei++)
690 d->ysim[i]+=p[2*ei]*exp(-p[2*ei+1]*d->x[i]);
691 v=d->ysim[i]-d->ymeas[i];
692 wss+=d->w[i]*v*v;
693 }
694 if(0) {
695 for(i=0; i<(unsigned int)parNr; i++) printf(" %g", p[i]);
696 printf(" -> %g\n", wss);
697 }
698
699 return(wss);
700}
701/*****************************************************************************/
702
703/*****************************************************************************/
int spectralBFNr(double *k, double *a, const int n)
Definition bf_dexp.c:193
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
unsigned int doubleMaxIndex(double *a, const unsigned int n)
Definition doubleutil.c:357
int mfEvalY(const char *fid, const int parNr, const double *p, const int sampleNr, const double *x, double *y, const int verbose)
Definition func.c:26
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
Definition ift.c:63
unsigned int simSamples(double initStep, double maxStep, double endTime, int mode, double *x)
Definition interpolate.c:50
int atoiCheck(const char *s, int *v)
Definition intutil.c:25
char * modelCode(const unsigned int i)
Definition modell.c:176
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 nloptRemoveEmpties(NLOPT *d)
Definition nlopt.c:398
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 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 * 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
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
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
Definition tac.c:130
void tacInit(TAC *tac)
Definition tac.c:24
int tacCopyTacchdr(TACC *d1, TACC *d2)
Definition tac.c:282
int tacCopyHdr(TAC *tac1, TAC *tac2)
Copy TAC header data from tac1 to tac2.
Definition tac.c:310
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 tacMultipleSamples(TAC *d1, const int fixMode, TAC *d2, const int verbose)
Check TAC data for multiple samples with the same sample time. Optionally replace the multiple sample...
Definition tacorder.c:336
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 tacExtractRange(TAC *d1, TAC *d2, double startT, double endT)
Extract the specified time (x) range from TAC structure.
Definition tacx.c:486
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 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).
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 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_UNKNOWN
Unknown format.
Definition tpctac.h:28
Header file for libtpctacmod.