TPCCLIB
Loading...
Searching...
No Matches
fit_1tcm.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "tpcclibConfig.h"
10/*****************************************************************************/
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <math.h>
15/*****************************************************************************/
16#include "tpcextensions.h"
17#include "tpcift.h"
18#include "tpctac.h"
19#include "tpcpar.h"
20#include "tpcli.h"
21#include "tpccm.h"
22#include "tpctacmod.h"
23#include "tpclinopt.h"
24#include "tpcrand.h"
25#include "tpcnlopt.h"
26/*****************************************************************************/
27
28/*****************************************************************************/
29/* Local functions */
30double func_1tcm(int parNr, double *p, void*);
31/*****************************************************************************/
32typedef struct FITDATA {
34 unsigned int ni;
36 double *xi;
38 double *yi;
40 double *yb;
41
43 unsigned int nt;
45 double *xt1;
47 double *xt2;
49 double *xt;
51 double *yt;
53 double *w;
55 double *syt;
56
58 int verbose;
59} FITDATA;
60/*****************************************************************************/
61
62/*****************************************************************************/
63static char *info[] = {
64 "Non-linear fitting of 1TCM to regional TTACs using PTAC as input function",
65 "and BTAC for vascular volume correction. Delay time between TTACs and",
66 "PTAC/BTAC is fitted by default. Regional radioactivity concentration is",
67 "modelled as Cpet(t) = Vb*Cb(t) + Ct(t),",
68 "and thus the estimated parameters are reported per total ROI volume.",
69 " ",
70 "Usage: @P [Options] ptacfile btacfile ttacfile [parfile]",
71 " ",
72 "Options:",
73 " -end=<value>",
74 " Tissue data length, used in the fitting, is restricted to",
75 " given time (min).",
76 " -Vb=<value>",
77 " Blood volume is constrained to given value (mL/mL).",
78 " If Vb is set to zero, then btacfile is not read, but a place filler",
79 " must nonetheless be given.",
80 " -Delay=<value>",
81 " Delay time is constrained to given value (sec).",
82 " -wf | -wfd | -w1",
83 " With -wf Weights are based on frame length or sampling interval;",
84 " with -wfd the late frames are given less weight by using formula",
85 " weight=(frame duration)*exp(-t*ln(2)/halflife) (Thiele et al, 2008);",
86 " with -w1 all weights are set to 1.0 (no weighting);",
87 " by default, weights in TTAC file are used, if available.",
88 " -i=<Isotope code>",
89 " Isotope, for example C-11, in case it is not found inside TTAC, but",
90 " is needed with option -wfd.",
91 " -svg=<Filename>",
92 " Fitted and measured TACs are plotted in specified SVG file.",
93 " -sim=<Filename>",
94 " Fitted TTACs at BTAC sample times are saved in specified TAC file.",
95 " -stdoptions", // List standard options like --help, -v, etc
96 " ",
97 "If time units are not specified in files, minutes are assumed.",
98 " ",
99 "See also: fitk2, fit_h2o, bfmh2o, fit_wrlv",
100 " ",
101 "Keywords: TAC, modelling, compartmental model",
102 0};
103/*****************************************************************************/
104
105/*****************************************************************************/
106/* Turn on the globbing of the command line, since it is disabled by default in
107 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
108 In Unix&Linux wildcard command line processing is enabled by default. */
109/*
110#undef _CRT_glob
111#define _CRT_glob -1
112*/
113int _dowildcard = -1;
114/*****************************************************************************/
115
116/*****************************************************************************/
117
130int tacReadModelingData2(
134 const char *tissuefile,
137 const char *inputfile1,
140 const char *inputfile2,
143 const char *inputfile3,
147 double *fitdur,
150 int cutInput,
153 int *fitSampleNr,
157 TAC *tis,
160 TAC *inp,
162 TPCSTATUS *status
163) {
164 int verbose=0; if(status!=NULL) verbose=status->verbose;
165 if(verbose>0) printf("%s()\n", __func__);
166 if(tis==NULL || inp==NULL) {
167 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
168 return TPCERROR_FAIL;
169 }
170 if(tissuefile==NULL || inputfile1==NULL || strnlen(inputfile1, 1)<1) {
171 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
172 return TPCERROR_NO_DATA;
173 }
174
175 /* Check the function input */
176 int input_nr=1;
177 if(inputfile2!=NULL && strnlen(inputfile2, 1)>0) input_nr++;
178 if(inputfile3!=NULL && strnlen(inputfile3, 1)>0) {
179 if(input_nr<2) {
180 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
181 return TPCERROR_NO_DATA;
182 }
183 input_nr++;
184 }
185 if(verbose>2) printf("input_nr := %d\n", input_nr);
186
187 /* Delete any previous data */
188 tacFree(tis); tacFree(inp);
189 if(fitSampleNr!=NULL) *fitSampleNr=0;
190
191 int ret;
192 /*
193 * Read tissue data
194 */
195 if(verbose>1) printf("reading tissue data in %s\n", tissuefile);
196 ret=tacRead(tis, tissuefile, status);
197 if(ret!=TPCERROR_OK) return(ret);
198
199 /* Do not check frame number; static scan is fine here */
200
201 /* Check for NaN's */
202 if(tacNaNs(tis)>0) {
203 tacFree(tis);
204 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_MISSING_DATA);
206 }
207
208 /* Sort the tissue data by increasing sample times */
209 ret=tacSortByTime(tis, status);
210 if(ret!=TPCERROR_OK) {
211 tacFree(tis);
212 statusSet(status, __func__, __FILE__, __LINE__, ret);
213 return(ret);
214 }
215
216 /* Make sure that there is no overlap in sample frame times; samples must
217 be sorted before this */
218 ret=tacCorrectFrameOverlap(tis, status);
219 if(ret!=TPCERROR_OK) {tacFree(tis); return ret;}
220
221 /*
222 * Read first input data
223 */
224 if(verbose>1) printf("reading input data 1 in %s\n", inputfile1);
225 ret=tacRead(inp, inputfile1, status);
226 if(ret!=TPCERROR_OK) {tacFree(tis); return ret;}
227 /* Check and correct the sample time unit */
228 if(tis->tunit==UNIT_UNKNOWN) tis->tunit=inp->tunit;
229 else if(inp->tunit==UNIT_UNKNOWN) inp->tunit=tis->tunit;
230 if(inp->tunit==UNIT_UNKNOWN && verbose>0) {
231 fprintf(stderr, "Warning: input sample time units not known.\n");}
232 if(tis->tunit!=inp->tunit && tacXUnitConvert(inp, tis->tunit, status)) {
233 tacFree(tis); tacFree(inp); return ret;}
234 /* Check TAC nr */
235 if(inp->tacNr>1) {
236 if(verbose>0) fprintf(stderr, "Warning: using only first TAC in %s\n", inputfile1);
237 inp->tacNr=1;
238 }
239 /* Check sample nr */
240 if(inp->sampleNr<4) {
241 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_TOO_FEW);
242 tacFree(tis); tacFree(inp); return TPCERROR_TOO_FEW;
243 }
244 /* Sort the data by increasing sample times */
245 tacSortByTime(inp, NULL);
246 /* If inp contains isotope and tis does not, then copy it */
248 int isotope=tacGetIsotope(inp);
250 }
251
252 /*
253 * Read following input files, if available
254 */
255 char *fname;
256 TAC tmptac; tacInit(&tmptac);
257 for(int ii=2; ii<=input_nr; ii++) {
258 if(ii==2) fname=(char*)inputfile2; else fname=(char*)inputfile3;
259 if(verbose>1) printf("reading input data %d in %s\n", ii, fname);
260 ret=tacRead(&tmptac, fname, status);
261 if(ret!=TPCERROR_OK) {tacFree(tis); tacFree(inp); tacFree(&tmptac); return ret;}
262 /* Check TAC nr */
263 if(tmptac.tacNr>1) {
264 if(verbose>0) fprintf(stderr, "Warning: using only first TAC in %s\n", fname);
265 tmptac.tacNr=1;
266 }
267 /* Check sample nr */
268 if(tmptac.sampleNr<4) {
269 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_TOO_FEW);
270 tacFree(tis); tacFree(inp); tacFree(&tmptac); return TPCERROR_TOO_FEW;
271 }
272 /* Sort the data by increasing sample times */
273 tacSortByTime(&tmptac, NULL);
274
275 /* Check and correct the sample time unit */
276 if(tis->tunit==UNIT_UNKNOWN) tis->tunit=tmptac.tunit;
277 else if(tmptac.tunit==UNIT_UNKNOWN) tmptac.tunit=tis->tunit;
278 if(inp->tunit!=tmptac.tunit && tacXUnitConvert(&tmptac, inp->tunit, status)) {
279 tacFree(tis); tacFree(inp); tacFree(&tmptac); return ret;
280 }
281
282 /* Check and correct the sample concentration unit */
283 if(inp->cunit==UNIT_UNKNOWN) inp->cunit=tmptac.cunit;
284 else if(tmptac.cunit==UNIT_UNKNOWN) tmptac.cunit=inp->cunit;
285 if(inp->cunit!=tmptac.cunit && tacYUnitConvert(&tmptac, inp->cunit, status)) {
286 tacFree(tis); tacFree(inp); tacFree(&tmptac); return ret;
287 }
288
289 /* Copy to input data */
290 if(tacInterpolateInto(&tmptac, inp, NULL, NULL, status)!=TPCERROR_OK) {
291 tacFree(tis); tacFree(inp); tacFree(&tmptac); return ret;
292 }
293
294 tacFree(&tmptac);
295 } // next input file
296
297 /* Set time unit to min */
298 ret=tacXUnitConvert(tis, UNIT_MIN, status);
299 if(ret && verbose>0) {
300 fprintf(stderr, "Warning: check that regional data times are in minutes.\n");
301 }
302 ret=tacXUnitConvert(inp, UNIT_MIN, status);
303 if(ret && verbose>0) {
304 fprintf(stderr, "Warning: check that input data times are in minutes.\n");
305 }
306 /* Check that input and tissue time ranges are about the same */
307 double iend, tend;
308 {
309 ret=tacXRange(inp, NULL, &iend); if(ret==0) ret=tacXRange(tis, NULL, &tend);
310 if(ret || iend<=0.0 || tend<=0.0) {
311 tacFree(tis); tacFree(inp);
312 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
314 }
315 if(tend>10.0*iend || tend<0.10*iend) {
316 if(verbose>0) fprintf(stderr, "Warning: check the sample time units.\n");
317 }
318 }
319 ret=tacYUnitConvert(inp, tis->cunit, status);
320 if(ret && verbose>0) {
321 fprintf(stderr, "Warning: check the calibration units.\n");
322 }
323
324 /*
325 * Check and set fit time length
326 */
327 if(verbose>1) printf("checking and setting fit time length\n");
328 /* Set fit duration */
329 double starttime=0, endtime=*fitdur;
330 int fnr=tacFittime(tis, &starttime, &endtime, NULL, NULL, status);
331 if(verbose>3) {
332 fprintf(stdout, "tis.sampleNr := %d\n", tis->sampleNr);
333 fprintf(stdout, "starttime := %g\n", starttime);
334 fprintf(stdout, "endtime := %g\n", endtime);
335 //fprintf(stdout, "first := %d\n", first);
336 //fprintf(stdout, "last := %d\n", last);
337 fprintf(stdout, "fitSampleNr := %d\n", fnr);
338 }
339 *fitdur=endtime;
340 if(fitSampleNr!=NULL) *fitSampleNr=fnr;
341
342 /* Check that input data does not end much before fitdur */
343 if(*fitdur>1.2*iend) {
344 tacFree(tis); tacFree(inp);
345 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_TOO_FEW);
346 return TPCERROR_TOO_FEW;
347 }
348
349 /* Cut off too many input samples to make calculation faster */
350 if(cutInput && iend>*fitdur) {
351 if(verbose>1) printf("cut off too many input samples\n");
352 int i; double f;
353 for(i=0; i<inp->sampleNr; i++) {
354 if(inp->isframe) f=0.5*(inp->x1[i]+inp->x2[i]); else f=inp->x[i];
355 if(f>(*fitdur)) break;
356 }
357 if(i<inp->sampleNr) i++;
358 inp->sampleNr=i;
359 if(inp->sampleNr<4) {
360 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_TOO_FEW);
361 tacFree(tis); tacFree(inp); return TPCERROR_TOO_FEW;
362 }
363 }
364 if(verbose>2) fprintf(stdout, "inp.sampleNr := %d\n", inp->sampleNr);
365
366 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
367 return(TPCERROR_OK);
368}
369
370
371/*****************************************************************************/
372
373/*****************************************************************************/
379int nnlsRTCM(
381 TAC *ttac,
387 TAC *ptac,
389 const int tcn,
391 const int vbc,
394 PAR *par,
396 TPCSTATUS *status
397) {
398 int verbose=0; if(status!=NULL) verbose=status->verbose;
399 if(verbose>0) printf("%s(ttac, ptac, %d, %d, par)\n", __func__, tcn, vbc);
400 if(ttac==NULL || ptac==NULL || par==NULL || tcn<1 || tcn>3) {
401 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
402 return TPCERROR_FAIL;
403 }
404 if(ttac->tacNr<1 || ttac->sampleNr<3 || ptac->tacNr<1 || ptac->sampleNr<3) {
405 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
406 return TPCERROR_NO_DATA;
407 }
408
409
410
411
412
413 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
414 return(TPCERROR_OK);
415}
416/*****************************************************************************/
417
418/*****************************************************************************/
422int main(int argc, char **argv)
423{
424 int ai, help=0, version=0, verbose=1;
425 char ptacfile[FILENAME_MAX], btacfile[FILENAME_MAX], ttacfile[FILENAME_MAX],
426 parfile[FILENAME_MAX], svgfile[FILENAME_MAX], simfile[FILENAME_MAX];
427 int weightMethod=WEIGHTING_UNKNOWN;
428 double fixed_dt=nan("");
429 double fixed_vb=nan("");
430 double tstop=nan(""); // fit end time
432
433 drandSeed(1);
434
435 /*
436 * Get arguments
437 */
438 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
439 ptacfile[0]=btacfile[0]=ttacfile[0]=parfile[0]=svgfile[0]=simfile[0]=(char)0;
440 /* Options */
441 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
442 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
443 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
444 if(strcasecmp(cptr, "W1")==0) {
445 weightMethod=WEIGHTING_OFF; continue;
446 } else if(strcasecmp(cptr, "WF")==0) {
447 weightMethod=WEIGHTING_ON_F; continue;
448 } else if(strcasecmp(cptr, "WFD")==0) {
449 weightMethod=WEIGHTING_ON_FD; continue;
450 } else if(strncasecmp(cptr, "I=", 2)==0) {
451 if((isot=isotopeIdentify(cptr+2))==ISOTOPE_UNKNOWN) {
452 fprintf(stderr, "Error: invalid isotope '%s'.\n", cptr+2); return(1);}
453 continue;
454 } else if(strncasecmp(cptr, "DELAY=", 6)==0 && strlen(cptr)>6) {
455 if(!atofCheck(cptr+6, &fixed_dt) && fixed_dt>=0.0) continue;
456 } else if(strncasecmp(cptr, "DT=", 3)==0 && strlen(cptr)>3) {
457 if(!atofCheck(cptr+3, &fixed_dt) && fixed_dt>=0.0) continue;
458 } else if(strncasecmp(cptr, "END=", 4)==0 && strlen(cptr)>4) {
459 if(!atofCheck(cptr+4, &tstop) && tstop>0.0) continue;
460 } else if(strncasecmp(cptr, "STOP=", 5)==0 && strlen(cptr)>5) {
461 if(!atofCheck(cptr+5, &tstop) && tstop>0.0) continue;
462 } else if(strncasecmp(cptr, "VB=", 3)==0 && strlen(cptr)>3) {
463 if(!atofCheck(cptr+3, &fixed_vb) && fixed_vb>=0.0 && fixed_vb<1.0) continue;
464 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
465 strlcpy(svgfile, cptr+4, FILENAME_MAX); continue;
466 } else if(strncasecmp(cptr, "SIM=", 4)==0 && strlen(cptr)>4) {
467 strlcpy(simfile, cptr+4, FILENAME_MAX); continue;
468 }
469 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
470 return(1);
471 } else break;
472
473 TPCSTATUS status; statusInit(&status);
474 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
475 status.verbose=verbose-3;
476
477 /* Print help or version? */
478 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
479 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
480 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
481
482 /* Process other arguments, starting from the first non-option */
483 if(ai<argc) strlcpy(ptacfile, argv[ai++], FILENAME_MAX);
484 if(ai<argc) strlcpy(btacfile, argv[ai++], FILENAME_MAX);
485 if(ai<argc) strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
486 if(ai<argc) strlcpy(parfile, argv[ai++], FILENAME_MAX);
487 if(ai<argc) {
488 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
489 return(1);
490 }
491 /* Did we get all the information that we need? */
492 if(!ttacfile[0]) { // note that parameter file is optional
493 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
494 return(1);
495 }
496 /* If Vb is set to zero, then btacfile is not needed */
497 if(fixed_vb==0.0) btacfile[0]=(char)0;
498
499 /* In verbose mode print arguments and options */
500 if(verbose>1) {
501 printf("ptacfile := %s\n", ptacfile);
502 printf("btacfile := %s\n", btacfile);
503 printf("ttacfile := %s\n", ttacfile);
504 if(parfile[0]) printf("parfile := %s\n", parfile);
505 if(svgfile[0]) printf("svgfile := %s\n", svgfile);
506 if(simfile[0]) printf("simfile := %s\n", simfile);
507 printf("weightMethod := %d\n", weightMethod);
508 if(!isnan(tstop)) printf("tstop := %g\n", tstop);
509 if(!isnan(fixed_dt)) printf("fixed_dt := %g\n", fixed_dt);
510 if(!isnan(fixed_vb)) printf("fixed_vb := %g\n", fixed_vb);
511 fflush(stdout);
512 }
513
514
515 /*
516 * Read tissue and input data
517 */
518 if(verbose>0) {printf("reading tissue and input data\n"); fflush(stdout);}
519 TAC ttac, input; tacInit(&ttac); tacInit(&input);
520 int fitSampleNr=0;
521 double fitdur=1.0E+10; if(tstop>0.01) fitdur=tstop;
522
523 if(tacReadModelingData2(ttacfile, ptacfile, btacfile, NULL, &fitdur, 0,
524 &fitSampleNr, &ttac, &input, &status)!=TPCERROR_OK) {
525 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
526 tacFree(&ttac); tacFree(&input); return(2);
527 }
528 if(isot!=ISOTOPE_UNKNOWN) tacSetIsotope(&ttac, isot);
529 if(verbose>2) {
530 printf("fileformat := %s\n", tacFormattxt(ttac.format));
531 printf("tacNr := %d\n", ttac.tacNr);
532 printf("tac.sampleNr := %d\n", ttac.sampleNr);
533 printf("input.sampleNr := %d\n", input.sampleNr);
534 printf("fitSampleNr := %d\n", fitSampleNr);
535 printf("xunit := %s\n", unitName(ttac.tunit));
536 printf("yunit := %s\n", unitName(ttac.cunit));
537 printf("fitdur := %g s\n", fitdur);
538 printf("isotope := %s\n", isotopeName(tacGetIsotope(&ttac)));
539 fflush(stdout);
540 }
541
542
543 /* Check and set weights */
544 if(verbose>0) {printf("setting weights\n"); fflush(stdout);}
545 if(tacSetWeights(&ttac, weightMethod, fitSampleNr, &status)!=TPCERROR_OK) {
546 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
547 tacFree(&ttac); tacFree(&input); return(3);
548 }
549 /* Number of samples with positive weight is needed to calculate AIC */
550 unsigned int wsampleNr=tacWSampleNr(&ttac);
551 if(verbose>2) printf("wsampleNr := %u\n", wsampleNr);
552 if(wsampleNr<5) {
553 fprintf(stderr, "Error: too few samples for fitting.\n");
554 tacFree(&ttac); tacFree(&input); return(2);
555 }
556
557 /* Get x range, weights considered */
558 double xmin, xmax;
559 if(tacSampleXRange(&ttac, &xmin, &xmax)!=0) {
560 fprintf(stderr, "Error: invalid data sample times.\n");
561 tacFree(&ttac); tacFree(&input); return(2);
562 }
563 if(verbose>1) {
564 printf("xmin := %g\n", xmin);
565 printf("xmax := %g\n", xmax);
566 }
567
568
569 /*
570 * Prepare PAR structure for printing and saving model parameters
571 */
572 if(verbose>1) {printf("preparing space for parameters\n"); fflush(stdout);}
573 PAR par; parInit(&par);
574 if(parAllocateWithTAC(&par, &ttac, 5, &status)!=TPCERROR_OK) {
575 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
576 tacFree(&ttac); tacFree(&input); parFree(&par); return(3);
577 }
578 iftFree(&par.h); // remove stupid header info
579 /* set time and program name */
580 {
581 char buf[256];
582 time_t t=time(NULL);
583 iftPut(&par.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
584 tpcProgramName(argv[0], 1, 1, buf, 256);
585 iftPut(&par.h, "program", buf, 0, NULL);
586 }
587 par.tacNr=ttac.tacNr; par.parNr=5;
589 for(int i=0; i<par.tacNr; i++) {
590 par.r[i].model=modelCodeIndex("1TCM");
591 par.r[i].dataNr=tacWSampleNr(&ttac);
592 par.r[i].start=xmin;
593 par.r[i].end=xmax;
594 }
595 /* Set parameter names */
596 strcpy(par.n[0].name, "K1"); par.n[0].unit=UNIT_ML_PER_ML_MIN;
597 strcpy(par.n[1].name, "k2"); par.n[1].unit=UNIT_PER_MIN;
598 strcpy(par.n[2].name, "Vb"); par.n[2].unit=UNIT_ML_PER_ML;
599 strcpy(par.n[3].name, "dT"); par.n[3].unit=UNIT_SEC;
600 strcpy(par.n[4].name, "K1/k2"); par.n[4].unit=UNIT_ML_PER_ML;
601 /* set file names */
602 iftPut(&par.h, "datafile", ttacfile, 0, NULL);
603 iftPut(&par.h, "plasma", ptacfile, 0, NULL);
604 iftPut(&par.h, "blood", btacfile, 0, NULL);
605
606
607 /*
608 * Delay correction, if fixed delay time was given
609 */
610 if(fixed_dt<0.0 || fixed_dt>0.0) {
611 if(verbose>1) {printf("correcting data for user-defined delay time\n"); fflush(stdout);}
612 if(tacDelay(&input, -fixed_dt/60.0, -1, &status) != TPCERROR_OK) {
613 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
614 tacFree(&ttac); tacFree(&input); parFree(&par); return(5);
615 }
616 if(verbose>1) {printf(" input data moved %g s\n", -fixed_dt); fflush(stdout);}
617 }
618
619
620 /*
621 * Vascular volume correction, if fixed Vb was given
622 */
623 if(fixed_vb>0.0) {
624 if(verbose>1) {printf("correcting data for user-defined Vb\n"); fflush(stdout);}
625 /* Separate BTAC */
626 TAC btac; tacInit(&btac);
627 int ret=tacExtract(&input, &btac, 1);
628 if(ret!=TPCERROR_OK) {
629 fprintf(stderr, "Error: %s\n", errorMsg(ret));
630 tacFree(&ttac); tacFree(&input); parFree(&par); tacFree(&btac); return(6);
631 }
632 /* Interpolate BTAC to TTAC sample times */
633 TAC bitac; tacInit(&bitac);
634 ret=tacInterpolate(&btac, &ttac, &bitac, NULL, NULL, &status);
635 tacFree(&btac);
636 if(ret!=TPCERROR_OK) {
637 fprintf(stderr, "Error: %s.\n", errorMsg(status.error));
638 tacFree(&ttac); tacFree(&input); parFree(&par); tacFree(&bitac); return(6);
639 }
640 /* Vb correction */
641 ret=tacVb(&ttac, -1, &bitac, fixed_vb, 0, 1, &status);
642 tacFree(&bitac);
643 if(ret!=TPCERROR_OK) {
644 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
645 tacFree(&ttac); tacFree(&input); parFree(&par); return(6);
646 }
647 if(verbose>1) {printf(" corrected for Vb %g\n", fixed_vb); fflush(stdout);}
648 tacFree(&btac);
649 }
650
651
652 /*
653 * Get good initial guess by calculating multi-linear solution
654 */
655 {
656 if(verbose>2) {printf("multi-linear solution to get good initial guess\n"); fflush(stdout);}
657 PAR mlpar; parInit(&mlpar);
658 int ret;
659 if(fixed_vb) ret=nnlsRTCM(&ttac, &input, 1, 0, &mlpar, &status);
660 else ret=nnlsRTCM(&ttac, &input, 1, 1, &mlpar, &status);
661 if(ret!=TPCERROR_OK) {
662 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
663 tacFree(&ttac); tacFree(&input); parFree(&par); parFree(&mlpar); return(7);
664 }
665
666
667 parFree(&mlpar);
668 }
669
670
671 /*
672 * Fit model to the TTACs
673 */
674 if(verbose==1) {printf("\n fitting...\n"); fflush(stdout);}
675 for(int ri=0; ri<ttac.tacNr; ri++) {
676 if(verbose>1) {printf("\n fitting %s\n", ttac.c[ri].name); fflush(stdout);}
677
678 // to be written
679
680 } // next TTAC
681
682
683
684
685 tacFree(&ttac); tacFree(&input); parFree(&par);
686 return(0);
687}
688/*****************************************************************************/
689
690/*****************************************************************************
691 *
692 * Functions to be minimized
693 *
694 *****************************************************************************/
695double func_1tcm(int parNr, double *p, void *fdata)
696{
697 FITDATA *d=(FITDATA*)fdata;
698
699 if(d->verbose>0) {printf("%s()\n", __func__); fflush(stdout);}
700 if(parNr!=5 || p==NULL || fdata==NULL || d->ni<1 || d->nt<1) return(nan(""));
701 if(d->verbose>9) {
702 printf("p[]: %g", p[0]);
703 for(int i=1; i<parNr; i++) printf(" %g", p[i]);
704 printf("\n"); fflush(stdout);
705 }
706
707 /* Process parameters */
708 double tau=p[0]; if(tau<0.0) tau=0.0;
709 double deltaT=p[1];
710 double Vb=p[2]; if(Vb<0.0) Vb=0.0;
711 double K1=p[3]/60.0; if(K1<0.0) K1=0.0;
712 double k2=p[4]/60.0; if(k2<0.0) k2=0.0;
713
714 /* Make input TAC with delay and dispersion */
715 double x[d->ni], y[d->ni], sy[d->ni];
716 for(unsigned int i=0; i<d->ni; i++) x[i]=d->xi[i]+deltaT;
717 for(unsigned int i=0; i<d->ni; i++) y[i]=d->yi[i];
718 if(simDispersion(x, y, d->ni, tau, 0.0, sy)!=0) return(nan(""));
719
720 /* Simulate tissue curve at input sample times */
721 if(simC1(x, y, d->ni, K1, k2, sy)!=0) return(nan(""));
722 for(unsigned int i=0; i<d->ni; i++) sy[i]+=Vb*y[i];
723
724 /* Interpolate simulated tissue curve to the sample times of measured tissue */
725 if(d->xt1==NULL || d->xt2==NULL) {
726 if(liInterpolate(x, sy, d->ni, d->xt, d->syt, NULL, NULL, d->nt, 3, 1, 0))
727 return(nan(""));
728 } else {
729 if(liInterpolateForPET(x, sy, d->ni, d->xt1, d->xt2, d->syt, NULL, NULL, d->nt, 3, 1, 0))
730 return(nan(""));
731 }
732
733 /* Calculate the weighted SS */
734 if(d->verbose>2) {fprintf(stdout, "computing WSS...\n"); fflush(stdout);}
735 double wss=0.0;
736 for(unsigned i=0; i<d->nt; i++) {
737 double v=d->syt[i] - d->yt[i];
738 wss+=d->w[i]*v*v;
739 }
740
741 return(wss);
742}
743/*****************************************************************************/
744
745/*****************************************************************************/
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
int tacDelay(TAC *tac, double dt, int ti, TPCSTATUS *status)
Move TAC y values (concentrations) in time, keeping sample times (x values) intact.
Definition delay.c:29
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 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.
char * isotopeName(int isotope_code)
Definition isotope.c:101
int isotopeIdentify(const char *isotope)
Definition isotope.c:145
int tacVb(TAC *ttac, const int i, TAC *btac, double Vb, const int simVb, const int petVolume, TPCSTATUS *status)
Correct TTACs for vascular blood, or simulate its effect.
Definition lisim.c:138
int tacInterpolateInto(TAC *inp, TAC *tac, TAC *itac, TAC *iitac, TPCSTATUS *status)
Add TACs from one TAC structure into another TAC structure, interpolating the input TACs and allocati...
Definition litac.c:330
int tacInterpolate(TAC *inp, TAC *xinp, TAC *tac, TAC *itac, TAC *iitac, TPCSTATUS *status)
Interpolate and/or integrate TACs from one TAC structure into a new TAC structure,...
Definition litac.c:141
unsigned int modelCodeIndex(const char *s)
Definition modell.c:237
void parFree(PAR *par)
Definition par.c:75
void parInit(PAR *par)
Definition par.c:25
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(double *t, double *ca, const int nr, const double k1, const double k2, double *ct)
Definition sim1cm.c:93
int simDispersion(double *x, double *y, const int n, const double tau1, const double tau2, double *tmp)
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 strnlen(const char *s, size_t n)
Definition stringext.c:566
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:635
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
int dataNr
Definition tpcpar.h:62
unsigned int model
Definition tpcpar.h:48
double start
Definition tpcpar.h:52
double end
Definition tpcpar.h:54
char name[MAX_TACNAME_LEN+1]
Definition tpctac.h:81
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
int isframe
Definition tpctac.h:95
TACC * c
Definition tpctac.h:117
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.
int tacExtract(TAC *d1, TAC *d2, const int i)
Extract the specified TAC from existing TAC structure into a new TAC.
Definition tac.c:396
void tacFree(TAC *tac)
Definition tac.c:106
void tacInit(TAC *tac)
Definition tac.c:24
int tacGetIsotope(TAC *tac)
Definition tacdc.c:25
void tacSetIsotope(TAC *tac, int isotope)
Definition tacdc.c:41
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacFittime(TAC *d, double *startTime, double *endTime, int *first, int *last, TPCSTATUS *status)
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 tacSetWeights(TAC *tac, weights weightMethod, int weightNr, TPCSTATUS *status)
Definition tacw.c:462
unsigned int tacWSampleNr(TAC *tac)
Definition tacw.c:219
int tacSampleXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Definition tacx.c:162
int tacCorrectFrameOverlap(TAC *d, TPCSTATUS *status)
Correct PET frame start and end times if frames are slightly overlapping or have small gaps in betwee...
Definition tacx.c:65
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 libtpccm.
Header file for library libtpcextensions.
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ WEIGHTING_ON_FD
Weights based on decay and sample frequency or frame length (Thiele et al, 2008).
@ WEIGHTING_UNKNOWN
Not known; usually assumed that not weighted.
@ WEIGHTING_ON_F
Weights based on sample frequency or frame length.
@ UNIT_MIN
minutes
@ UNIT_ML_PER_ML
mL/mL
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ UNIT_UNKNOWN
Unknown unit.
@ UNIT_SEC
seconds
@ UNIT_PER_MIN
1/min
@ TPCERROR_INVALID_XRANGE
Invalid sample time range.
@ TPCERROR_FAIL
General error.
@ TPCERROR_OK
No error.
@ TPCERROR_NO_DATA
File contains no data.
@ TPCERROR_TOO_FEW
File contains too few samples.
@ TPCERROR_MISSING_DATA
File contains missing values.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.
isotope
Definition tpcisotope.h:50
@ 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_TSV_UK
UK TSV (point as decimal separator).
Definition tpcpar.h:35
Header file for libtpcrand.
Header file for library libtpctac.
Header file for libtpctacmod.