TPCCLIB
Loading...
Searching...
No Matches
fitvb.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 <unistd.h>
14#include <string.h>
15#include <time.h>
16/*****************************************************************************/
17#include "libtpcmisc.h"
18#include "libtpcmodel.h"
19#include "libtpccurveio.h"
20#include "libtpcsvg.h"
21#include "libtpcmodext.h"
22/*****************************************************************************/
23
24/*****************************************************************************/
25const int parNr=1;
26DFT input, dft;
27double *petmeas, *petsim;
28double pmin[MAX_PARAMETERS], pmax[MAX_PARAMETERS];
29int fitframeNr;
30double wss_wo_penalty=0.0;
31/*****************************************************************************/
32/* Local functions */
33double vbFunc(int parNr, double *p, void*);
34/*****************************************************************************/
35
36/*****************************************************************************/
37static char *info[] = {
38 "Non-linear fitting of Vb as the only model parameter to blood and tissue,",
39 "time-activity curves (BTAC, and TTACs), to verify that goodness-of-fit",
40 "is better with compartmental models.",
41 "Sample times must be in minutes.",
42 " ",
43 "Usage: @P [Options] btacfile ttacfile endtime resultfile",
44 " ",
45 "Options:",
46 " -minVb=<Vb(%)>",
47 " Enter a lower limit for Vb; 0 by default.",
48 " -maxVb=<Vb(%)>",
49 " Enter an upper limit for Vb; 100 by default.",
50 " -fit=<Filename>",
51 " Fitted regional TACs are written in DFT format.",
52 " -svg=<Filename>",
53 " Fitted and measured TACs are plotted in specified SVG file.",
54 " -stdoptions", // List standard options like --help, -v, etc
55 " ",
56 "See also: fitk2, fitk3, fitk4, fitk5, fit_h2o, tacweigh, taccbv",
57 " ",
58 "Keywords: TAC, modelling, vascular fraction",
59 0};
60/*****************************************************************************/
61
62/*****************************************************************************/
63/* Turn on the globbing of the command line, since it is disabled by default in
64 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
65 In Unix&Linux wildcard command line processing is enabled by default. */
66/*
67#undef _CRT_glob
68#define _CRT_glob -1
69*/
70int _dowildcard = -1;
71/*****************************************************************************/
72
73/*****************************************************************************/
77int main(int argc, char **argv)
78{
79 int ai, help=0, version=0, verbose=1;
80 int ri, fi, pi, m, n, ret;
81 char dfile[FILENAME_MAX], bfile[FILENAME_MAX], rfile[FILENAME_MAX], ffile[FILENAME_MAX];
82 char svgfile[FILENAME_MAX];
83 double fitdur, wss, aic;
84 double def_pmin[MAX_PARAMETERS], def_pmax[MAX_PARAMETERS];
85
86
87
88 /* Set parameter initial values and constraints */
89 /* Vb */ def_pmin[0]=0.0; def_pmax[0]=1.0;
90
91 /*
92 * Get arguments
93 */
94 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
95 dfile[0]=bfile[0]=rfile[0]=ffile[0]=svgfile[0]=(char)0;
96 fitdur=nan("");
97 //iftInit(&ift); resInit(&res); dftInit(&dft); dftInit(&input);
98 /* Get options first, because it affects what arguments are read */
99 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
100 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
101 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
102 if(strncasecmp(cptr, "minVb=", 6)==0 && strlen(cptr)>3) {
103 double minVb=0.01*atof_dpi(cptr+6);
104 if(minVb>=0.0) {
105 if(minVb>=1.0) fprintf(stderr, "Warning: min Vb was set to %g%%\n", 100.*minVb);
106 def_pmin[0]=minVb;
107 continue;
108 }
109 } else if(strncasecmp(cptr, "maxVb=", 6)==0 && strlen(cptr)>3) {
110 double maxVb=0.01*atof_dpi(cptr+6);
111 if(maxVb>=0.0) {
112 if(maxVb<0.05) fprintf(stderr, "Warning: max Vb was set to %g%%\n", 100.*maxVb);
113 def_pmax[0]=maxVb;
114 continue;
115 }
116 } else if(strncasecmp(cptr, "FIT=", 4)==0) {
117 strlcpy(ffile, cptr+4, FILENAME_MAX); if(strlen(ffile)>0) continue;
118 } else if(strncasecmp(cptr, "SVG=", 4)==0) {
119 strlcpy(svgfile, cptr+4, FILENAME_MAX); if(strlen(svgfile)>0) continue;
120 }
121 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
122 return(1);
123 } else break;
124
125 /* Print help or version? */
126 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
127 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
128 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
129
130 /* Process other arguments, starting from the first non-option */
131 if(ai<argc) {strlcpy(bfile, argv[ai++], FILENAME_MAX);}
132 if(ai<argc) {strlcpy(dfile, argv[ai++], FILENAME_MAX);}
133 if(ai<argc) {
134 if(!atof_with_check(argv[ai], &fitdur) && fitdur>=0.0) {
135 ai++;
136 } else {
137 fprintf(stderr, "Error: invalid fit time '%s'.\n", argv[ai]);
138 return(1);
139 }
140 }
141 if(ai<argc) {strlcpy(rfile, argv[ai++], FILENAME_MAX);}
142 if(ai<argc) {
143 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
144 return(1);
145 }
146 /* Did we get all the information that we need? */
147 if(!rfile[0]) { // note that parameter file is optional
148 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
149 return(1);
150 }
151 if(fitdur<=0) fitdur=1.0E+100;
152 if(def_pmin[0]>=def_pmax[0]) {
153 fprintf(stderr, "Error: invalid limits for Vb.\n");
154 return(1);
155 }
156
157
158 /* In verbose mode print arguments and options */
159 if(verbose>1) {
160 printf("bfile := %s\n", bfile);
161 printf("dfile :=%s\n", dfile);
162 printf("rfile := %s\n", rfile);
163 printf("ffile := %s\n", ffile);
164 printf("svgfile := %s\n", svgfile);
165 printf("fitdur := %g\n", fitdur);
166 printf("Vb: %g - %g\n", def_pmin[0], def_pmax[0]);
167 }
168
169
170 /*
171 * Read tissue and input data
172 */
173 if(verbose>1) printf("reading tissue and input data\n");
174 dftInit(&dft); dftInit(&input);
175 char tmp[256];
176 ret=dftReadModelingData(dfile, bfile, NULL, NULL, &fitdur,
177 &fitframeNr, &dft, &input, stdout, verbose-2, tmp);
178 if(ret!=0) {
179 fprintf(stderr, "Error: %s\n", tmp);
180 return(2);
181 }
182 if(fitframeNr<4 || input.frameNr<4) {
183 fprintf(stderr, "Error: too few samples in specified fit duration.\n");
184 dftEmpty(&input); dftEmpty(&dft); return(2);
185 }
186 if(verbose>10) dftPrint(&dft);
187 if(verbose>10) dftPrint(&input);
188 /* Print the weights */
189 if(verbose>2) {
190 fprintf(stdout, "common_data_weights := %g", dft.w[0]);
191 for(fi=1; fi<dft.frameNr; fi++) fprintf(stdout, ", %g", dft.w[fi]);
192 fprintf(stdout, "\n");
193 }
194
195
196 /*
197 * Prepare the room for the results
198 */
199 if(verbose>1) printf("initializing result data\n");
200 RES res; resInit(&res);
201 ret=res_allocate_with_dft(&res, &dft); if(ret!=0) {
202 fprintf(stderr, "Error: cannot setup memory for results.\n");
203 dftEmpty(&input); dftEmpty(&dft); return(7);
204 }
205 /* Copy titles & filenames */
206 tpcProgramName(argv[0], 1, 1, res.program, 256);
207 strcpy(res.datafile, dfile);
208 strcpy(res.bloodfile, bfile);
209 strcpy(res.fitmethod, "TGO");
210 /* Constants */
211 res.isweight=dft.isweight;
212 /* Set data range */
213 sprintf(res.datarange, "%g - %g %s", 0.0, fitdur, dftTimeunit(dft.timeunit));
214 res.datanr=fitframeNr;
215 /* Set current time to results */
216 res.time=time(NULL);
217 /* Set parameter number, including also the extra "parameters"
218 and the parameter names and units */
219 res.parNr=3;
220 pi=0; strcpy(res.parname[pi], "Vb"); strcpy(res.parunit[pi], "%");
221 pi++; strcpy(res.parname[pi], "WSS"); strcpy(res.parunit[pi], "");
222 pi++; strcpy(res.parname[pi], "AIC"); strcpy(res.parunit[pi], "");
223
224
225 /*
226 * Fit ROIs
227 */
228 if(verbose>0) {
229 fprintf(stdout, "fitting regional TACs: ");
230 if(verbose>1) fprintf(stdout, "\n");
231 }
232 fflush(stdout);
233 for(ri=0; ri<dft.voiNr; ri++) {
234 if(verbose>2) printf("\n %d %s:\n", ri, dft.voi[ri].name);
235
236 /* Initiate values */
237 petmeas=dft.voi[ri].y; petsim=dft.voi[ri].y2;
238
239 /* Set constraints */
240 pmin[0]=def_pmin[0]; pmax[0]=def_pmax[0]; /* Vb */
241 if(verbose>3) {
242 printf(" constraints :=");
243 for(pi=0; pi<parNr; pi++) printf(" [%g,%g]", pmin[pi], pmax[pi]);
244 printf("\n");
245 }
246
247 /* Fit */
250 ret=tgo(
251 pmin, pmax, vbFunc, NULL, parNr, 8,
252 &wss, res.voi[ri].parameter, 100, 0, verbose /*-8*/);
253 if(ret>0) {
254 fprintf(stderr, "\nError in optimization (%d).\n", ret);
255 dftEmpty(&input); dftEmpty(&dft); resEmpty(&res); return(8);
256 }
257 if(verbose>4) {
258 printf(" fitted_parameters :=");
259 for(pi=0; pi<parNr; pi++) printf(" %g", res.voi[ri].parameter[pi]);
260 printf("\n");
261 }
262 /* Correct fitted parameters to match constraints like inside function */
263 (void)modelCheckParameters(parNr, pmin, pmax, res.voi[ri].parameter,
264 res.voi[ri].parameter, NULL);
265 wss=wss_wo_penalty;
266
267 /* Calculate AIC, based on nr of parameters that actually are fitted */
268 for(pi=n=0; pi<parNr; pi++) if(pmax[pi]>pmin[pi]) n++;
269 if(verbose>2) printf("nr_of_fitted_parameters := %d\n", n);
270 for(fi=m=0; fi<fitframeNr; fi++) if(dft.w[fi]>0.0) m++;
271 if(verbose>2) printf("nr_of_fitted_samples := %d\n", m);
272 aic=aicSS(wss, m, n);
273
274 /* Set results wss and aic */
275 res.voi[ri].parameter[res.parNr-2]=wss;
276 res.voi[ri].parameter[res.parNr-1]=aic;
277
278 /* done with this region */
279 if(dft.voiNr>2 && verbose==1) {fprintf(stdout, "."); fflush(stdout);}
280
281
282 } /* next region */
283 if(verbose>0) {fprintf(stdout, "\n"); fflush(stdout);}
284
285 /* Convert Vb fractions to percents */
286 for(ri=0; ri<res.voiNr; ri++){
287 res.voi[ri].parameter[0]*=100.0;
288 }
289
290 /*
291 * Print results on screen
292 */
293 if(verbose>0) {resPrint(&res); fprintf(stdout, "\n");}
294
295
296 /*
297 * Save results
298 */
299 if(verbose>1) printf("saving results\n");
300 ret=resWrite(&res, rfile, verbose-3);
301 if(ret) {
302 fprintf(stderr, "Error in writing '%s': %s\n", rfile, reserrmsg);
303 dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
304 return(11);
305 }
306 if(verbose>0) fprintf(stdout, "Model parameters written in %s\n", rfile);
307
308
309 /*
310 * Saving and/or plotting of fitted TACs
311 */
312 if(svgfile[0] || ffile[0]) {
313
314 /* Create a DFT containing fitted TACs */
315 char tmp[64];
316 DFT dft2;
317 dftInit(&dft2); ret=dftdup(&dft, &dft2);
318 if(ret) {
319 fprintf(stderr, "Error: cannot save fitted curves.\n");
320 dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
321 return(21);
322 }
323 for(ri=0; ri<dft.voiNr; ri++) for(fi=0; fi<fitframeNr; fi++)
324 dft2.voi[ri].y[fi]=dft2.voi[ri].y2[fi];
325 dft2.frameNr=fitframeNr;
326
327 /* Save SVG plot of fitted and original data */
328 if(svgfile[0]) {
329 if(verbose>1) printf("saving SVG plot\n");
330 sprintf(tmp, "Vb fit: ");
331 if(strlen(dft.studynr)>0) strcat(tmp, dft.studynr);
332 /*fi=dft.frameNr; dft.frameNr=fitframeNr; if(fi>dft.frameNr) dft.frameNr++;
333 ret=plot_fit_svg(&dft, &dft2, tmp, svgfile); dft.frameNr=fi;*/
334 ret=plot_fitrange_svg(&dft, &dft2, tmp, 0.0, 1.02*dft.x[fitframeNr-1],
335 0.0, nan(""), svgfile, verbose-8);
336 if(ret) {
337 fprintf(stderr, "Error (%d) in writing '%s'.\n", ret, svgfile);
338 dftEmpty(&dft2); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
339 return(30+ret);
340 }
341 if(verbose>0) printf("Plots written in %s\n", svgfile);
342 }
343
344 /* Save fitted TACs */
345 if(ffile[0]) {
346 if(verbose>1) printf("saving fitted curves\n");
347 tpcProgramName(argv[0], 1, 0, tmp, 64);
348 sprintf(dft2.comments, "# program := %s\n", tmp);
349 if(dftWrite(&dft2, ffile)) {
350 fprintf(stderr, "Error in writing '%s': %s\n", ffile, dfterrmsg);
351 dftEmpty(&dft2); dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
352 return(22);
353 }
354 if(verbose>0) printf("Fitted TACs written in %s\n", ffile);
355 }
356
357 dftEmpty(&dft2);
358 }
359
360 dftEmpty(&dft); dftEmpty(&input); resEmpty(&res);
361 return(0);
362}
363/*****************************************************************************/
364
365/*****************************************************************************
366 *
367 * Functions to be minimized
368 *
369 *****************************************************************************/
370double vbFunc(int parNr, double *p, void *fdata)
371{
372 int ret;
373 double Vb, wss=0.0;
374 double pa[MAX_PARAMETERS], penalty=1.0;
375
376 /* Check parameters against the constraints */
377 ret=modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
378 if(fdata) {}
379 Vb=pa[0];
380
381 /* Interpolate BTAC to measured PET frames */
383 ret=interpolate4pet(
384 input.x, input.voi[0].y, input.frameNr,
385 dft.x1, dft.x2, petsim, NULL, NULL, fitframeNr);
386 else
387 ret=interpolate(
388 input.x, input.voi[0].y, input.frameNr,
389 dft.x, petsim, NULL, NULL, fitframeNr);
390 if(ret) {
391 printf("error %d in interpolation\n", ret);
392 return(nan(""));
393 }
394 /* And multiply with Vb */
395 for(int i=0; i<fitframeNr; i++) petsim[i]*=Vb;
396
397 /* Calculate error */
398 for(int i=0; i<fitframeNr; i++) if(dft.w[i]>0.0) {
399 double d=petmeas[i]-petsim[i];
400 wss+=dft.w[i]*d*d;
401 }
402 wss_wo_penalty=wss;
403 wss*=penalty;
404 if(0) {printf("%g => %g\n", pa[0], wss); fflush(stdout);}
405
406 return(wss);
407}
408/*****************************************************************************/
409
410/*****************************************************************************/
double aicSS(double ss, const int n, const int k)
Definition aic.c:20
int modelCheckParameters(int par_nr, double *lower_p, double *upper_p, double *test_p, double *accept_p, double *penalty)
Definition constraints.c:15
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
double atof_dpi(char *str)
Definition decpoint.c:59
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
void dftEmpty(DFT *data)
Definition dft.c:20
int dftReadModelingData(char *tissuefile, char *inputfile1, char *inputfile2, char *inputfile3, double *fitdur, int *fitframeNr, DFT *tis, DFT *inp, FILE *loginfo, int verbose, char *status)
Definition dftinput.c:342
void dftPrint(DFT *data)
Definition dftio.c:538
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
int res_allocate_with_dft(RES *res, DFT *dft)
Definition dftres.c:14
int interpolate(double *x, double *y, int nr, double *newx, double *newy, double *newyi, double *newyii, int newnr)
Linear interpolation and integration.
Definition integr.c:28
int interpolate4pet(double *x, double *y, int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, int newnr)
Interpolate and integrate TAC to PET frames.
Definition integr.c:510
Header file for libtpccurveio.
char reserrmsg[64]
Definition result.c:6
void resInit(RES *res)
Definition result.c:52
void resPrint(RES *res)
Definition result.c:186
int resWrite(RES *res, char *filename, int verbose)
Definition result.c:565
#define DFT_TIME_STARTEND
void resEmpty(RES *res)
Definition result.c:22
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
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_fitrange_svg(DFT *dft1, DFT *dft2, char *main_title, double x1, double x2, double y1, double y2, char *fname, int verbose)
Definition plotfit.c:16
Header file for libtpcsvg.
int timetype
Voi * voi
int timeunit
char studynr[MAX_STUDYNR_LEN+1]
double * w
double * x1
char comments[_DFT_COMMENT_LEN+1]
int voiNr
double * x2
int frameNr
int isweight
double * x
int parNr
char parname[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
int voiNr
int datanr
ResVOI * voi
char program[1024]
char datarange[128]
int isweight
char datafile[FILENAME_MAX]
char fitmethod[128]
char parunit[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
char bloodfile[FILENAME_MAX]
time_t time
double parameter[MAX_RESPARAMS]
double * y2
double * y
char name[MAX_REGIONNAME_LEN+1]