TPCCLIB
Loading...
Searching...
No Matches
fit_dms.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 "tpcbfm.h"
22#include "tpctacmod.h"
23#include "tpclinopt.h"
24#include "tpcrand.h"
25#include "tpcnlopt.h"
26/*****************************************************************************/
27
28/*****************************************************************************/
29/* Local functions */
30double func_dmsurge(int parNr, double *p, void*);
31/*****************************************************************************/
32typedef struct FITDATA {
34 unsigned int n;
36 double *x;
39 double *x2;
41 double *ymeas;
43 double *ysim;
45 double *w;
46} FITDATA;
47/*****************************************************************************/
48
49/*****************************************************************************/
50static char *info[] = {
51 "Fitting of the sum of surge functions and delay time",
52 "to time-activity curves (TACs).",
53 " ",
54 "Function:",
55 " ",
56 " f(x) = Sum of Ai*(x-dt)*exp(-Ki*(x-dt)) where i=1..N",
57 " ",
58 "Usage: @P [Options] tacfile [parfile]",
59 " ",
60 "Options:",
61 " -n=<value>",
62 " Maximum number of surge functions (1<=n<=10); by default 5.",
63 " -kMax=<value>",
64 " Maximum K value (kmax>kmin). By default 10.0.",
65 " -kMin=<value>",
66 " Minimum K value (>0). By default, kMax*1.0E-10.",
67 " -bfnr=<value>",
68 " Number of basis functions, used in determination of initial parameter",
69 " estimates and number of exponentials for nonlinear fitting;",
70 " default is 500.",
71 " -dt=<min,max,step> | -dt=delay",
72 " The range and step size of precision of time delay estimation, or",
73 " fixed delay time.",
74 " -w1",
75 " All weights are set to 1.0 (no weighting); by default, weights in",
76 " data file are used, if available.",
77 " -wf",
78 " Weight by sampling interval.",
79 " -nllsq | -llsq",
80 " Non-linear LSQ fit (default), or only linear LSQ fit; In case of NLLSQ,",
81 " LLSQ is still performed first to obtain initial parameter values.",
82 " -svg=<Filename>",
83 " Fitted and measured TACs are plotted in specified SVG file.",
84 " -fit=<Filename>",
85 " Fitted TACs are written in specified TAC file.",
86 " -stdoptions", // List standard options like --help, -v, etc
87 " ",
88 "Function parameters are written the format determined by file name extension.",
89 "PET time frames are used in fitting, if available in TAC file.",
90 " ",
91 "See also: fit_feng, fit_suri, fit_gvar, fit2dat, tacframe, fitdt",
92 " ",
93 "Keywords: TAC, curve fitting",
94 0};
95/*****************************************************************************/
96
97/*****************************************************************************/
98/* Turn on the globbing of the command line, since it is disabled by default in
99 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
100 In Unix&Linux wildcard command line processing is enabled by default. */
101/*
102#undef _CRT_glob
103#define _CRT_glob -1
104*/
105int _dowildcard = -1;
106/*****************************************************************************/
107
108/*****************************************************************************/
112int main(int argc, char **argv)
113{
114 int ai, help=0, version=0, verbose=1;
115 char tacfile[FILENAME_MAX], parfile[FILENAME_MAX], svgfile[FILENAME_MAX], fitfile[FILENAME_MAX];
116 int weights=0; // 0=default, 1=no weighting, 2=frequency
117 int bfNr=500;
118 int maxSurgeNr=10;
119 double kMin=nan("");
120 double kMax=10.0;
121 double dtRange[3];
122 int nllsq=1; // whether to do NLLSQ after LLSQ
123// unsigned int model=MF_DMSURGE; // fid="dmsurge"
124
125
126 /*
127 * Get arguments
128 */
129 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
130 tacfile[0]=parfile[0]=svgfile[0]=fitfile[0]=(char)0;
131 for(int i=0; i<3; i++) dtRange[i]=nan("");
132 /* Options */
133 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
134 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
135 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
136 if(strcasecmp(cptr, "W1")==0) {
137 weights=1; continue;
138 } else if(strcasecmp(cptr, "WF")==0) {
139 weights=2; continue;
140 } else if(strncasecmp(cptr, "N=", 2)==0) {
141 if(atoiCheck(cptr+2, &maxSurgeNr)==0 && maxSurgeNr>0 && maxSurgeNr<=10) continue;
142 fprintf(stderr, "Error: invalid option for number of surge functions '%s'.\n", argv[ai]);
143 return(1);
144 } else if(strncasecmp(cptr, "BFNR=", 5)==0) {
145 if(atoiCheck(cptr+5, &bfNr)==0 && bfNr>5) continue;
146 } else if(strncasecmp(cptr, "KMIN=", 5)==0) {
147 kMin=atofVerified(cptr+5); if(kMin>0) continue;
148 } else if(strncasecmp(cptr, "KMAX=", 5)==0) {
149 kMax=atofVerified(cptr+5); if(kMax>0.0) continue;
150 } else if(strncasecmp(cptr, "DT=", 3)==0) {
151 int n=atofList(cptr+3, ",", dtRange, 3);
152 if(n==1) {
153 dtRange[1]=dtRange[0]; dtRange[2]=0.0; continue;
154 } else if(n==3) {
155 if(dtRange[0]<dtRange[1] && dtRange[2]<0.2*(dtRange[1]-dtRange[0])) continue;
156 }
157 fprintf(stderr, "Error: invalid delay time option '%s'.\n", argv[ai]);
158 return(1);
159 } else if(strcasecmp(cptr, "NLLSQ")==0) {
160 nllsq=1; continue;
161 } else if(strcasecmp(cptr, "LLSQ")==0) {
162 nllsq=0; continue;
163 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
164 strlcpy(svgfile, cptr+4, FILENAME_MAX); continue;
165 } else if(strncasecmp(cptr, "FIT=", 4)==0 && strlen(cptr)>4) {
166 strlcpy(fitfile, cptr+4, FILENAME_MAX); continue;
167 }
168 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
169 return(1);
170 } else break;
171
172 TPCSTATUS status; statusInit(&status);
173 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
174 status.verbose=verbose-3;
175
176 /* Print help or version? */
177 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
178 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
179 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
180
181 /* Process other arguments, starting from the first non-option */
182 if(ai<argc) strlcpy(tacfile, argv[ai++], FILENAME_MAX);
183 if(ai<argc) strlcpy(parfile, argv[ai++], FILENAME_MAX);
184 if(ai<argc) {
185 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
186 return(1);
187 }
188 /* Did we get all the information that we need? */
189 if(!tacfile[0]) {
190 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
191 return(1);
192 }
193 /* Check k range, and set kMin to default, unless user provided */
194 if(!isfinite(kMin)) kMin=kMax*1.0E-10;
195 else if(!(kMax>kMin)) {
196 fprintf(stderr, "Error: invalid k limits.\n");
197 return(1);
198 }
199
200
201 /* In verbose mode print arguments and options */
202 if(verbose>1) {
203 printf("tacfile := %s\n", tacfile);
204 if(parfile[0]) printf("parfile := %s\n", parfile);
205 if(svgfile[0]) printf("svgfile := %s\n", svgfile);
206 if(fitfile[0]) printf("fitfile := %s\n", fitfile);
207 printf("nllsq := %d\n", nllsq);
208 printf("maxSurgeNr := %d\n", maxSurgeNr);
209 printf("bfNr := %d\n", bfNr);
210 printf("kmin := %g\n", kMin);
211 printf("kmax := %g\n", kMax);
212 if(isfinite(dtRange[0]))
213 printf("dtMin := %g\ndtMax := %g\ndtStep :=%g\n", dtRange[0], dtRange[1], dtRange[2]);
214 printf("weights := %d\n", weights);
215 fflush(stdout);
216 }
217
218
219
220 /*
221 * Read TAC data
222 */
223 if(verbose>1) printf("reading %s\n", tacfile);
224 TAC tac; tacInit(&tac);
225 if(tacRead(&tac, tacfile, &status)!=TPCERROR_OK) {
226 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
227 tacFree(&tac); return(2);
228 }
229 if(verbose>1) {
230 printf("fileformat := %s\n", tacFormattxt(tac.format));
231 printf("tacNr := %d\n", tac.tacNr);
232 printf("sampleNr := %d\n", tac.sampleNr);
233 printf("xunit := %s\n", unitName(tac.tunit));
234 printf("yunit := %s\n", unitName(tac.cunit));
235 printf("isframe := %d\n", tac.isframe);
236 }
237 if(tac.tacNr<1) {
238 fprintf(stderr, "Error: file contains no data.\n");
239 tacFree(&tac); return(2);
240 }
241 if(tac.sampleNr<3) {
242 fprintf(stderr, "Error: too few samples.\n");
243 tacFree(&tac); return(2);
244 }
245 /* Check NaNs */
246 if(tacNaNs(&tac)>0) {
247 fprintf(stderr, "Error: data contains missing values.\n");
248 tacFree(&tac); return(2);
249 }
250 /* Sort data by sample time */
251 tacSortByTime(&tac, &status);
252 /* Check and set weights */
253 if(weights==0) {
254 if(!tacIsWeighted(&tac)) {
256 for(int i=0; i<tac.sampleNr; i++) tac.w[i]=1.0;
257 }
258 } else if(weights==1) {
260 for(int i=0; i<tac.sampleNr; i++) tac.w[i]=1.0;
261 } else if(weights==2) {
262 int ret=tacWByFreq(&tac, ISOTOPE_UNKNOWN, &status);
263 if(ret!=TPCERROR_OK) {
264 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
265 tacFree(&tac); return(2);
266 }
267 }
268
269
270 /*
271 * Get and check data range
272 */
273 double ymin, ymax, xmin, xmax;
274 tacYRange(&tac, 0, &ymin, &ymax, NULL, NULL, NULL, NULL);
275 tacXRange(&tac, &xmin, &xmax);
276 if(verbose>2) {
277 printf(" fitrange_minv := %g\n", ymin);
278 printf(" fitrange_maxv := %g\n", ymax);
279 printf(" fitrange_minx := %g\n", xmin);
280 printf(" fitrange_maxx := %g\n", xmax);
281 }
282 if(!(xmax>xmin)) {
283 fprintf(stderr, "Error: invalid sample times.\n");
284 tacFree(&tac); return(2);
285 }
286 /* Get the first smallest sample distance (delta x) that is > 0 */
287 double sdist=xmax;
288 for(int i=1; i<tac.sampleNr; i++) {
289 double dx=tac.x[i]-tac.x[i-1];
290 if(dx>0.0 && dx<sdist) sdist=dx;
291 }
292 if(verbose>1) printf("sdist := %g\n", sdist);
293 /* Set delay time range if necessary */
294 if(!isfinite(dtRange[0])) {
295 dtRange[1]=0.1*(xmax-xmin);
296 dtRange[0]=-dtRange[1];
297 dtRange[2]=0.01*(dtRange[1]-dtRange[0]);
298// dtRange[2]=0.001*(dtRange[1]-dtRange[0]);
299 if(verbose>1)
300 printf("dtMin := %g\ndtMax := %g\ndtStep :=%g\n", dtRange[0], dtRange[1], dtRange[2]);
301 }
302
303
304 /*
305 * Prepare the room for fitted TTACs, if requested
306 */
307 TAC ftac; tacInit(&ftac);
308 if(fitfile[0] || svgfile[0]) {
309 if(verbose>1) printf("allocating space for fitted TTACs\n");
310 if(tacDuplicate(&tac, &ftac)!=TPCERROR_OK) {
311 fprintf(stderr, "Error: cannot allocate space for fitted TACs.\n");
312 tacFree(&tac);
313 return(3);
314 }
315 }
316
317
318 /*
319 * Set PAR structure for the results
320 */
321 PAR par; parInit(&par);
322 if(parAllocateWithTAC(&par, &tac, 1+2*maxSurgeNr, &status)!=TPCERROR_OK) {
323 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
324 tacFree(&tac); tacFree(&ftac); return(4);
325 }
326 par.tacNr=tac.tacNr;
327 par.parNr=1+2*maxSurgeNr;
329 /* Set parameter names and units */
330 sprintf(par.n[0].name, "dT");
331 par.n[0].unit=tac.tunit;
332 for(int i=1; i<par.parNr; i+=2) {
333 sprintf(par.n[i].name, "a%d", 1+i/2);
334 sprintf(par.n[i+1].name, "k%d", 1+i/2);
335 par.n[i].unit=tac.cunit;
336 par.n[i+1].unit=unitInverse(tac.tunit);
337 }
338 int maxParNr=0;
339
340
341 /*
342 * Spectral analysis to find good initial parameters for non-linear fitting for each TAC
343 */
344 for(int ci=0; ci<tac.tacNr; ci++) {
345 if(verbose>1 && tac.tacNr>1) printf("linear fitting of TAC %s\n", tac.c[ci].name);
346
347 /* First Spectral analysis */
348 double pa[bfNr], pk[bfNr], yfit[tac.sampleNr], dt=nan("");
349 int ret=0;
350 if(tac.isframe)
351 ret=spectralDMSurge(tac.x1, tac.x2, tac.c[ci].y, tac.w, tac.sampleNr, kMin, kMax, bfNr,
352 dtRange[0], dtRange[1], dtRange[2],
353 pk, pa, &dt, yfit, &status);
354 else
355 ret=spectralDMSurge(tac.x, NULL, tac.c[ci].y, tac.w, tac.sampleNr, kMin, kMax, bfNr,
356 dtRange[0], dtRange[1], dtRange[2],
357 pk, pa, &dt, yfit, &status);
358 if(ret!=TPCERROR_OK) {
359 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
360 tacFree(&tac); tacFree(&ftac); parFree(&par); return(6);
361 }
362 if(verbose>2) {
363 printf("delta_t := %g\n", dt);
364 printf("solutions for each k:\n");
365 for(int bi=0; bi<bfNr; bi++) printf("\t%g\t%g\n", pk[bi], pa[bi]);
366 }
367 /* Spectral analysis refined */
368 if(verbose>2) printf("refining parameters of Spectral analysis\n");
369 double kMin2, kMax2, dtRange2[3];
370 if(spectralKRange(pk, pa, bfNr, &kMin2, &kMax2, &status)!=TPCERROR_OK) {
371 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
372 tacFree(&tac); tacFree(&ftac); parFree(&par); return(6);
373 }
374 if(kMax2<6.0*kMin2) {kMax2*=3.0; kMin2*=0.75; if(kMin2<kMin) kMin2=kMin;}
375 dtRange2[0]=dt-2.0*dtRange[2]; if(dtRange2[0]<dtRange[0]) dtRange2[0]=dtRange[0];
376 dtRange2[1]=dt+2.0*dtRange[2]; if(dtRange2[1]>dtRange[1]) dtRange2[1]=dtRange[1];
377 dtRange2[2]=0.02*(dtRange2[1]-dtRange2[0]);
378 if(verbose>2) {
379 printf(" refined kMin := %g\n refined kMax := %g\n", kMin2, kMax2);
380 printf(" refined delay range and step size : %g %g %g\n", dtRange2[0], dtRange2[1], dtRange2[2]);
381 }
382 if(tac.isframe)
383 ret=spectralDMSurge(tac.x1, tac.x2, tac.c[ci].y, tac.w, tac.sampleNr, kMin2, kMax2, bfNr,
384 dtRange2[0], dtRange2[1], dtRange2[2],
385 pk, pa, &dt, yfit, &status);
386 else
387 ret=spectralDMSurge(tac.x, NULL, tac.c[ci].y, tac.w, tac.sampleNr, kMin2, kMax2, bfNr,
388 dtRange2[0], dtRange2[1], dtRange2[2],
389 pk, pa, &dt, yfit, &status);
390 if(ret!=TPCERROR_OK) {
391 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
392 tacFree(&tac); tacFree(&ftac); parFree(&par); return(6);
393 }
394 if(verbose>2) {
395 printf("refined delta_t := %g\n", dt);
396 printf("refined solutions for each k:\n");
397 for(int bi=0; bi<bfNr; bi++) printf("\t%g\t%g\n", pk[bi], pa[bi]);
398 }
399 if(ftac.tacNr>0)
400 for(int i=0; i<tac.sampleNr; i++) ftac.c[ci].y[i]=yfit[i];
401
402 /* Get max A parameter to be used as basis of upper limit */
403 double aMax=pa[doubleMaxIndex(pa, bfNr)];
404 if(verbose>3) printf("aMax := %g\n", aMax);
405
406 /* Calculate how many zero-separated basis functions there really were */
407 int fbfNr=spectralBFNr(pk, pa, bfNr);
408 if(verbose>2) printf("fbfNr := %d\n", fbfNr);
409 if(fbfNr<1) {
410 fprintf(stderr, "Error: cannot estimate initial parameters.\n");
411 tacFree(&tac); tacFree(&ftac); parFree(&par); return(6);
412 }
413
414 /* Set the nr of Surge functions, at most maxSurgeNr */
415 int surgeNr=fbfNr;
416 if(surgeNr>maxSurgeNr) surgeNr=maxSurgeNr;
417 if(verbose>1) printf("surgeNr := %d\n", surgeNr);
418 int localParNr=1+2*surgeNr;
419 if(localParNr>maxParNr) maxParNr=localParNr;
420
421 /* Extract parameters for specified number of Surge functions at most */
422 double init_k[surgeNr], init_a[surgeNr];
423 ret=spectralBFExtract(pk, pa, bfNr, init_k, init_a, surgeNr);
424 if(ret<1) {
425 fprintf(stderr, "Error: cannot estimate initial parameters.\n");
426 tacFree(&tac); tacFree(&ftac); parFree(&par); return(6);
427 }
428 if(verbose>2) {
429 printf("\n\tClustered a and k values\n");
430 for(int i=0; i<surgeNr; i++) printf("\t%g\t%g\n", init_a[i], init_k[i]);
431 printf("\n"); fflush(stdout);
432 }
433
434 /* Set parameters in PAR structure */
435 par.r[ci].model=modelCodeIndex("dmsurge");
436 //printf("model=%d\nold_id=%d\n", par.r[ci].model, modelOldId(par.r[ci].model));
437 par.r[ci].dataNr=tacWSampleNr(&tac);
438 par.r[ci].start=xmin;
439 par.r[ci].end=xmax;
440 par.r[ci].wss=0.0;
441 par.r[ci].fitNr=2*surgeNr; if(dtRange[2]>0.0) par.r[ci].fitNr++;
442 par.r[ci].p[0]=dt;
443 for(int i=0, pi=1; i<surgeNr && pi<par.parNr; i++, pi+=2) par.r[ci].p[pi]=init_a[i];
444 for(int i=0, pi=2; i<surgeNr && pi<par.parNr; i++, pi+=2) par.r[ci].p[pi]=init_k[i];
445 for(int i=localParNr; i<par.parNr; i++) par.r[ci].p[i]=0.0;
446
447 /* If not refined with NLLSQ, calculate fitted TAC and WSS with final LLSQ parameters */
448 if(nllsq==0) {
449 if(ftac.isframe)
450 ret=mfEvalFrameY("dmsurge", localParNr, par.r[ci].p, ftac.sampleNr, ftac.x1, ftac.x2, yfit, 0);
451 else
452 ret=mfEvalY("dmsurge", localParNr, par.r[ci].p, ftac.sampleNr, ftac.x, yfit, 0);
453 if(ret) {
454 fprintf(stderr, "Error: cannot calculate fitted TAC.\n");
455 tacFree(&tac); tacFree(&ftac); parFree(&par); return(6);
456 }
457 for(int i=0; i<tac.sampleNr; i++) {
458 double v=tac.c[ci].y[i]-yfit[i];
459 par.r[ci].wss+=tac.w[i]*v*v;
460 }
461
462 /* Copy fitted TAC if needed later */
463 if(ftac.tacNr>0) for(int i=0; i<tac.sampleNr; i++) ftac.c[ci].y[i]=yfit[i];
464 }
465
466
467
468 /* If needed, calculate fitted TAC with final LLSQ parameters */
469 if(nllsq==0 && ftac.tacNr>0) {
470 if(ftac.isframe)
471 ret=mfEvalFrameY("dmsurge", localParNr, par.r[ci].p, ftac.sampleNr, ftac.x1, ftac.x2, ftac.c[ci].y, 0);
472 else
473 ret=mfEvalY("dmsurge", localParNr, par.r[ci].p, ftac.sampleNr, ftac.x, ftac.c[ci].y, 0);
474 if(ret) {
475 fprintf(stderr, "Error: cannot calculate fitted TAC.\n");
476 tacFree(&tac); tacFree(&ftac); parFree(&par); return(6);
477 }
478 }
479 }
480 /* Set parameter number to the actual max among TACs */
481 par.parNr=maxParNr;
482
483
484 /*
485 * Non-linear fitting of each TAC using initial estimates from above, if requested.
486 * Delay time is constrained to the estimate from LLSQ.
487 */
488 if(nllsq!=0) {
489 for(int ci=0; ci<tac.tacNr; ci++) {
490 if(verbose>1 && tac.tacNr>1) printf("non-linear fitting of TAC %s\n", tac.c[ci].name);
491 double final_wss=0.0;
492
493 /* Prepare for LLSQ optimization */
494 NLOPT ipar; nloptInit(&ipar); // dt, a[0], k[0], a[1], k[1], a[2], ...
495 if(nloptAllocate(&ipar, par.parNr)!=TPCERROR_OK) {
496 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
497 tacFree(&tac); tacFree(&ftac); parFree(&par); return(8);
498 }
499 ipar.totalNr=par.parNr;
500 for(unsigned int i=0; i<ipar.totalNr; i++) ipar.xfull[i]=par.r[ci].p[i];
501 /* deltaT */
502 ipar.xlower[0]=ipar.xupper[0]=ipar.xfull[0];
503 ipar.xdelta[0]=0.0;
504 ipar.xtol[0]=0.0;
505 for(unsigned int i=1; i<ipar.totalNr; i++) {
506 if(i%2) { // A
507 ipar.xlower[i]=0.0;
508 ipar.xupper[i]=100.*ipar.xfull[i];
509 ipar.xdelta[i]=0.01*ipar.xfull[i];
510 ipar.xtol[i]=0.0001*ipar.xfull[i];
511 } else { // k
512 if(ipar.xfull[i]<kMin) ipar.xfull[i]=kMin;
513 ipar.xlower[i]=0.01*ipar.xfull[i]; //if(ipar.xlower[i]<kMin) ipar.xlower[i]=kMin;
514 ipar.xupper[i]=10.*ipar.xfull[i];
515 ipar.xdelta[i]=0.01*ipar.xfull[i];
516 ipar.xtol[i]=0.0001*ipar.xfull[i];
517 }
518 }
519 if(verbose>2) {
520 printf("Initial parameters for optimization:\n");
521 nloptWrite(&ipar, stdout); fflush(stdout);
522 }
523 /* Get nr of fixed parameters before deltas are modified between fittings */
524 unsigned int fixedNr=nloptFixedNr(&ipar);
525 /* Set function */
526 ipar._fun=func_dmsurge;
527 /* Set data pointers for the fit */
528 FITDATA fitdata;
529 fitdata.n=tac.sampleNr;
530 if(!tac.isframe) {fitdata.x=tac.x; fitdata.x2=NULL;} else {fitdata.x=tac.x1; fitdata.x2=tac.x2;}
531 fitdata.ymeas=tac.c[ci].y;
532 fitdata.ysim=ftac.c[ci].y;
533 fitdata.w=tac.w;
534 ipar.fundata=&fitdata;
535 double initial_wss=func_dmsurge(ipar.totalNr, ipar.xfull, ipar.fundata);
536 if(verbose>3)
537 printf(" initial_wss := %g\n", initial_wss);
538 if(!isfinite(initial_wss)) {
539 fprintf(stderr, "Error: invalid initial parameter guess.\n");
540 tacFree(&tac); tacFree(&ftac); parFree(&par); nloptFree(&ipar); return(8);
541 }
542
543 /* Nonlinear optimization: Simplex */
544 if(verbose>2) {printf("starting nonlinear optimization\n"); fflush(stdout);}
545 if(verbose>3) printf("1st non-linear optimization\n");
546 if(nloptSimplex(&ipar, 0, &status)!=TPCERROR_OK) {
547 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
548 tacFree(&tac); tacFree(&ftac); parFree(&par); nloptFree(&ipar); return(8);
549 }
550 final_wss=func_dmsurge(ipar.totalNr, ipar.xfull, ipar.fundata);
551 if(verbose>3) nloptWrite(&ipar, stdout);
552 if(verbose>6) {
553 printf("measured and fitted TAC:\n");
554 for(int i=0; i<tac.sampleNr; i++)
555 printf("\t%g\t%g\n", tac.c[ci].y[i], ftac.c[ci].y[i]);
556 }
557 if(verbose>3) printf(" final_wss := %g\n", final_wss);
558 /* Simplex again, with new deltas and smaller tolerance */
559 for(unsigned int i=1; i<ipar.totalNr; i++) {
560 ipar.xdelta[i]*=0.093;
561 ipar.xtol[i]*=0.01;
562 }
563 if(verbose>3) printf("2nd non-linear optimization\n");
564 if(nloptSimplex(&ipar, 0, &status)!=TPCERROR_OK) {
565 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
566 tacFree(&tac); tacFree(&ftac); parFree(&par); nloptFree(&ipar); return(8);
567 }
568 final_wss=func_dmsurge(ipar.totalNr, ipar.xfull, ipar.fundata);
569 if(verbose>3) nloptWrite(&ipar, stdout);
570 if(verbose>6) {
571 printf("measured and fitted TAC:\n");
572 for(int i=0; i<tac.sampleNr; i++)
573 printf("\t%g\t%g\n", tac.c[ci].y[i], ftac.c[ci].y[i]);
574 }
575 if(verbose>3) printf(" final_wss := %g\n", final_wss);
576
577 /* Copy results into PAR structure */
578 for(unsigned int i=0; i<ipar.totalNr; i++)
579 par.r[ci].p[i]=ipar.xfull[i];
580 par.r[ci].wss=final_wss;
581 par.r[ci].fitNr=ipar.totalNr-fixedNr;
582
583 nloptFree(&ipar);
584 }
585 }
586
587
588 /* Print and save function parameters */
589 if(verbose>0) parWrite(&par, stdout, PAR_FORMAT_TSV_UK, 0, NULL);
590 if(parfile[0]) {
591 /* Set file format */
592 par.format=parFormatFromExtension(parfile);
593 if(verbose>2) printf("parameter file format := %s\n", parFormattxt(par.format));
595 /* set header contents */
596 {
597 iftPut(&par.h, "datafile", tacfile, 0, NULL);
598 {
599 char buf[256];
600 time_t t=time(NULL);
601 iftPut(&par.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
602 tpcProgramName(argv[0], 1, 1, buf, 256);
603 iftPut(&par.h, "program", buf, 0, NULL);
604 }
605 }
606 /* Save file */
607 if(verbose>1) printf(" saving %s\n", parfile);
608 FILE *fp=fopen(parfile, "w");
609 if(fp==NULL) {
610 fprintf(stderr, "Error: cannot open file for writing.\n");
611 tacFree(&tac); tacFree(&ftac); parFree(&par); return(11);
612 }
613 int ret=parWrite(&par, fp, PAR_FORMAT_UNKNOWN, 1, &status);
614 fclose(fp);
615 if(ret!=TPCERROR_OK) {
616 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
617 tacFree(&tac); tacFree(&ftac); parFree(&par); return(12);
618 }
619 if(verbose>0) printf("function parameters saved in %s\n", parfile);
620 }
621
622
623 /*
624 * SVG plot of fitted and original data
625 */
626 if(svgfile[0]) {
627
628 if(verbose>1) printf("saving SVG plot\n");
629 if(tacPlotFitSVG(&tac, &ftac, "", 0.0, nan(""), 0.0, nan(""), svgfile, NULL)!=TPCERROR_OK) {
630 fprintf(stderr, "Error: cannot plot fitted data.\n");
631 tacFree(&tac); tacFree(&ftac); parFree(&par);
632 return(21);
633 }
634 if(verbose>0) printf("Plots written in %s.\n", svgfile);
635 }
636
637 /*
638 * Save fitted TTACs
639 */
640 if(fitfile[0]) {
641 if(verbose>1) printf("writing %s\n", fitfile);
642 FILE *fp; fp=fopen(fitfile, "w");
643 if(fp==NULL) {
644 fprintf(stderr, "Error: cannot open file for writing (%s)\n", fitfile);
645 tacFree(&tac); tacFree(&ftac); parFree(&par);
646 return(31);
647 }
648 int ret=tacWrite(&ftac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
649 fclose(fp);
650 if(ret!=TPCERROR_OK) {
651 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
652 tacFree(&tac); tacFree(&ftac); parFree(&par);
653 return(32);
654 }
655 if(verbose>0) printf("fitted TACs saved in %s.\n", fitfile);
656 }
657
658 tacFree(&tac); tacFree(&ftac); parFree(&par);
659
660 return(0);
661}
662/*****************************************************************************/
663
664/*****************************************************************************
665 *
666 * Functions to be minimized
667 *
668 *****************************************************************************/
669double func_dmsurge(int parNr, double *p, void *fdata)
670{
671 FITDATA *d=(FITDATA*)fdata;
672
673 /* Calculate the curve values and weighted SS */
674 if(d->x2!=NULL) { // PET frame start and end times available
675 if(mfEvalFrameY("dmsurge", parNr, p, d->n, d->x, d->x2, d->ysim, 0)) return(nan(""));
676 } else {
677 if(mfEvalY("dmsurge", parNr, p, d->n, d->x, d->ysim, 0)) return(nan(""));
678 }
679 double wss=0.0;
680 for(unsigned i=0; i<d->n; i++) {
681 double v=d->ysim[i]-d->ymeas[i];
682 wss+=d->w[i]*v*v;
683 }
684
685 return(wss);
686}
687/*****************************************************************************/
688
689/*****************************************************************************/
int spectralBFNr(double *k, double *a, const int n)
Definition bf_dexp.c:193
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
int spectralDMSurge(const double *x, const double *x2, const double *y, double *w, const int sNr, const double kMin, const double kMax, const int fNr, const double dtMin, const double dtMax, const double dtStep, double *k, double *a, double *dtEst, double *yfit, TPCSTATUS *status)
Definition bf_dms.c:27
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
int atofList(const char *s1, const char *s2, double *x, int maxn)
Definition decpoint.c:150
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 mfEvalFrameY(const char *fid, const int parNr, const double *p, const int sampleNr, const double *x1, const double *x2, double *y, const int verbose)
Definition func.c:790
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
Definition ift.c:63
int atoiCheck(const char *s, int *v)
Definition intutil.c:25
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 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
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
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 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 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 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.