11#include "tpcclibConfig.h"
28static char *info[] = {
29 "Fitting of full or reduced compartmental model to plasma and tissue",
30 "time-activity curves (PTAC and TTAC) to estimate the model parameters.",
32 " ____ ____ ____ ____ ",
33 " | Cp |--K1->| C1 |--k3->| C2 |--k5->| C3 | compartments in series (s)",
34 " |____|<-k2--|____|<-k4--|____|<-k6--|____| ",
37 " ____ | |--k3->| C2 | compartments in parallel (p)",
38 " | |--K1->| |<-k4--|____| ",
39 " | Cp | | C1 | ____ ",
40 " |____|<-k2--| |--k5->| C3 | ",
41 " |____|<-k6--|____| ",
43 "Compartmental models are transformed into general linear least squares",
44 "functions (1, 2, 3, 4), which are solved using Lawson-Hanson linear",
45 "least-squares algorithms (5). Note that rate constants and macroparameters",
46 "are represented per volume (as measured by PET) including vascular volume.",
48 "Usage: @P [options] PTAC TTAC fittime results",
51 " -model=<k1 | k2 | k3 | k4 | k5s | k6s | k5p | k6p>",
52 " representing the following compartmental model settings:",
53 " k1 (for assuming k2=k3=k4=k5=k6=0)",
54 " k2 (for assuming k3=k4=k5=k6=0)",
55 " k3 (for assuming k4=k5=k6=0)",
56 " k4 (for assuming k5=k6=0); default",
57 " k5s (for assuming k6=0 and compartments in series)",
58 " k6s (compartments in series)",
59 " k5p (for assuming k6=0 and compartments in parallel)",
62 " -Vp=<ignored|fitted>",
63 " Vascular volume is ignored (default) or fitted; note that PTAC is",
64 " assumed to represent vascular blood curve.",
66 " Sample weights are set to 1 (-w1) or to frame lengths (-wf);",
67 " by default weights in TTAC file are used, if available.",
69 " Use frame mid times even when start and end times are available.",
71 " Fitted and measured TACs are plotted in specified SVG file.",
73 " Fitted regional TTACs are written in specified file.",
75 " Parameters of linear model are saved in specified file.",
79 "1. Blomqvist G. On the construction of functional maps in positron emission",
80 " tomography. J Cereb Blood Flow Metab 1984;4:629-632.",
81 "2. Gjedde A, Wong DF. Modeling neuroreceptor binding of radioligands",
82 " in vivo. In: Quantitative imaging: neuroreceptors, neurotransmitters,",
83 " and enzymes. (Eds. Frost JJ, Wagner HM Jr). Raven Press, 1990, 51-79.",
84 "3. Oikonen V. Multilinear solution for 4-compartment model:",
85 " I. Tissue compartments in series.",
86 " https://www.turkupetcentre.net/reports/tpcmod0023.pdf",
87 "4. Oikonen V. Multilinear solution for 4-compartment model:",
88 " II. Two parallel tissue compartments.",
89 " https://www.turkupetcentre.net/reports/tpcmod0024.pdf",
90 "5. Lawson CL & Hanson RJ. Solving least squares problems.",
91 " Prentice-Hall, 1974.",
93 "See also: fitk4, fitk5, patlak, logan, imglhdv, fitdelay, taccbv",
95 "Keywords: TAC, modelling, compartmental model, LLSQ",
112enum {MODEL_UNKNOWN, MODEL_K1, MODEL_K2, MODEL_K3, MODEL_K4,
113 MODEL_K5S, MODEL_K5P, MODEL_K6S, MODEL_K6P};
114enum {VB_UNKNOWN, VB_IGNORED, VB_FITTED};
115enum {METHOD_UNKNOWN, METHOD_NNLS, METHOD_BVLS};
116static char *model_str[] = {
118 "K1",
"K1-k2",
"K1-k3",
"K1-k4",
"K1-k5",
"K1-k5 parallel",
119 "K1-k6",
"K1-k6 parallel", 0};
120static char *vb_model_str[] = {
"unknown",
"ignored",
"fitted", 0};
121static char *method_str[] = {
"unknown",
"NNLS",
"BVLS", 0};
128int main(
int argc,
char **argv)
130 int ai, help=0, version=0, verbose=1;
131 char ptacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], resfile[FILENAME_MAX],
132 fitfile[FILENAME_MAX], svgfile[FILENAME_MAX], lpfile[FILENAME_MAX];
135 double fitdur=nan(
"");
136 int method=METHOD_NNLS;
138 int vb_model=VB_IGNORED;
144 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
145 ptacfile[0]=ttacfile[0]=resfile[0]=fitfile[0]=svgfile[0]=lpfile[0]=(char)0;
147 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
149 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
150 if(strncasecmp(cptr,
"SVG=", 4)==0) {
151 strlcpy(svgfile, cptr+4, FILENAME_MAX);
if(strlen(svgfile)>0)
continue;
152 }
else if(strncasecmp(cptr,
"FIT=", 4)==0) {
153 strlcpy(fitfile, cptr+4, FILENAME_MAX);
if(strlen(fitfile)>0)
continue;
154 }
else if(strncasecmp(cptr,
"LP=", 3)==0) {
155 strlcpy(lpfile, cptr+3, FILENAME_MAX);
if(strlen(lpfile)>0)
continue;
156 }
else if(strcasecmp(cptr,
"W1")==0) {
158 }
else if(strcasecmp(cptr,
"WF")==0) {
160 }
else if(strcasecmp(cptr,
"MID")==0) {
162 }
else if(strcasecmp(cptr,
"NNLS")==0) {
163 method=METHOD_NNLS;
continue;
164 }
else if(strcasecmp(cptr,
"BVLS")==0) {
165 method=METHOD_BVLS;
continue;
166 }
else if(strncasecmp(cptr,
"VB=", 3)==0 ||
167 strncasecmp(cptr,
"VP=", 3)==0 ||
168 strncasecmp(cptr,
"VA=", 3)==0)
171 if(strncasecmp(cptr,
"FITTED", 1)==0) {vb_model=VB_FITTED;
continue;}
172 if(strncasecmp(cptr,
"IGNORED", 1)==0) {vb_model=VB_IGNORED;
continue;}
173 }
else if(strncasecmp(cptr,
"MODEL=", 6)==0) {
175 if(strcasecmp(cptr,
"K1")==0) {model=MODEL_K1;
continue;}
176 if(strcasecmp(cptr,
"K2")==0) {model=MODEL_K2;
continue;}
177 if(strcasecmp(cptr,
"K3")==0) {model=MODEL_K3;
continue;}
178 if(strcasecmp(cptr,
"K4")==0) {model=MODEL_K4;
continue;}
179 if(strcasecmp(cptr,
"K5S")==0) {model=MODEL_K5S;
continue;}
180 if(strcasecmp(cptr,
"K5P")==0) {model=MODEL_K5P;
continue;}
181 if(strcasecmp(cptr,
"K6S")==0) {model=MODEL_K6S;
continue;}
182 if(strcasecmp(cptr,
"K6P")==0) {model=MODEL_K6P;
continue;}
183 fprintf(stderr,
"Error: invalid model '%s'.\n", cptr);
186 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
195 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
200 if(ai<argc)
strlcpy(ptacfile, argv[ai++], FILENAME_MAX);
201 if(ai<argc)
strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
204 fprintf(stderr,
"Error: invalid fit time '%s'.\n", argv[ai]);
207 if(fitdur<=0.0) fitdur=1.0E+99;
210 if(ai<argc)
strlcpy(resfile, argv[ai++], FILENAME_MAX);
212 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
217 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
224 printf(
"ptacfile := %s\n", ptacfile);
225 printf(
"ttacfile := %s\n", ttacfile);
226 printf(
"resfile := %s\n", resfile);
227 if(fitfile[0]) printf(
"fitfile := %s\n", fitfile);
228 if(svgfile[0]) printf(
"svgfile := %s\n", svgfile);
229 if(lpfile[0]) printf(
"lpfile := %s\n", lpfile);
230 printf(
"model := %s\n", model_str[model]);
231 printf(
"vb_model := %s\n", vb_model_str[vb_model]);
232 printf(
"method := %s\n", method_str[method]);
233 printf(
"required_fittime := %g min\n", fitdur);
234 printf(
"weights := %d\n",
weights);
235 if(mid!=0) printf(
"mid := %d\n", mid);
243 case MODEL_K1: llsq_n=1;
break;
244 case MODEL_K2: llsq_n=2;
break;
245 case MODEL_K3: llsq_n=3;
break;
246 case MODEL_K4: llsq_n=4;
break;
247 case MODEL_K5S: llsq_n=5;
break;
248 case MODEL_K6S: llsq_n=6;
break;
249 case MODEL_K5P: llsq_n=5;
break;
250 case MODEL_K6P: llsq_n=6;
break;
253 if(vb_model==VB_FITTED) llsq_n++;
254 if(verbose>2) printf(
"llsq_n := %d\n", llsq_n);
260 if(verbose>1) printf(
"reading tissue and input data\n");
265 &fitSampleNr, &ttac0, &ptac, &status);
272 printf(
"tacNr := %d\n", ttac0.
tacNr);
273 printf(
"ttac.sampleNr := %d\n", ttac0.
sampleNr);
274 printf(
"ptac.sampleNr := %d\n", ptac.
sampleNr);
275 printf(
"fitSampleNr := %d\n", fitSampleNr);
278 printf(
"fitdur := %g s\n", fitdur);
281 if(fitSampleNr<llsq_n || ptac.
sampleNr<llsq_n) {
282 fprintf(stderr,
"Error: too few samples in specified fit duration.\n");
291 for(
int i=0; i<ttac0.
sampleNr; i++) ttac0.
w[i]=1.0;
298 if(verbose>0) fprintf(stderr,
"Warning: data is not weighted.\n");
305 if(verbose>1) printf(
"integrating PTAC\n");
310 ret=
tacInterpolate(&ptac, &ttac0, &input0, &input1, &input2, &status);
321 fprintf(stderr,
"Error: cannot make 3rd integral of PTAC.\n");
331 if(verbose>1) printf(
"integrating TTAC\n");
335 ret=
tacInterpolate(&ttac0, &ttac0, NULL, &ttac1, &ttac2, &status);
343 for(
int i=0; i<ttac2.
tacNr; i++) {
349 fprintf(stderr,
"Error: cannot make 3rd integral of TTAC.\n");
359 if(verbose>1) printf(
"initializing LLSQ parameter data\n");
375 iftPut(&lp.
h,
"program", buf, 0, NULL);
377 iftPut(&lp.
h,
"plasmafile", ptacfile, 0, NULL);
378 iftPut(&lp.
h,
"datafile", ttacfile, 0, NULL);
380 iftPut(&lp.
h,
"fitmethod", method_str[method], 0, NULL);
382 iftPut(&lp.
h,
"model", model_str[model], 0, NULL);
386 for(i=0; i<lp.
tacNr; i++) {
394 for(i=0; i<MAX_LLSQ_N; i++) {
395 sprintf(lp.
n[i].
name,
"P%d", 1+i);
401 if(method==METHOD_NNLS) {
406 if(verbose>1) printf(
"allocating memory for NNLS\n");
407 int llsq_m=fitSampleNr;
408 double *llsq_mat=(
double*)malloc((2*llsq_n*llsq_m)*
sizeof(
double));
410 fprintf(stderr,
"Error: cannot allocate memory for NNLS.\n");
416 double **llsq_a=(
double**)malloc(llsq_n*
sizeof(
double*));
418 fprintf(stderr,
"Error: cannot allocate memory for NNLS.\n");
424 for(
int ni=0; ni<llsq_n; ni++) llsq_a[ni]=llsq_mat+ni*llsq_m;
425 double r2, llsq_b[llsq_m], llsq_x[llsq_n], llsq_wp[llsq_n], llsq_zz[llsq_m];
427 double *matbackup=llsq_mat+llsq_n*llsq_m;
432 for(
int ti=0; ti<ttac0.
tacNr; ti++) {
434 if(verbose>1 && ttac0.
tacNr>1) {
435 printf(
"Region %d %s\n", 1+ti, ttac0.
c[ti].
name); fflush(stdout);}
438 for(
int mi=0; mi<llsq_m; mi++)
439 llsq_b[mi]=ttac0.
c[ti].
y[mi];
440 int n=llsq_n;
if(vb_model==VB_FITTED) n--;
441 for(
int mi=0; mi<llsq_m; mi++) {
442 if(n>0) llsq_mat[mi]=input1.
c[0].
y[mi];
443 if(n>1) llsq_mat[mi+llsq_m]=-ttac1.
c[ti].
y[mi];
444 if(n>2) llsq_mat[mi+2*llsq_m]=input2.
c[0].
y[mi];
445 if(n>3) llsq_mat[mi+3*llsq_m]=-ttac2.
c[ti].
y[mi];
446 if(n>4) llsq_mat[mi+4*llsq_m]=input3.
c[0].
y[mi];
447 if(n>5) llsq_mat[mi+5*llsq_m]=-ttac3.
c[ti].
y[mi];
448 if(vb_model==VB_FITTED)
449 llsq_mat[mi+(llsq_n-1)*llsq_m]=input0.
c[0].
y[mi];
452 printf(
"Matrix A and vector B:\n");
453 for(
int mi=0; mi<llsq_m; mi++) {
454 printf(
"%.2e", llsq_a[0][mi]);
455 for(
int ni=1; ni<llsq_n; ni++) printf(
", %.2e", llsq_a[ni][mi]);
456 printf(
"; %.3e\n", llsq_b[mi]);
460 for(
int i=0; i<llsq_n*llsq_m; i++) matbackup[i]=llsq_mat[i];
465 if(verbose>3) printf(
"starting NNLS...\n");
466 ret=
nnls(llsq_a, llsq_m, llsq_n, llsq_b, llsq_x, &r2, llsq_wp, llsq_zz, indexp);
467 if(verbose>3) printf(
" ... done.\n");
469 fprintf(stderr,
"Warning: no NNLS solution for %s\n", ttac0.
c[ti].
name);
470 for(
int ni=0; ni<llsq_n; ni++) llsq_x[ni]=0.0;
473 fprintf(stderr,
"Warning: NNLS iteration max exceeded for %s\n", ttac0.
c[ti].
name);
476 printf(
"solution_vector: %g", llsq_wp[0]);
477 for(
int ni=1; ni<llsq_n; ni++) printf(
", %g", llsq_wp[ni]);
480 for(
int ni=0; ni<llsq_n; ni++) lp.
r[ti].
p[ni]=llsq_x[ni];
486 for(
int mi=0; mi<llsq_m; mi++) {
487 ttac1.
c[ti].
y[mi]=0.0;
488 for(
int ni=0; ni<llsq_n; ni++) ttac1.
c[ti].
y[mi]+=llsq_x[ni]*matbackup[mi+ni*llsq_m];
494 free(llsq_a); free(llsq_mat);
496 }
else if(method==METHOD_BVLS) {
501 if(verbose>1) printf(
"allocating memory for BVLS\n");
502 int llsq_m=fitSampleNr;
503 double *llsq_mat=(
double*)malloc((2*llsq_n*llsq_m)*
sizeof(
double));
505 fprintf(stderr,
"Error: cannot allocate memory for NNLS.\n");
511 double b[llsq_m], x[MAX_LLSQ_N], bl[MAX_LLSQ_N], bu[MAX_LLSQ_N], w[llsq_n], zz[llsq_m];
512 double act[llsq_m*(llsq_n+2)], r2;
513 int istate[llsq_n+1], iterNr;
514 double *matbackup=llsq_mat+llsq_n*llsq_m;
519 for(
int ti=0; ti<ttac0.
tacNr; ti++) {
521 if(verbose>1 && ttac0.
tacNr>1) {
522 printf(
"Region %d %s\n", 1+ti, ttac0.
c[ti].
name); fflush(stdout);}
525 for(
int mi=0; mi<llsq_m; mi++)
526 b[mi]=ttac0.
c[ti].
y[mi];
527 int n=llsq_n;
if(vb_model==VB_FITTED) n--;
528 for(
int mi=0; mi<llsq_m; mi++) {
529 if(n>0) llsq_mat[mi]=input1.
c[0].
y[mi];
530 if(n>1) llsq_mat[mi+llsq_m]=-ttac1.
c[ti].
y[mi];
531 if(n>2) llsq_mat[mi+2*llsq_m]=input2.
c[0].
y[mi];
532 if(n>3) llsq_mat[mi+3*llsq_m]=-ttac2.
c[ti].
y[mi];
533 if(n>4) llsq_mat[mi+4*llsq_m]=input3.
c[0].
y[mi];
534 if(n>5) llsq_mat[mi+5*llsq_m]=-ttac3.
c[ti].
y[mi];
535 if(vb_model==VB_FITTED)
536 llsq_mat[mi+(llsq_n-1)*llsq_m]=input0.
c[0].
y[mi];
539 printf(
"Matrix A and vector B:\n");
540 for(
int mi=0; mi<llsq_m; mi++) {
541 printf(
"%.2e", llsq_mat[mi]);
542 for(
int ni=1; ni<llsq_n; ni++) printf(
", %.2e", llsq_mat[mi+ni*llsq_m]);
543 printf(
"; %.3e\n", b[mi]);
547 for(
int i=0; i<llsq_n*llsq_m; i++) matbackup[i]=llsq_mat[i];
551 istate[llsq_n]=0;
for(
int ni=0; ni<llsq_n; ni++) istate[ni]=1+ni;
553 if(vb_model==VB_FITTED) {bl[llsq_n-1]=0.0; bu[llsq_n-1]=1.0;}
556 bl[0]=0.0; bu[0]=10.0;
559 bl[0]=0.0; bu[0]=10.0;
560 bl[1]=0.0; bu[1]=10.0;
563 bl[0]=0.0; bu[0]=10.0;
564 bl[1]=0.0; bu[1]=10.0;
565 bl[2]=0.0; bu[2]=10.0;
568 bl[0]=0.0; bu[0]=10.0;
569 bl[1]=0.0; bu[1]=10.0;
570 bl[2]=0.0; bu[2]=2.0;
571 bl[3]=0.0; bu[3]=2.0;
574 bl[0]=0.0; bu[0]=10.0;
575 bl[1]=0.0; bu[1]=10.0;
576 bl[2]=0.0; bu[2]=2.0;
577 bl[3]=0.0; bu[3]=2.0;
578 bl[4]=0.0; bu[4]=1.0;
581 bl[0]=0.0; bu[0]=10.0;
582 bl[1]=0.0; bu[1]=10.0;
583 bl[2]=0.0; bu[2]=2.0;
584 bl[3]=0.0; bu[3]=2.0;
585 bl[4]=0.0; bu[4]=1.0;
588 bl[0]=0.0; bu[0]=10.0;
589 bl[1]=0.0; bu[1]=10.0;
590 bl[2]=0.0; bu[2]=2.0;
591 bl[3]=0.0; bu[3]=2.0;
592 bl[4]=0.0; bu[4]=1.0;
593 bl[5]=0.0; bu[5]=0.2;
596 bl[0]=0.0; bu[0]=10.0;
597 bl[1]=0.0; bu[1]=10.0;
598 bl[2]=0.0; bu[2]=2.0;
599 bl[3]=0.0; bu[3]=2.0;
600 bl[4]=0.0; bu[4]=1.0;
601 bl[5]=0.0; bu[5]=0.2;
608 if(verbose>3) printf(
"starting BVLS...\n");
609 ret=
bvls(0, llsq_m, llsq_n, llsq_mat, b, bl, bu, x, w, act, zz, istate, &iterNr, verbose-3);
610 if(verbose>3) printf(
" ... done.\n");
613 if(ret==-1) fprintf(stderr,
"Warning: BVLS iteration max exceeded for %s\n", ttac0.
c[ti].
name);
614 else fprintf(stderr,
"Warning: no BVLS solution for %s\n", ttac0.
c[ti].
name);
615 for(
int ni=0; ni<llsq_n; ni++) x[ni]=0.0;
619 printf(
"solution_vector: %d", istate[0]);
620 for(
int ni=1; ni<llsq_n; ni++) printf(
", %d", istate[ni]);
623 for(
int ni=0; ni<llsq_n; ni++) lp.
r[ti].
p[ni]=x[ni];
629 for(
int mi=0; mi<llsq_m; mi++) {
630 ttac1.
c[ti].
y[mi]=0.0;
631 for(
int ni=0; ni<llsq_n; ni++) ttac1.
c[ti].
y[mi]+=x[ni]*matbackup[mi+ni*llsq_m];
641 fprintf(stderr,
"Error: selected method not available.");
653 if(verbose>1 && lp.
tacNr<50)
661 if(verbose>1) printf(
"writing %s\n", lpfile);
665 FILE *fp; fp=fopen(lpfile,
"w");
667 fprintf(stderr,
"Error: cannot open file for writing parameter file.\n");
680 if(verbose>0) printf(
"Results saved in %s.\n", lpfile);
689 if(verbose>1) printf(
"initializing CM parameter data\n");
706 iftPut(&cmpar.
h,
"program", buf, 0, NULL);
708 iftPut(&cmpar.
h,
"plasmafile", ptacfile, 0, NULL);
709 iftPut(&cmpar.
h,
"datafile", ttacfile, 0, NULL);
711 iftPut(&cmpar.
h,
"fitmethod", method_str[method], 0, NULL);
713 iftPut(&cmpar.
h,
"model", model_str[model], 0, NULL);
717 for(i=0; i<cmpar.
tacNr; i++) {
720 cmpar.
r[i].
end=fitdur;
726 double k1, k2, k3, k4, k5, k6, k1k2, k3k4, k5k6, Ki, Vt, Vp;
727 const double llimit=1.0E-06;
730 i=0; strcpy(cmpar.
n[i].
name,
"K1");
732 for(
int ti=0; ti<cmpar.
tacNr; ti++) {
733 if(vb_model==VB_FITTED) Vp=lp.
r[ti].
p[llsq_n-1];
else Vp=0.0;
734 cmpar.
r[ti].
p[0]=k1=lp.
r[ti].
p[0];
735 cmpar.
r[ti].
p[1]=100.*Vp;
739 i=0; strcpy(cmpar.
n[i].
name,
"K1");
740 i=1; strcpy(cmpar.
n[i].
name,
"k2");
741 i=2; strcpy(cmpar.
n[i].
name,
"K1/k2");
743 for(
int ti=0; ti<cmpar.
tacNr; ti++) {
744 if(vb_model==VB_FITTED) Vp=lp.
r[ti].
p[llsq_n-1];
else Vp=0.0;
745 k1=lp.
r[ti].
p[0]-Vp*lp.
r[ti].
p[1];
747 if(k1<llimit) k1=k2=0.0;
748 if(k2<llimit) k2=0.0;
750 if(isfinite(k1)) cmpar.
r[ti].
p[0]=k1;
751 if(isfinite(k2)) cmpar.
r[ti].
p[1]=k2;
752 if(isfinite(k1k2)) cmpar.
r[ti].
p[2]=k1k2;
753 cmpar.
r[ti].
p[3]=100.*Vp;
758 i=0; strcpy(cmpar.
n[i].
name,
"K1");
759 i=1; strcpy(cmpar.
n[i].
name,
"k2");
760 i=2; strcpy(cmpar.
n[i].
name,
"k3");
761 i=3; strcpy(cmpar.
n[i].
name,
"K1/k2");
762 i=4; strcpy(cmpar.
n[i].
name,
"Ki");
764 for(
int ti=0; ti<cmpar.
tacNr; ti++) {
765 if(vb_model==VB_FITTED) Vp=lp.
r[ti].
p[llsq_n-1];
else Vp=0.;
766 k1=lp.
r[ti].
p[0]-Vp*lp.
r[ti].
p[1];
767 k2=lp.
r[ti].
p[1]-lp.
r[ti].
p[2]/k1;
769 if(k1<llimit) k1=k2=k3=0.0;
770 if(k2<llimit) k2=k3=0.0;
771 if(k3<llimit) k3=0.0;
774 if(isfinite(k1)) cmpar.
r[ti].
p[0]=k1;
775 if(isfinite(k2)) cmpar.
r[ti].
p[1]=k2;
776 if(isfinite(k3)) cmpar.
r[ti].
p[2]=k3;
777 if(isfinite(k1k2)) cmpar.
r[ti].
p[3]=k1k2;
778 if(isfinite(Ki)) cmpar.
r[ti].
p[4]=Ki;
779 cmpar.
r[ti].
p[5]=100.*Vp;
784 i=0; strcpy(cmpar.
n[i].
name,
"K1");
785 i=1; strcpy(cmpar.
n[i].
name,
"k2");
786 i=2; strcpy(cmpar.
n[i].
name,
"k3");
787 i=3; strcpy(cmpar.
n[i].
name,
"k4");
788 i=4; strcpy(cmpar.
n[i].
name,
"K1/k2");
789 i=5; strcpy(cmpar.
n[i].
name,
"k3/k4");
790 i=6; strcpy(cmpar.
n[i].
name,
"Vt");
792 for(
int ti=0; ti<cmpar.
tacNr; ti++) {
793 if(vb_model==VB_FITTED) Vp=lp.
r[ti].
p[llsq_n-1];
else Vp=0.0;
794 k1=lp.
r[ti].
p[0]-Vp*lp.
r[ti].
p[1];
795 k2=lp.
r[ti].
p[1]-(lp.
r[ti].
p[2]-Vp*lp.
r[ti].
p[3])/k1;
796 k3=lp.
r[ti].
p[1]-k2-lp.
r[ti].
p[3]/k2;
797 k4=lp.
r[ti].
p[1]-k2-k3;
798 if(k1<llimit) k1=k2=k3=k4=0.0;
799 if(k2<llimit) k2=k3=k4=0.0;
800 if(k3<llimit) k3=k4=0.0;
801 if(k4<llimit) k4=0.0;
805 if(isfinite(k1)) cmpar.
r[ti].
p[0]=k1;
806 if(isfinite(k2)) cmpar.
r[ti].
p[1]=k2;
807 if(isfinite(k3)) cmpar.
r[ti].
p[2]=k3;
808 if(isfinite(k4)) cmpar.
r[ti].
p[3]=k4;
809 if(isfinite(k1k2)) cmpar.
r[ti].
p[4]=k1k2;
810 if(isfinite(k3k4)) cmpar.
r[ti].
p[5]=k3k4;
811 if(isfinite(Vt)) cmpar.
r[ti].
p[6]=Vt;
812 cmpar.
r[ti].
p[7]=100.*Vp;
817 i=0; strcpy(cmpar.
n[i].
name,
"K1");
818 i=1; strcpy(cmpar.
n[i].
name,
"k2");
819 i=2; strcpy(cmpar.
n[i].
name,
"k3");
820 i=3; strcpy(cmpar.
n[i].
name,
"k4");
821 i=4; strcpy(cmpar.
n[i].
name,
"k5");
822 i=5; strcpy(cmpar.
n[i].
name,
"K1/k2");
823 i=6; strcpy(cmpar.
n[i].
name,
"k3/k4");
824 i=7; strcpy(cmpar.
n[i].
name,
"Ki");
826 for(
int ti=0; ti<cmpar.
tacNr; ti++) {
827 if(vb_model==VB_FITTED) Vp=lp.
r[ti].
p[llsq_n-1];
else Vp=0.0;
828 k1=lp.
r[ti].
p[0]-Vp*lp.
r[ti].
p[1];
829 k2=lp.
r[ti].
p[1]-(lp.
r[ti].
p[2]-Vp*lp.
r[ti].
p[3])/k1;
830 k3=lp.
r[ti].
p[1]-k2-(lp.
r[ti].
p[3]-lp.
r[ti].
p[4]/k1)/k2;
831 k4=lp.
r[ti].
p[1]-k2-k3-(lp.
r[ti].
p[4]/k1)/k3;
832 k5=lp.
r[ti].
p[1]-k2-k3-k4;
833 if(k1<llimit) k1=k2=k3=k4=k5=0.0;
834 if(k2<llimit) k2=k3=k4=k5=0.0;
835 if(k3<llimit) k3=k4=k5=0.0;
836 if(k4<llimit) k4=k5=0.0;
837 if(k5<llimit) k5=0.0;
840 Ki=k1*k3*k5/(k2*k4+k2*k5+k3*k5);
841 if(isfinite(k1)) cmpar.
r[ti].
p[0]=k1;
842 if(isfinite(k2)) cmpar.
r[ti].
p[1]=k2;
843 if(isfinite(k3)) cmpar.
r[ti].
p[2]=k3;
844 if(isfinite(k4)) cmpar.
r[ti].
p[3]=k4;
845 if(isfinite(k5)) cmpar.
r[ti].
p[4]=k5;
846 if(isfinite(k1k2)) cmpar.
r[ti].
p[5]=k1k2;
847 if(isfinite(k3k4)) cmpar.
r[ti].
p[6]=k3k4;
848 if(isfinite(Ki)) cmpar.
r[ti].
p[7]=Ki;
849 cmpar.
r[ti].
p[8]=100.*Vp;
854 i=0; strcpy(cmpar.
n[i].
name,
"K1");
855 i=1; strcpy(cmpar.
n[i].
name,
"k2");
856 i=2; strcpy(cmpar.
n[i].
name,
"k3");
857 i=3; strcpy(cmpar.
n[i].
name,
"k4");
858 i=4; strcpy(cmpar.
n[i].
name,
"k5");
859 i=5; strcpy(cmpar.
n[i].
name,
"K1/k2");
860 i=6; strcpy(cmpar.
n[i].
name,
"k3/k4");
861 i=7; strcpy(cmpar.
n[i].
name,
"Ki");
863 for(
int ti=0; ti<cmpar.
tacNr; ti++) {
864 if(vb_model==VB_FITTED) Vp=lp.
r[ti].
p[llsq_n-1];
else Vp=0.0;
865 k1=lp.
r[ti].
p[0]-Vp*lp.
r[ti].
p[1];
866 k2=lp.
r[ti].
p[1]-(lp.
r[ti].
p[2]-Vp*lp.
r[ti].
p[3])/k1;
867 k4=(lp.
r[ti].
p[3]-lp.
r[ti].
p[4]/k1)/k2;
868 k5=lp.
r[ti].
p[4]/(k1*k4);
869 k3=lp.
r[ti].
p[1]-k2-k4-k5;
870 if(k1<llimit) k1=k2=k3=k4=k5=0.0;
871 if(k2<llimit) k2=k3=k4=k5=0.0;
872 if(k3<llimit) k3=k4=0.0;
873 if(k4<llimit) k4=0.0;
874 if(k5<llimit) k5=0.0;
878 if(isfinite(k1)) cmpar.
r[ti].
p[0]=k1;
879 if(isfinite(k2)) cmpar.
r[ti].
p[1]=k2;
880 if(isfinite(k3)) cmpar.
r[ti].
p[2]=k3;
881 if(isfinite(k4)) cmpar.
r[ti].
p[3]=k4;
882 if(isfinite(k5)) cmpar.
r[ti].
p[4]=k5;
883 if(isfinite(k1k2)) cmpar.
r[ti].
p[5]=k1k2;
884 if(isfinite(k3k4)) cmpar.
r[ti].
p[6]=k3k4;
885 if(isfinite(Ki)) cmpar.
r[ti].
p[7]=Ki;
886 cmpar.
r[ti].
p[8]=100.*Vp;
891 i=0; strcpy(cmpar.
n[i].
name,
"K1");
892 i=1; strcpy(cmpar.
n[i].
name,
"k2");
893 i=2; strcpy(cmpar.
n[i].
name,
"k3");
894 i=3; strcpy(cmpar.
n[i].
name,
"k4");
895 i=4; strcpy(cmpar.
n[i].
name,
"k5");
896 i=5; strcpy(cmpar.
n[i].
name,
"k6");
897 i=6; strcpy(cmpar.
n[i].
name,
"K1/k2");
898 i=7; strcpy(cmpar.
n[i].
name,
"k3/k4");
899 i=8; strcpy(cmpar.
n[i].
name,
"k5/k6");
900 i=9; strcpy(cmpar.
n[i].
name,
"Vt");
902 for(
int ti=0; ti<cmpar.
tacNr; ti++) {
903 if(vb_model==VB_FITTED) Vp=lp.
r[ti].
p[llsq_n-1];
else Vp=0.0;
904 k1=lp.
r[ti].
p[0]-Vp*lp.
r[ti].
p[1];
905 k2=lp.
r[ti].
p[1]-(lp.
r[ti].
p[2]-Vp*lp.
r[ti].
p[3])/k1;
906 k3=lp.
r[ti].
p[1]-k2-(lp.
r[ti].
p[3]-(lp.
r[ti].
p[4]-Vp*lp.
r[ti].
p[5])/k1)/k2;
907 k4=lp.
r[ti].
p[1]-k2-k3-((lp.
r[ti].
p[4]-Vp*lp.
r[ti].
p[5])/k1-lp.
r[ti].
p[5]/k2)/k3;
908 k6=lp.
r[ti].
p[5]/(k2*k4);
909 k5=lp.
r[ti].
p[1]-k2-k3-k4-k6;
910 if(k1<llimit) k1=k2=k3=k4=k5=k6=0.0;
911 if(k2<llimit) k2=k3=k4=k5=k6=0.0;
912 if(k3<llimit) k3=k4=k5=k6=0.0;
913 if(k4<llimit) k4=k5=k6=0.0;
914 if(k5<llimit) k5=k6=0.0;
915 if(k6<llimit) k6=0.0;
919 Vt=k1k2*(1.0+k3k4*(1.0+k5k6));
920 if(isfinite(k1)) cmpar.
r[ti].
p[0]=k1;
921 if(isfinite(k2)) cmpar.
r[ti].
p[1]=k2;
922 if(isfinite(k3)) cmpar.
r[ti].
p[2]=k3;
923 if(isfinite(k4)) cmpar.
r[ti].
p[3]=k4;
924 if(isfinite(k5)) cmpar.
r[ti].
p[4]=k5;
925 if(isfinite(k6)) cmpar.
r[ti].
p[5]=k6;
926 if(isfinite(k1k2)) cmpar.
r[ti].
p[6]=k1k2;
927 if(isfinite(k3k4)) cmpar.
r[ti].
p[7]=k3k4;
928 if(isfinite(k5k6)) cmpar.
r[ti].
p[8]=k5k6;
929 if(isfinite(Vt)) cmpar.
r[ti].
p[9]=Vt;
930 cmpar.
r[ti].
p[10]=100.*Vp;
935 i=0; strcpy(cmpar.
n[i].
name,
"K1");
936 i=1; strcpy(cmpar.
n[i].
name,
"k2");
937 i=2; strcpy(cmpar.
n[i].
name,
"k3");
938 i=3; strcpy(cmpar.
n[i].
name,
"k4");
939 i=4; strcpy(cmpar.
n[i].
name,
"k5");
940 i=5; strcpy(cmpar.
n[i].
name,
"k6");
941 i=6; strcpy(cmpar.
n[i].
name,
"K1/k2");
942 i=7; strcpy(cmpar.
n[i].
name,
"k3/k4");
943 i=8; strcpy(cmpar.
n[i].
name,
"k5/k6");
944 i=9; strcpy(cmpar.
n[i].
name,
"Vt");
946 for(
int ti=0; ti<cmpar.
tacNr; ti++) {
947 if(vb_model==VB_FITTED) Vp=lp.
r[ti].
p[llsq_n-1];
else Vp=0.0;
948 k1=lp.
r[ti].
p[0]-Vp*lp.
r[ti].
p[1];
949 k2=lp.
r[ti].
p[1]-(lp.
r[ti].
p[2]-Vp*lp.
r[ti].
p[3])/k1;
950 if(k1<llimit) k1=k2=0.0;
951 if(k2<llimit) k2=0.0;
955 Vt=cmpar.
r[ti].
p[4]/cmpar.
r[ti].
p[5]-Vp;
956 if(isfinite(k1)) cmpar.
r[ti].
p[0]=k1;
957 if(isfinite(k2)) cmpar.
r[ti].
p[1]=k2;
958 if(isfinite(k1k2)) cmpar.
r[ti].
p[6]=k1k2;
959 if(isfinite(Vt)) cmpar.
r[ti].
p[9]=Vt;
960 cmpar.
r[ti].
p[10]=100.*Vp;
967 for(
int ti=0; ti<cmpar.
tacNr; ti++) {
977 if(verbose>0 && lp.
tacNr<80)
984 if(verbose>1) printf(
"writing %s\n", resfile);
988 FILE *fp; fp=fopen(resfile,
"w");
990 fprintf(stderr,
"Error: cannot open file for writing parameter file.\n");
1003 if(verbose>0) printf(
"Results saved in %s.\n", resfile);
1013 if(verbose>1) printf(
"saving SVG plot\n");
1016 sprintf(buf,
"%s %s", method_str[method], model_str[model]);
1018 if(i<0) i=
iftFindKey(&ttac0.
h,
"study_number", 0);
1019 if(i>=0) {strcat(buf,
": "); strcat(buf, ttac0.
h.
item[i].
value);}
1020 ret=
tacPlotFitSVG(&ttac0, &ttac1, buf, 0.0, nan(
""), 0.0, nan(
""), svgfile, &status);
1028 if(verbose>0) printf(
"Plots written in %s.\n", svgfile);
1036 if(verbose>1) printf(
"writing %s\n", fitfile);
1037 FILE *fp; fp=fopen(fitfile,
"w");
1039 fprintf(stderr,
"Error: cannot open file for writing fitted TTACs.\n");
1052 if(verbose>0) printf(
"fitted TACs saved in %s.\n", fitfile);
int bvls(int key, const int m, const int n, double *a, double *b, double *bl, double *bu, double *x, double *w, double *act, double *zz, int *istate, int *iter, int verbose)
Bounded-value least-squares method to solve the linear problem A x ~ b , subject to limit1 <= x <= li...
int llsqWght(int N, int M, double **A, double *a, double *b, double *weight)
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,...
int atofCheck(const char *s, double *v)
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
int iftFindKey(IFT *ift, const char *key, int start_index)
int liIntegrate(double *x, double *y, const int nr, double *yi, const int se, const int verbose)
Linear integration of TAC with trapezoidal method.
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,...
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *wp, double *zzp, int *indexp)
int nnlsWght(int N, int M, double **A, double *b, double *weight)
char * parFormattxt(parformat c)
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
int parFormatFromExtension(const char *s)
int parAllocateWithTAC(PAR *par, TAC *tac, int parNr, TPCSTATUS *status)
Allocate PAR based on data in TAC.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
void tpcPrintBuild(const char *program, FILE *fp)
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
void statusInit(TPCSTATUS *s)
char * errorMsg(tpcerror e)
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
IFT h
Optional (but often useful) header information.
char name[MAX_PARNAME_LEN+1]
char name[MAX_TACNAME_LEN+1]
IFT h
Optional (but often useful) header information.
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacDuplicate(TAC *tac1, TAC *tac2)
Make a duplicate of TAC structure.
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)
char * tacFormattxt(tacformat c)
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
int tacIsWeighted(TAC *tac)
unsigned int tacWSampleNr(TAC *tac)
int tacWByFreq(TAC *tac, isotope isot, TPCSTATUS *status)
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_PERCENTAGE
Percentage (%).
@ TPCERROR_FAIL
General error.
char * unitName(int unit_code)
Header file for library libtpcift.
@ ISOTOPE_UNKNOWN
Unknown.
Header file for libtpcli.
Header file for libtpclinopt.
Header file for libtpcpar.
@ PAR_FORMAT_UNKNOWN
Unknown format.
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Header file for libtpctacmod.