TPCCLIB
Loading...
Searching...
No Matches
fit_wcbf.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#ifdef HAVE_OMP_H
11#include <omp.h>
12#endif
13/*****************************************************************************/
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <math.h>
18/*****************************************************************************/
19#include "tpcextensions.h"
20#include "tpcift.h"
21#include "tpctac.h"
22#include "tpcpar.h"
23#include "tpcli.h"
24#include "tpccm.h"
25#include "tpctacmod.h"
26#include "tpclinopt.h"
27#include "tpcrand.h"
28#include "tpcnlopt.h"
29#include "tpcbfm.h"
30/*****************************************************************************/
31
32/*****************************************************************************/
33/* Local functions */
34double func_wcbf(int parNr, double *p, void*);
35/*****************************************************************************/
36typedef struct FITDATA {
38 unsigned int ni;
40 double *xi;
42 double *yi;
43
45 unsigned int nt;
47 double *xt1;
49 double *xt2;
51 double *xt;
53 double *yt;
55 double *w;
57 double *syt;
58
60 double pGM, pWM;
61
63 int verbose;
64} FITDATA;
65/*****************************************************************************/
66
67/*****************************************************************************/
68static char *info[] = {
69 "Non-linear fitting of the radiowater model with PVC to brain TTACs using BTAC",
70 "as the input function (Iida et al., 2000).",
71 " ",
72 "Usage: @P [Options] btacfile ttacfile [parfile]",
73 " ",
74 "Options:",
75 " -Va=<value>",
76 " Arterial blood volume is constrained to given value (mL/mL).",
77 " -dt=<value>",
78 " Delay time (activity appearance time in tissue minus that in blood)",
79 " in seconds. Dispersion in BTAC is corrected in relation to delay",
80 " as tau=0.31*dt-0.30 (Iida et al., 1989), when tau>0.",
81 " -pGM=<value>",
82 " Partition coefficient of water in grey matter; by default 1.03 mL/mL.",
83 " -pWM=<value>",
84 " Partition coefficient of water in white matter; by default 0.86 mL/L.",
85 " -fWM=<value> | fit",
86 " Blood flow in white matter; by default 0.21 mL/(min*mL).",
87 " Enter 'fit' to estimate fW as a free parameter.",
88 " -w1 | -wf",
89 " By default, weights in data file are used, if available.",
90 " With these options all weights can be set to 1.0 (no weighting)",
91 " or based on frame durations.",
92 " -svg=<Filename>",
93 " Fitted and measured TACs are plotted in specified SVG file.",
94 " -fit=<Filename>",
95 " Fitted TTACs are written in specified TAC file.",
96 " -sim=<Filename>",
97 " Fitted TTACs at BTAC sample times are saved in specified TAC file.",
98 " -stdoptions", // List standard options like --help, -v, etc
99 " ",
100 "Sample times must be in seconds, unless units are specified in the file.",
101 " ",
102 "Reference:",
103 "1. Iida H et al., Quantitation of regional cerebral blood flow corrected",
104 " for partial volume effect using O-15 water and PET: I. Theory, error",
105 " analysis, and stereologic comparison.",
106 " J Cereb Blood Flow Metab. 2000;20(8):1237-1251.",
107 " https://doi.org/10.1097/00004647-200008000-00009",
108 "2. Iida et al., A determination of the regional brain/blood partition",
109 " coefficient of water using dynamic positron emission tomography.",
110 " J Cereb Blood Flow Metab. 1989;9(6):874-885.",
111 " https://doi.org/10.1038/jcbfm.1989.121",
112 " ",
113 "See also: fit_h2o, bfmh2o, fitk2",
114 " ",
115 "Keywords: TAC, modelling, perfusion, brain, radiowater",
116 0};
117/*****************************************************************************/
118
119/*****************************************************************************/
120/* Turn on the globbing of the command line, since it is disabled by default in
121 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
122 In Unix&Linux wildcard command line processing is enabled by default. */
123/*
124#undef _CRT_glob
125#define _CRT_glob -1
126*/
127int _dowildcard = -1;
128/*****************************************************************************/
129
130/*****************************************************************************/
134int main(int argc, char **argv)
135{
136 int ai, help=0, version=0, verbose=1;
137 char btacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], parfile[FILENAME_MAX],
138 svgfile[FILENAME_MAX], simfile[FILENAME_MAX], fitfile[FILENAME_MAX];
139 int weights=0; // 0=default, 1=no weighting, 2=frequency
140 double fixed_dt=nan("");
141 double fixed_va=nan("");
142 double fixed_pg=1.03;
143 double fixed_pw=0.86;
144 double fixed_fw=0.21;
145
146 drandSeed(1);
147
148
149
150 /*
151 * Get arguments
152 */
153 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
154 btacfile[0]=ttacfile[0]=parfile[0]=svgfile[0]=fitfile[0]=simfile[0]=(char)0;
155 /* Options */
156 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
157 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
158 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
159 if(strcasecmp(cptr, "W1")==0) {
160 weights=1; continue;
161 } else if(strcasecmp(cptr, "WF")==0) {
162 weights=2; continue;
163 } else if(strncasecmp(cptr, "VA=", 3)==0 && strlen(cptr)>3) {
164 if(!atofCheck(cptr+3, &fixed_va) && fixed_va>=0.0 && fixed_va<1.0) continue;
165 } else if(strncasecmp(cptr, "DT=", 3)==0 && strlen(cptr)>3) {
166 if(!atofCheck(cptr+3, &fixed_dt) && fixed_dt>-50.0 && fixed_dt<50.0) continue;
167 } else if(strncasecmp(cptr, "DELAY=", 6)==0 && strlen(cptr)>6) {
168 if(!atofCheck(cptr+6, &fixed_dt) && fixed_dt>-50.0 && fixed_dt<50.0) continue;
169 } else if(strncasecmp(cptr, "PGM=", 4)==0 && strlen(cptr)>4) {
170 if(!atofCheck(cptr+4, &fixed_pg) && fixed_pg>0.0 && fixed_pg<1.05) continue;
171 } else if(strncasecmp(cptr, "PWM=", 4)==0 && strlen(cptr)>4) {
172 if(!atofCheck(cptr+4, &fixed_pw) && fixed_pw>0.0 && fixed_pw<1.05) continue;
173 } else if(strncasecmp(cptr, "FWM=FIT", 5)==0) {
174 fixed_fw=nan(""); continue;
175 } else if(strncasecmp(cptr, "FWM=", 4)==0 && strlen(cptr)>4) {
176 if(!atofCheck(cptr+4, &fixed_fw) && fixed_fw>=0.0 && fixed_fw<1.0) continue;
177 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
178 strlcpy(svgfile, cptr+4, FILENAME_MAX); continue;
179 } else if(strncasecmp(cptr, "FIT=", 4)==0 && strlen(cptr)>4) {
180 strlcpy(fitfile, cptr+4, FILENAME_MAX); continue;
181 } else if(strncasecmp(cptr, "SIM=", 4)==0 && strlen(cptr)>4) {
182 strlcpy(simfile, cptr+4, FILENAME_MAX); continue;
183 }
184 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
185 return(1);
186 } else break;
187
188 TPCSTATUS status; statusInit(&status);
189 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
190 status.verbose=verbose-3;
191
192 /* Print help or version? */
193 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
194 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
195 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
196
197 /* Process other arguments, starting from the first non-option */
198 if(ai<argc) strlcpy(btacfile, argv[ai++], FILENAME_MAX);
199 if(ai<argc) strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
200 if(ai<argc) strlcpy(parfile, argv[ai++], FILENAME_MAX);
201 if(ai<argc) {
202 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
203 return(1);
204 }
205 /* Did we get all the information that we need? */
206 if(!ttacfile[0]) { // note that parameter file is optional
207 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
208 return(1);
209 }
210
211 /* In verbose mode print arguments and options */
212 if(verbose>1) {
213 printf("btacfile := %s\n", btacfile);
214 printf("ttacfile := %s\n", ttacfile);
215 if(parfile[0]) printf("parfile := %s\n", parfile);
216 if(svgfile[0]) printf("svgfile := %s\n", svgfile);
217 if(fitfile[0]) printf("fitfile := %s\n", fitfile);
218 if(simfile[0]) printf("simfile := %s\n", simfile);
219 printf("weights := %d\n", weights);
220 printf("fixed_pg := %g\n", fixed_pg);
221 printf("fixed_pw := %g\n", fixed_pw);
222 if(!isnan(fixed_va)) printf("fixed_va := %g\n", fixed_va);
223 if(!isnan(fixed_fw)) printf("fixed_fw := %g\n", fixed_fw);
224 if(!isnan(fixed_dt)) printf("fixed_dt := %g\n", fixed_dt);
225 fflush(stdout);
226 }
227
228
229 /*
230 * Read the data
231 */
232 if(verbose>1) printf("reading TACs\n");
233 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
234 TAC ttac, btac; tacInit(&ttac); tacInit(&btac);
235
236 if(tacRead(&ttac, ttacfile, &status)!=TPCERROR_OK) {
237 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
238 tacFree(&ttac); tacFree(&btac); return(2);
239 }
240 if(verbose>2) {
241 printf("ttac.fileformat := %s\n", tacFormattxt(ttac.format));
242 printf("ttacNr := %d\n", ttac.tacNr);
243 printf("ttac.sampleNr := %d\n", ttac.sampleNr);
244 fflush(stdout);
245 }
246
247 if(tacRead(&btac, btacfile, &status)!=TPCERROR_OK) {
248 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
249 tacFree(&ttac); tacFree(&btac); return(2);
250 }
251 if(verbose>2) {
252 printf("btac.fileformat := %s\n", tacFormattxt(btac.format));
253 printf("btacNr := %d\n", btac.tacNr);
254 printf("btac.sampleNr := %d\n", btac.sampleNr);
255 fflush(stdout);
256 }
257 if(btac.tacNr>1) {
258 if(verbose>0) fprintf(stderr, "Warning: BTAC file contains more than two TACs.\n");
259 btac.tacNr=1;
260 }
261
262 if(ttac.sampleNr<7 || btac.sampleNr<7) {
263 fprintf(stderr, "Error: too few samples.\n");
264 tacFree(&ttac); tacFree(&btac); return(2);
265 }
266 /* Check NaNs */
267 if(tacNaNs(&ttac)>0 || tacNaNs(&btac)>0) {
268 fprintf(stderr, "Error: data contains missing values.\n");
269 tacFree(&ttac); tacFree(&btac); return(2);
270 }
271 /* Sort data by sample time */
272 tacSortByTime(&ttac, &status);
273 tacSortByTime(&btac, &status);
274 /* Fix any gaps and overlap in data if possible and if not then quit with error */
275 if(tacSetXContiguous(&ttac) || tacSetXContiguous(&btac)) {
276 fprintf(stderr, "Error: invalid data sample times.\n");
277 tacFree(&ttac); tacFree(&ttac); return(2);
278 }
279 /* Convert sample times into seconds */
280 if(tacXUnitConvert(&ttac, UNIT_SEC, &status)!=TPCERROR_OK ||
281 tacXUnitConvert(&btac, UNIT_SEC, &status)!=TPCERROR_OK)
282 {
283 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
284 tacFree(&ttac); tacFree(&ttac); return(2);
285 }
286 /* Convert BTAC concentrations into TTAC units */
287 if(tacYUnitConvert(&btac, ttac.cunit, &status)!=TPCERROR_OK) {
288 fprintf(stderr, "Error: check and set the data units.\n");
289 tacFree(&ttac); tacFree(&ttac); return(2);
290 }
291 /* Get x range */
292 double xmin, xmax;
293 if(tacXRange(&ttac, &xmin, &xmax)!=0) {
294 fprintf(stderr, "Error: invalid data sample times.\n");
295 tacFree(&ttac); tacFree(&btac); return(2);
296 }
297 if(verbose>1) {
298 printf("xmin := %g\n", xmin);
299 printf("xmax := %g\n", xmax);
300 printf("final_xunit := %s\n", unitName(ttac.tunit));
301 }
302
303
304 /* Set places for fitted TACs */
305 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
306 if(tacAllocateMore(&ttac, ttac.tacNr)!=TPCERROR_OK) {
307 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
308 tacFree(&ttac); tacFree(&ttac); return(2);
309 }
310
311 /* Check and set weights */
312 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
313 if(weights==0) {
314 if(!tacIsWeighted(&ttac)) {
316 for(int i=0; i<ttac.sampleNr; i++) ttac.w[i]=1.0;
317 }
318 } else if(weights==1) {
320 for(int i=0; i<ttac.sampleNr; i++) ttac.w[i]=1.0;
321 } else if(weights==2) {
322 if(tacWByFreq(&ttac, ISOTOPE_UNKNOWN, &status)!=TPCERROR_OK) {
323 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
324 tacFree(&ttac); tacFree(&btac); return(2);
325 }
326 }
327
328
329 /*
330 * Prepare PAR structure for printing and saving model parameters
331 */
332 if(verbose>1) printf("preparing space for parameters\n");
333 PAR par; parInit(&par);
334 if(parAllocateWithTAC(&par, &ttac, 6, &status)!=TPCERROR_OK) {
335 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
336 tacFree(&ttac); tacFree(&btac); parFree(&par); return(3);
337 }
338 iftFree(&par.h); // remove stupid header info
339 /* set time and program name */
340 {
341 char buf[256];
342 time_t t=time(NULL);
343 iftPut(&par.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
344 tpcProgramName(argv[0], 1, 1, buf, 256);
345 iftPut(&par.h, "program", buf, 0, NULL);
346 }
347 par.tacNr=ttac.tacNr; par.parNr=6;
349 for(int i=0; i<par.tacNr; i++) {
350 par.r[i].model=modelCodeIndex("radiowater-brain");
351 par.r[i].dataNr=tacWSampleNr(&ttac);
352 par.r[i].start=xmin;
353 par.r[i].end=xmax;
354 }
355 /* Set parameter names */
356 strcpy(par.n[0].name, "aGM"); par.n[0].unit=UNIT_UNITLESS;
357 strcpy(par.n[1].name, "fGM"); par.n[1].unit=UNIT_ML_PER_ML_MIN;
358 strcpy(par.n[2].name, "aWM"); par.n[2].unit=UNIT_UNITLESS;
359 strcpy(par.n[3].name, "fWM"); par.n[3].unit=UNIT_ML_PER_ML_MIN;
360 strcpy(par.n[4].name, "Va"); par.n[4].unit=UNIT_ML_PER_ML;
361 strcpy(par.n[5].name, "dT"); par.n[5].unit=UNIT_SEC;
362 /* set file names */
363 iftPut(&par.h, "inputfile", btacfile, 0, NULL);
364 iftPut(&par.h, "datafile", ttacfile, 0, NULL);
365 /* set fixed parameters */
366 iftPutDouble(&par.h, "pGM", fixed_pg, 0, NULL);
367 iftPutDouble(&par.h, "pWM", fixed_pw, 0, NULL);
368
369
370 /*
371 * Fit radiowater model with PVC for the brain TTACs
372 */
373 if(verbose==1) {printf("\nfitting...\n"); fflush(stdout);}
374 int failed=0;
375//#pragma omp parallel for
376 for(int ri=0; ri<ttac.tacNr; ri++) {
377 if(verbose>1) {printf("\nfitting %s\n", ttac.c[ri].name); fflush(stdout);}
378 /* Set data pointers for the fit */
379 FITDATA fitdata;
380 fitdata.ni=btac.sampleNr;
381 fitdata.xi=btac.x;
382 fitdata.yi=btac.c[0].y;
383 fitdata.nt=ttac.sampleNr;
384 if(ttac.isframe) {
385 fitdata.xt1=ttac.x1;
386 fitdata.xt2=ttac.x2;
387 fitdata.xt=NULL;
388 } else {
389 fitdata.xt=ttac.x;
390 fitdata.xt1=NULL;
391 fitdata.xt2=NULL;
392 }
393 fitdata.yt=ttac.c[ri].y;
394 fitdata.w=ttac.w;
395 fitdata.syt=ttac.c[ttac.tacNr+ri].y;
396 fitdata.pGM=fixed_pg;
397 fitdata.pWM=fixed_pw;
398 if(verbose>10) fitdata.verbose=verbose-10; else fitdata.verbose=0;
399 /* Set NLLS options */
400 NLOPT nlo; nloptInit(&nlo);
401 if(nloptAllocate(&nlo, 6)!=TPCERROR_OK) {
402 fprintf(stderr, "Error: cannot initiate NLLS.\n"); fflush(stderr); failed++;
403 nloptFree(&nlo); continue;
404 }
405 nlo._fun=func_wcbf; nlo.maxFunCalls=50000;
406 nlo.fundata=&fitdata;
407 nlo.totalNr=6;
408 /* Set initial values and limits */
409 // alphaGM
410 nlo.xlower[0]=0.00; nlo.xupper[0]=1.0; nlo.xfull[0]=0.5; nlo.xtol[0]=0.002;
411 // fGM
412 nlo.xlower[1]=0.40; nlo.xupper[1]=1.4; nlo.xfull[1]=0.8; nlo.xtol[1]=0.002;
413 // parameter[2] = alphaWM/(1-alphaGM-Va), i.e. alphaWM=parameter[2]*(1-alpgaGM-Va)
414 nlo.xlower[2]=0.00; nlo.xupper[2]=1.0; nlo.xfull[2]=0.6; nlo.xtol[2]=0.002;
415 // fWM
416 if(isnan(fixed_fw)) {
417 nlo.xlower[3]=0.0; nlo.xupper[3]=0.5; nlo.xfull[3]=0.2; nlo.xtol[3]=0.002;
418 } else {
419 nlo.xlower[3]=nlo.xupper[3]=nlo.xfull[3]=fixed_fw; nlo.xtol[3]=0.0;
420 }
421 // Va
422 if(isnan(fixed_va)) {
423 nlo.xlower[4]=0.0; nlo.xupper[4]=0.1; nlo.xfull[4]=0.02; nlo.xtol[4]=0.001;
424 } else {
425 nlo.xlower[4]=nlo.xupper[4]=nlo.xfull[4]=fixed_va; nlo.xtol[4]=0.0;
426 }
427 // Delay
428 if(isnan(fixed_dt)) {
429 nlo.xlower[5]=-1.0; nlo.xupper[5]=10.0; nlo.xfull[5]=5.0; nlo.xtol[5]=0.01;
430 } else {
431 nlo.xlower[5]=nlo.xupper[5]=nlo.xfull[5]=fixed_dt; nlo.xtol[5]=0.0;
432 }
433
434
435#if(0)
436 // call function for testing
437 fitdata.verbose=10;
438 double wss=func_wcbf(nlo.totalNr, nlo.xfull, &fitdata);
439 if(verbose>1) {
440 printf("\nTime\tTTAC\tsimTTAC\n");
441 for(unsigned int i=0; i<fitdata.nt; i++)
442 printf("%g\t%g\t%g\n", ttac.x[i], ttac.c[ri].y[i], ttac.c[ri+ttac.tacNr].y[i]);
443 printf("\n"); fflush(stdout);
444 }
445 if(verbose>1) {printf("\twss := %g\n", wss); fflush(stdout);}
446
447#else
448 /* Fit */
449 if(verbose>2) {
450 printf("initial guess\n");
451 nlo.funval=nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
452 nloptWrite(&nlo, stdout);
453 fflush(stdout);
454 }
455
456 //status.verbose=10;
457// if(nloptSimplexARRS(&nlo, 0, &status)!=TPCERROR_OK) {
458// if(nloptIATGO(&nlo, 1, 150, 0.10, &status)!=TPCERROR_OK) {
459 if(nloptSimplexMS(&nlo, 500, &status)!=TPCERROR_OK) {
460 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr); failed++;
461 nloptFree(&nlo); continue;
462 }
463 //status.verbose=1;
464 double wss=nlo._fun(nlo.totalNr, nlo.xfull, nlo.fundata);
465 if(verbose>6) {
466 printf("\nTime\tTTAC\tsimTTAC\n");
467 for(unsigned int i=0; i<fitdata.nt; i++)
468 printf("%g\t%g\t%g\n", ttac.x[i], ttac.c[ri].y[i], ttac.c[ri+ttac.tacNr].y[i]);
469 printf("\n"); fflush(stdout);
470 }
471 if(verbose>2) nloptWrite(&nlo, stdout);
472 if(verbose>2) printf(" wss := %g\n", wss);
473
474#endif
475
476
477 /* Copy parameters */
478 for(int i=0; i<par.parNr; i++) par.r[ri].p[i]=nlo.xfull[i];
479 par.r[ri].p[2]*=1.0-par.r[ri].p[0]-par.r[ri].p[4]; // alphaWM=fraction*(1-alphaGM-Va)
480 par.r[ri].wss=wss;
481
482 nloptFree(&nlo);
483 }
484 if(failed>0) {tacFree(&ttac); tacFree(&btac); parFree(&par); return(5);}
485
486
487 /* Print and save the parameters */
488 if(verbose>0) parWrite(&par, stdout, PAR_FORMAT_TSV_UK, 1, NULL);
489 if(parfile[0]) {
490 par.format=parFormatFromExtension(parfile);
491 if(verbose>2) printf("parameter file format := %s\n", parFormattxt(par.format));
493 /* Save file */
494 if(verbose>1) printf(" saving %s\n", parfile);
495 FILE *fp=fopen(parfile, "w");
496 if(fp==NULL) {
497 fprintf(stderr, "Error: cannot open file for writing.\n");
498 tacFree(&ttac); tacFree(&btac); parFree(&par); return(11);
499 }
500 int ret=parWrite(&par, fp, PAR_FORMAT_UNKNOWN, 1, &status);
501 fclose(fp);
502 if(ret!=TPCERROR_OK) {
503 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
504 tacFree(&ttac); tacFree(&btac); parFree(&par); return(12);
505 }
506 if(verbose>0) printf("parameters saved in %s\n", parfile);
507 }
508
509
510 /*
511 * Save and/or plot fitted TACs, if requested
512 */
513 if(svgfile[0] || fitfile[0]) {
514
515 TAC fit; tacInit(&fit);
516 (void)tacDuplicate(&ttac, &fit);
517 for(int r=0; r<ttac.tacNr; r++)
518 for(int i=0; i<ttac.sampleNr; i++)
519 fit.c[r].y[i]=ttac.c[r+ttac.tacNr].y[i];
520
521 /*
522 * SVG plot of fitted and original data
523 */
524 if(svgfile[0]) {
525 if(verbose>1) printf("plotting measured and fitted data\n");
526 if(tacPlotFitSVG(&ttac, &fit, "", nan(""), nan(""), nan(""), nan(""), svgfile, NULL)!=TPCERROR_OK)
527 {
528 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
529 tacFree(&ttac); tacFree(&btac); parFree(&par); tacFree(&fit);
530 return(21);
531 }
532 if(verbose>0) printf("Measured and fitted data plotted in %s\n", svgfile);
533 }
534
535 /*
536 * Save fitted TTACs
537 */
538 if(fitfile[0]) {
539 if(verbose>1) printf("writing %s\n", fitfile);
540 int ret=TPCERROR_OK;
541 FILE *fp; fp=fopen(fitfile, "w");
542 if(fp==NULL) {
543 fprintf(stderr, "Error: cannot open file for writing fitted TTACs.\n");
544 ret=TPCERROR_FAIL;
545 } else {
546 ret=tacWrite(&fit, fp, TAC_FORMAT_PMOD, 1, &status);
547 fclose(fp);
548 if(ret!=TPCERROR_OK) fprintf(stderr, "Error: %s\n", errorMsg(status.error));
549 }
550 if(ret!=TPCERROR_OK) {
551 tacFree(&ttac); tacFree(&btac); parFree(&par); tacFree(&fit);
552 return(22);
553 }
554 if(verbose>0) printf("fitted TACs saved in %s.\n", fitfile);
555 }
556
557 tacFree(&fit);
558 }
559
560
561 /*
562 * Compute and save fitted TTACs at BTAC sample times, if requested
563 */
564 if(simfile[0]) {
565 if(verbose>1) printf("calculating simulated TTACs\n");
566
567 /* Allocate memory for simulated TTACs */
568 TAC sim; tacInit(&sim);
569 if(tacDuplicate(&ttac, &sim) || tacAllocateMoreSamples(&sim, btac.sampleNr-ttac.sampleNr)) {
570 fprintf(stderr, "Error: cannot allocate space for simulated TTACs\n");
571 tacFree(&ttac); tacFree(&btac); parFree(&par); tacFree(&sim);
572 return(31);
573 }
574 sim.sampleNr=btac.sampleNr;
575 sim.isframe=btac.isframe;
576 (void)tacXCopy(&btac, &sim, 0, sim.sampleNr-1);
578
579 /* Set data pointers for the function data structure */
580 FITDATA fitdata;
581 fitdata.ni=btac.sampleNr;
582 fitdata.xi=btac.x;
583 fitdata.yi=btac.c[0].y;
584 fitdata.nt=btac.sampleNr;
585 if(btac.isframe) {
586 fitdata.xt1=btac.x1;
587 fitdata.xt2=btac.x2;
588 fitdata.xt=NULL;
589 } else {
590 fitdata.xt=btac.x;
591 fitdata.xt1=NULL;
592 fitdata.xt2=NULL;
593 }
594 fitdata.w=btac.w;
595 fitdata.pGM=fixed_pg;
596 fitdata.pWM=fixed_pw;
597 fitdata.verbose=0;
598
599 double pp[6];
600
601 /* Simulate one TAC at a time */
602 for(int ri=0; ri<sim.tacNr; ri++) {
603 fitdata.yt=fitdata.syt=sim.c[ri].y;
604 for(int j=0; j<6; j++) pp[j]=par.r[ri].p[j];
605 pp[2]=par.r[ri].p[2]/(1.0-par.r[ri].p[0]-par.r[ri].p[4]); // fraction = alphaWM/(1-alphaGM-Va)
606
607 func_wcbf(6, pp, &fitdata);
608 }
609
610 /* Save simulated TTACs */
611 if(verbose>1) printf("writing %s\n", simfile);
612 FILE *fp; fp=fopen(simfile, "w");
613 if(fp==NULL) {
614 fprintf(stderr, "Error: cannot open file for writing (%s)\n", simfile);
615 tacFree(&ttac); tacFree(&btac); parFree(&par); tacFree(&sim); return(32);
616 }
617 int ret=tacWrite(&sim, fp, TAC_FORMAT_PMOD, 1, &status);
618 fclose(fp); tacFree(&sim);
619 if(ret!=TPCERROR_OK) {
620 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
621 tacFree(&ttac); tacFree(&btac); parFree(&par); return(33);
622 }
623 if(verbose>=0) {printf("%s saved.\n", simfile); fflush(stdout);}
624 }
625
626
627 tacFree(&ttac); tacFree(&btac); parFree(&par);
628 return(0);
629}
630/*****************************************************************************/
631
632/*****************************************************************************
633 *
634 * Functions to be minimized
635 *
636 *****************************************************************************/
637double func_wcbf(int parNr, double *p, void *fdata)
638{
639 FITDATA *d=(FITDATA*)fdata;
640
641 if(d->verbose>0) {printf("%s() %d\n", __func__, d->verbose); fflush(stdout);}
642 if(parNr!=6 || p==NULL || fdata==NULL || d->ni<1 || d->nt<1) return(nan(""));
643 if(d->verbose>9) {
644 printf("p[]: %g", p[0]);
645 for(int i=1; i<parNr; i++) printf(" %g", p[i]);
646 printf("\n"); fflush(stdout);
647 }
648
649 /* Process parameters */
650 double aGM=p[0];
651 double fGM=p[1]/60.0;
652 double fWM=p[3]/60.0;
653 double Va=p[4];
654 double dT=p[5];
655 double tau=0.31*dT-0.30; if(!(tau>=0.0)) tau=0.0;
656 double aWM=p[2]*(1.0-aGM-Va); // p[2] = fraction of aWM from remaining vol
657 //printf("pGM=%g pWM=%g\n", d->pGM, d->pWM);
658
659
660 /* Make input TAC with delay and dispersion */
661 double x[d->ni], y[d->ni], sy[d->ni];
662 for(unsigned int i=0; i<d->ni; i++) x[i]=d->xi[i]+dT;
663 for(unsigned int i=0; i<d->ni; i++) y[i]=d->yi[i];
664 if(simDispersion(x, y, d->ni, tau, 0.0, sy)!=0) return(nan(""));
665
666 /* Simulate tissue and PET curves at input sample times */
667 double cgm[d->ni];
668 if(simC1_d(x, y, d->ni, fGM, fGM/d->pGM, cgm)!=0) return(nan(""));
669 double cwm[d->ni];
670 if(simC1_d(x, y, d->ni, fWM, fWM/d->pWM, cwm)!=0) return(nan(""));
671 for(unsigned int i=0; i<d->ni; i++)
672 sy[i] = Va*y[i] + aGM*cgm[i] + aWM*cwm[i];
673
674 /* Interpolate simulated tissue curve to the sample times of measured tissue */
675 if(d->xt1==NULL || d->xt2==NULL) {
676 if(liInterpolate(x, sy, d->ni, d->xt, d->syt, NULL, NULL, d->nt, 3, 1, 0))
677 return(nan(""));
678 } else {
679 if(liInterpolateForPET(x, sy, d->ni, d->xt1, d->xt2, d->syt, NULL, NULL, d->nt, 3, 1, 0))
680 return(nan(""));
681 }
682
683 /* Calculate the weighted SS */
684 if(d->verbose>2) {fprintf(stdout, "computing WSS...\n"); fflush(stdout);}
685 double wss=0.0;
686 for(unsigned i=0; i<d->nt; i++) {
687 double v=d->syt[i] - d->yt[i];
688 wss+=d->w[i]*v*v;
689 }
690
691 return(wss);
692}
693/*****************************************************************************/
694
695/*****************************************************************************/
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
int atofCheck(const char *s, double *v)
Definition decpoint.c:94
unsigned int drandSeed(short int seed)
Make and optionally set the seed for rand(), drand, drandRange, and drandGaussian().
Definition gaussdev.c:27
void iftFree(IFT *ift)
Definition ift.c:37
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
Definition ift.c:63
int iftPutDouble(IFT *ift, const char *key, const double value, char comment, TPCSTATUS *status)
Definition ift.c:128
int liInterpolate(double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear interpolation and/or integration with trapezoidal method.
int liInterpolateForPET(double *x, double *y, const int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear TAC interpolation and/or integration to PET frames.
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
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 simC1_d(double *t, double *ca, const int nr, const double k1, const double k2, double *ct)
Definition sim1cm.c:229
int simDispersion(double *x, double *y, const int n, const double tau1, const double tau2, double *tmp)
int nloptSimplexMS(NLOPT *nlo, unsigned int spNr, TPCSTATUS *status)
Definition simplex.c:624
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
char * errorMsg(tpcerror e)
Definition statusmsg.c:68
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
double(* _fun)(int, double *, void *)
Definition tpcnlopt.h:42
double funval
Definition tpcnlopt.h:50
unsigned int maxFunCalls
Definition tpcnlopt.h:46
double * xupper
Definition tpcnlopt.h:33
double * xlower
Definition tpcnlopt.h:31
void * fundata
Definition tpcnlopt.h:44
double * xfull
Definition tpcnlopt.h:29
double * 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 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 tacAllocateMoreSamples(TAC *tac, int addNr)
Allocate memory for more samples in TAC data.
Definition tac.c:435
int tacAllocateMore(TAC *tac, int tacNr)
Definition tac.c:178
int tacPlotFitSVG(TAC *tac1, TAC *tac2, const char *main_title, const double x1, const double x2, const double y1, const double y2, const char *fname, TPCSTATUS *status)
Definition tacfitplot.c:27
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int 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 tacYUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:72
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:23
int tacIsWeighted(TAC *tac)
Definition tacw.c:24
unsigned int tacWSampleNr(TAC *tac)
Definition tacw.c:219
int tacWByFreq(TAC *tac, isotope isot, TPCSTATUS *status)
Definition tacw.c:134
int tacXCopy(TAC *tac1, TAC *tac2, int i1, int i2)
Definition tacx.c:24
int tacSetXContiguous(TAC *d)
Set PET TAC frame times contiguous, without even tiny overlap or gaps in between.
Definition tacx.c:1166
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Definition tacx.c:124
Header file for libtpcbfm.
Header file for libtpccm.
Header file for library libtpcextensions.
weights
Is data weighted, or are weight factors available with data?
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ UNIT_ML_PER_ML
mL/mL
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ UNIT_UNITLESS
Unitless.
@ UNIT_SEC
seconds
@ TPCERROR_FAIL
General error.
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.
@ ISOTOPE_UNKNOWN
Unknown.
Definition tpcisotope.h:51
Header file for libtpcli.
Header file for libtpclinopt.
Header file for library libtpcnlopt.
Header file for libtpcpar.
@ PAR_FORMAT_FIT
Function fit format of Turku PET Centre.
Definition tpcpar.h:30
@ PAR_FORMAT_UNKNOWN
Unknown format.
Definition tpcpar.h:28
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Definition tpcpar.h:35
Header file for libtpcrand.
Header file for library libtpctac.
@ TAC_FORMAT_PMOD
PMOD TAC format.
Definition tpctac.h:33
Header file for libtpctacmod.