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