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