TPCCLIB
Loading...
Searching...
No Matches
fit_ratf.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 <math.h>
13#include <string.h>
14#include <time.h>
15/*****************************************************************************/
16#include "libtpcmisc.h"
17#include "libtpcmodel.h"
18#include "libtpccurveio.h"
19#include "libtpcsvg.h"
20#include "libtpcmodext.h"
21/*****************************************************************************/
22double func_ratf(int parNr, double *p, void*);
23/*****************************************************************************/
24double *x, *ymeas, *yfit, *w;
25int dataNr=0, parNr=0;
26double pmin[MAX_PARAMETERS], pmax[MAX_PARAMETERS];
27/*****************************************************************************/
28
29/*****************************************************************************/
30static char *info[] = {
31 "Non-linear fitting of 1st-3rd degree rational function to PET plasma and",
32 "tissue time-activity curves (TACs).",
33 " ",
34 "Function:",
35 " ",
36 " p1 + p3*x + p5*x^2 + p7*x^3 ",
37 " f(x) = --------------------------- ",
38 " p2 + p4*x + p6*x^2 + p8*x^3 ",
39 " ",
40 ", where p1=0 and p2=1.",
41 " ",
42 "Usage: @P [Options] tacfile fitfile",
43 " ",
44 "Options:",
45 " -w1",
46 " All weights are set to 1.0 (no weighting); by default, weights in",
47 " data file are used, if available.",
48 " -wf",
49 " Weight by sampling interval.",
50 " -svg=<Filename>",
51 " Fitted and measured TACs are plotted in specified SVG file.",
52 " -stdoptions", // List standard options like --help, -v, etc
53 " ",
54 "Options for selecting the rational function:",
55 " -p3p3 3rd degree polynomial/3rd degree polynomial (default)",
56 " -p3p2 3rd degree polynomial/2nd degree polynomial",
57 " -p2p2 2nd degree polynomial/2nd degree polynomial",
58 " -p2p1 2nd degree polynomial/1st degree polynomial",
59 " -p1p1 1st degree polynomial/1st degree polynomial",
60 " ",
61 "Program writes the fit start and end times, nr of points, WSS,",
62 "and parameters (p1, p2, ...) of the fitted function to the fit file.",
63 " ",
64 "See also: fit2dat, fit_exp, fit_sigm, fit_ppf",
65 " ",
66 "Keywords: curve fitting, TAC, simulation, rational function",
67 0};
68/*****************************************************************************/
69
70/*****************************************************************************/
71/* Turn on the globbing of the command line, since it is disabled by default in
72 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
73 In Unix&Linux wildcard command line processing is enabled by default. */
74/*
75#undef _CRT_glob
76#define _CRT_glob -1
77*/
78int _dowildcard = -1;
79/*****************************************************************************/
80
81/*****************************************************************************/
85int main(int argc, char **argv)
86{
87 int ai, help=0, version=0, verbose=1;
88 int fi, pi, ri, type=-1, ret;
89 char *cptr, datfile[FILENAME_MAX], fitfile[FILENAME_MAX],
90 svgfile[FILENAME_MAX];
91 int weights=0; // 0=default, 1=no weighting, 2=frequency
92 DFT dft;
93 FIT fit;
94 double a, b, c, tstart, tstop, miny, maxy;
95 enum {MODEL_UNKNOWN, MODEL_P3P3, MODEL_P3P2, MODEL_P2P2,
96 MODEL_P2P1, MODEL_P1P1};
97 int model=MODEL_UNKNOWN;
98 static char *model_name[] = {"Unknown", "pol3/pol3", "pol3/pol2", "pol2/pol2",
99 "pol2/pol1", "pol1/pol1", 0};
100 int func_par_nr[6]={0,6,5,4,3,2};
101
102
103
104 /*
105 * Get arguments
106 */
107 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
108 datfile[0]=fitfile[0]=svgfile[0]=(char)0;
109 dftInit(&dft); fitInit(&fit);
110 /* Options */
111 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
112 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
113 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
114 if(strcasecmp(cptr, "P3P3")==0) {
115 model=MODEL_P3P3; type=233; continue;
116 } else if(strcasecmp(cptr, "P3P2")==0) {
117 model=MODEL_P3P2; type=232; continue;
118 } else if(strcasecmp(cptr, "P2P2")==0) {
119 model=MODEL_P2P2; type=222; continue;
120 } else if(strcasecmp(cptr, "P2P1")==0) {
121 model=MODEL_P2P1; type=221; continue;
122 } else if(strcasecmp(cptr, "P1P1")==0) {
123 model=MODEL_P1P1; type=211; continue;
124 } else if(strcasecmp(cptr, "W1")==0) {
125 weights=1; continue;
126 } else if(strcasecmp(cptr, "WF")==0) {
127 weights=2; continue;
128 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
129 strcpy(svgfile, cptr+4); continue;
130 }
131 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
132 return(1);
133 } else break;
134
135 /* Print help or version? */
136 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
137 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
138 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
139
140 /* Process other arguments, starting from the first non-option */
141 for(; ai<argc; ai++) {
142 if(!datfile[0]) {strcpy(datfile, argv[ai]); continue;}
143 else if(!fitfile[0]) {strcpy(fitfile, argv[ai]); continue;}
144 fprintf(stderr, "Error: invalid argument '%s'\n", argv[ai]);
145 return(1);
146 }
147
148 /* Is something missing? */
149 if(!fitfile[0]) {
150 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
151 return(1);
152 }
153 /* If function was not selected by options, use default */
154 if(type<=0) type=233;
155 if(model==MODEL_UNKNOWN) model=MODEL_P3P3;
156 parNr=func_par_nr[model];
157
158 /* In verbose mode print arguments and options */
159 if(verbose>1) {
160 printf("datfile := %s\n", datfile);
161 printf("fitfile := %s\n", fitfile);
162 printf("svgfile := %s\n", svgfile);
163 printf("type := %d\n", type);
164 printf("parNr := %d\n", parNr);
165 printf("weights := %d\n", weights);
166 }
167
168 /*
169 * Set parameter constraints
170 * note that these apply to the [0,1] scaled data!
171 */
172 pmin[0]=-1.0e3; pmax[0]=5.0e3;
173 pmin[1]=-5.0e2; pmax[1]=1.0e3;
174 pmin[2]=-5.0e2; pmax[2]=1.0e4;
175 pmin[3]=-0.10; pmax[3]=1.0e4;
176 pmin[4]=-5.00; pmax[4]=5.0e3;
177 pmin[5]=-1.0e2; pmax[5]=1.0e4;
178
179
180 /*
181 * Read data
182 */
183 if(verbose>1) printf("reading %s\n", datfile);
184 if(dftRead(datfile, &dft)) {
185 fprintf(stderr, "Error in reading '%s': %s\n", datfile, dfterrmsg);
186 return(2);
187 }
188 if(dft.frameNr<3) {
189 fprintf(stderr, "Error: not enough samples for decent fitting.\n");
190 dftEmpty(&dft); return(3);
191 }
192 dataNr=dft.frameNr;
193
194 /* Check for NA's */
195 if(dft_nr_of_NA(&dft) > 0) {
196 fprintf(stderr, "Error: missing sample(s) in %s\n", datfile);
197 dftEmpty(&dft); return(2);
198 }
199
200 /* Sort the samples by time in case data is catenated from several curves */
201 (void)dftSortByFrame(&dft);
202 if(verbose>30) dftPrint(&dft);
203
204 /* Get min and max X and Y */
205 ret=dftMinMax(&dft, &tstart, &tstop, &miny, &maxy);
206 if(ret!=0) {
207 fprintf(stderr, "Error: invalid contents in %s\n", datfile);
208 dftEmpty(&dft); return(2);
209 }
210 if(dataNr<3 || tstop<=0.0 || maxy<=0.0) {
211 fprintf(stderr, "Error: invalid contents in %s\n", datfile);
212 dftEmpty(&dft); return(2);
213 }
214 if(tstart<0.0) fprintf(stderr, "Warning: negative x value(s).\n");
215 if(miny<0.0) fprintf(stderr, "Warning: negative y value(s).\n");
216
217 /* Check and set weights */
218 if(weights==0) {
219 if(dft.isweight==0) {
220 dft.isweight=1; for(fi=0; fi<dft.frameNr; fi++) dft.w[fi]=1.0;}
221 } else if(weights==1) {
222 dft.isweight=1; for(fi=0; fi<dft.frameNr; fi++) dft.w[fi]=1.0;
223 } else if(weights==2) {
224 dftWeightByFreq(&dft);
225 }
226 if(verbose==10) dftPrint(&dft);
227
228
229 /*
230 * Allocate memory for fits
231 */
232 if(verbose>1) printf("allocating memory for fits.\n");
233 ret=fit_allocate_with_dft(&fit, &dft);
234 if(ret) {
235 fprintf(stderr, "Error: cannot allocate space for fit results (%d).\n", ret);
236 dftEmpty(&dft); return(4);
237 }
238 /* Set necessary information in fit data structure */
239 fit.voiNr=dft.voiNr;
240 strncpy(fit.datafile, datfile, FILENAME_MAX);
241 tpcProgramName(argv[0], 1, 1, fit.program, 1024);
242 strcpy(fit.unit, dft.unit);
243 fit.time=time(NULL);
244 for(ri=0; ri<dft.voiNr; ri++) {
245 fit.voi[ri].type=type; fit.voi[ri].parNr=2+parNr;
246 fit.voi[ri].start=tstart; fit.voi[ri].end=tstop;
247 fit.voi[ri].dataNr=dataNr;
248 }
249
250 /*
251 * Scale data between [0,1] during the fitting
252 */
253 /* Set the scale factors */
254 double xscale, yscale[dft.voiNr];
255 xscale=1.0/tstop;
256 for(ri=0; ri<dft.voiNr; ri++) {
257 a=dft.voi[ri].y[0];
258 for(fi=1; fi<dft.frameNr; fi++)
259 if(dft.voi[ri].y[fi]>a) a=dft.voi[ri].y[fi];
260 yscale[ri]=1.0/a;
261 }
262 if(verbose>1) {
263 printf("xscale=%g yscale=", xscale);
264 for(ri=0; ri<dft.voiNr; ri++) printf("%g ", yscale[ri]);
265 printf("\n");
266 }
267 /* Allocate memory for scaled data for fitting */
268 double *scaled_data;
269 scaled_data=malloc(sizeof(double)*3*dft.frameNr);
270 if(scaled_data==NULL) {
271 fprintf(stderr, "Error: out of memory.\n");
272 dftEmpty(&dft); fitEmpty(&fit);
273 return(5);
274 }
275 /* Set pointers */
276 x=scaled_data; ymeas=scaled_data+dft.frameNr; yfit=ymeas+dft.frameNr;
277 w=dft.w;
278 /* Calculate scaled x values */
279 for(fi=0; fi<dft.frameNr; fi++) x[fi]=xscale*dft.x[fi];
280
281
282 /*
283 * Fit each TAC
284 */
285 if(verbose>1) {printf("fitting\n"); fflush(stdout);}
286 for(ri=0; ri<dft.voiNr; ri++) {
287 if(verbose>0 && dft.voiNr>1) printf("%s\n", dft.voi[ri].name);
288
289 /* Scale y values for this TAC */
290 for(fi=0; fi<dft.frameNr; fi++)
291 ymeas[fi]=yscale[ri]*dft.voi[ri].y[fi];
292
293 /* Set the initial values for parameters */
294 fit.voi[ri].p[0]=0.0; fit.voi[ri].p[1]=1.0;
295 fit.voi[ri].wss=3.402823e+38;
296
297 /* fit */
300 ret=tgo(pmin, pmax, func_ratf, NULL, parNr, 15, &fit.voi[ri].wss,
301 fit.voi[ri].p+2, 1000, 3, verbose-8);
302 if(ret) {
303 fprintf(stderr, "Error %d in TGO.\n", ret);
304 dftEmpty(&dft); fitEmpty(&fit); free(scaled_data);
305 return(6);
306 }
307
308 /* Print measured and fitted curve (scaled down) */
309 if(verbose>6) {
310 printf(" Measured Fitted:\n");
311 for(fi=0; fi<dft.frameNr; fi++)
312 printf(" %2d: %8.2e %8.2e %8.2e\n", fi+1, x[fi], ymeas[fi], yfit[fi]);
313 printf("\n");
314 }
315 if(verbose>2) {
316 printf(" fitted parameters (scaled), with limits:\n");
317 for(pi=0; pi<parNr; pi++)
318 printf(" %g [%g, %g]\n", fit.voi[ri].p[pi+2], pmin[pi], pmax[pi]);
319 printf("\n");
320 }
321
322 /* Force parameter values inside limits, as they are in the simulation */
323 modelCheckParameters(parNr, pmin, pmax,
324 fit.voi[ri].p+2, fit.voi[ri].p+2, &a);
325 fit.voi[ri].wss/=a; // remove penalty from reported WSS
326 /* Calculate the function values again in case parameters were changed */
327 func_ratf(parNr, fit.voi[ri].p+2, NULL);
328
329 /* Scale the fitted y values back */
330 for(fi=0; fi<dft.frameNr; fi++) dft.voi[ri].y2[fi]=yfit[fi]/yscale[ri];
331
332 /* Calculate the WSS from data in original scale */
333 a=c=0.0;
334 for(fi=0; fi<dft.frameNr; fi++) {
335 b=dft.voi[ri].y2[fi]-dft.voi[ri].y[fi];
336 a+=w[fi]*b*b;
337 if(fi==0 || fabs(b)>c) c=fabs(b);
338 }
339 fit.voi[ri].wss=a;
340 if(verbose>1) printf(" max_dev := %g\n", c);
341 if(verbose>4) printf("\n last_y := %g\n\n", dft.voi[ri].y2[dft.frameNr-1]);
342
343 /* Scale back the parameters */
344 for(pi=0; pi<parNr; pi+=2)
345 fit.voi[ri].p[pi+2]/=yscale[ri];
346 for(pi=0; pi<parNr; pi++)
347 fit.voi[ri].p[pi+2]*=(double)pow(xscale, floor(1+pi/2));
348
349 } /* next TAC */
350 free(scaled_data);
351
352
353 /*
354 * Print fit results on screen
355 */
356 if(verbose>1) {
357 printf("\n");
358 fitWrite(&fit, "stdout");
359 printf("\n");
360 }
361
362 /*
363 * Save fit results
364 */
365 if(verbose>1) printf("saving results in %s\n", fitfile);
366 if(fitWrite(&fit, fitfile)) {
367 fprintf(stderr, "Error in writing '%s': %s\n", fitfile, fiterrmsg);
368 dftEmpty(&dft); fitEmpty(&fit); return(11);
369 }
370
371 /*
372 * Plotting of fitted TACs, if requested
373 */
374 if(svgfile[0]) {
375 if(verbose>1) printf("saving SVG plot\n");
376
377 /* Create a DFT containing fitted TACs */
378 char tmp[128];
379 DFT dft2;
380 dftInit(&dft2); ret=dftdup(&dft, &dft2);
381 if(ret) {
382 fprintf(stderr, "Error: cannot plot fitted curves.\n");
383 dftEmpty(&dft); fitEmpty(&fit);
384 return(21);
385 }
386 for(ri=0; ri<dft.voiNr; ri++) for(fi=0; fi<dft.frameNr; fi++)
387 dft2.voi[ri].y[fi]=dft2.voi[ri].y2[fi];
388
389 /* Save SVG plot of fitted and original data */
390 tpcProgramName(argv[0], 0, 0, tmp, 64); strcat(tmp, " ");
391 strcat(tmp, model_name[model]); strcat(tmp, " ");
392 if(strlen(dft2.studynr)>1) strcat(tmp, dft.studynr);
393 ret=plot_fit_svg(&dft, &dft2, tmp, svgfile, verbose-8);
394 if(ret) {
395 fprintf(stderr, "Error (%d) in writing '%s'.\n", ret, svgfile);
396 dftEmpty(&dft2); dftEmpty(&dft); fitEmpty(&fit);
397 return(30+ret);
398 }
399 if(verbose>0) printf("Plots written in %s\n", svgfile);
400
401 dftEmpty(&dft2);
402 }
403
404 /* Free memory */
405 dftEmpty(&dft); fitEmpty(&fit);
406
407 return(0);
408}
409/*****************************************************************************/
410
411/*****************************************************************************
412 *
413 * Functions to be minimized
414 *
415 *****************************************************************************/
416double func_ratf(int parNr, double *p, void *fdata)
417{
418 int i;
419 double v, dd, dr, x2, x3, wss;
420 double pa[MAX_PARAMETERS], penalty=1.0;
421
422 /* Check parameters against the constraints */
423 (void)modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
424 if(fdata) {}
425 if(0) {
426 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
427 printf("\n");
428 }
429
430 /* Calculate the curve and WSS */
431 x2=x3=1.0;
432 for(i=0, wss=0.0; i<dataNr; i++) {
433 /* Calculate x^2 and x^3 */
434 if(parNr>=3) {x2=x[i]*x[i]; if(parNr>=5) x3=x2*x[i];}
435 /* Calculate the divider */
436 dr=1.0;
437 if(parNr>=2) dr+=pa[1]*x[i];
438 if(parNr>=4) dr+=pa[3]*x2;
439 if(parNr>=6) dr+=pa[5]*x3;
440 /* Calculate the dividend */
441 dd=0.0;
442 if(parNr>=1) dd+=pa[0]*x[i];
443 if(parNr>=3) dd+=pa[2]*x2;
444 if(parNr>=5) dd+=pa[4]*x3;
445 /* Calculate the curve value */
446 yfit[i]=dd/dr;
447 /* Calculate weighted SS */
448 v=yfit[i]-ymeas[i]; wss+=w[i]*v*v;
449 }
450 if(!isfinite(wss)) wss=nan("");
451 wss*=penalty;
452 return(wss);
453}
454/*****************************************************************************/
455
456/*****************************************************************************/
458
int modelCheckParameters(int par_nr, double *lower_p, double *upper_p, double *test_p, double *accept_p, double *penalty)
Definition constraints.c:15
void dftInit(DFT *data)
Definition dft.c:38
int dftdup(DFT *dft1, DFT *dft2)
Definition dft.c:655
char dfterrmsg[64]
Definition dft.c:6
int dftSortByFrame(DFT *dft)
Definition dft.c:1169
int dftMinMax(DFT *dft, double *minx, double *maxx, double *miny, double *maxy)
Definition dft.c:974
void dftEmpty(DFT *data)
Definition dft.c:20
int dft_nr_of_NA(DFT *dft)
Definition dft.c:905
int dftRead(char *filename, DFT *data)
Definition dftio.c:22
void dftPrint(DFT *data)
Definition dftio.c:538
int fit_allocate_with_dft(FIT *fit, DFT *dft)
Definition fitres.c:14
Header file for libtpccurveio.
void fitEmpty(FIT *fit)
Definition mathfunc.c:18
int fitWrite(FIT *fit, char *filename)
Definition mathfunc.c:54
char fiterrmsg[64]
Definition mathfunc.c:6
void fitInit(FIT *fit)
Definition mathfunc.c:38
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
Definition proginfo.c:101
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
Header file for libtpcmodel.
int tgo(double *lowlim, double *uplim, double(*objf)(int, double *, void *), void *objfData, int dim, int neighNr, double *fmin, double *gmin, int samNr, int tgoNr, int verbose)
Definition tgo.c:39
int TGO_LOCAL_INSIDE
Definition tgo.c:29
#define MAX_PARAMETERS
Definition libtpcmodel.h:31
int TGO_SQUARED_TRANSF
Definition tgo.c:27
Header file for libtpcmodext.
int plot_fit_svg(DFT *dft1, DFT *dft2, char *main_title, char *fname, int verbose)
Definition plotfit.c:216
int dftWeightByFreq(DFT *dft)
Header file for libtpcsvg.
Voi * voi
char studynr[MAX_STUDYNR_LEN+1]
double * w
int voiNr
int frameNr
int isweight
double * x
char unit[MAX_UNITS_LEN+1]
int voiNr
char datafile[FILENAME_MAX]
char program[1024]
char unit[MAX_UNITS_LEN+1]
FitVOI * voi
time_t time
double wss
double end
double start
double p[MAX_FITPARAMS]
double * y2
double * y
char name[MAX_REGIONNAME_LEN+1]