TPCCLIB
Loading...
Searching...
No Matches
lhsol.c
Go to the documentation of this file.
1
10/*****************************************************************************/
11#include "tpcclibConfig.h"
12/*****************************************************************************/
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <math.h>
17/*****************************************************************************/
18#include "tpcextensions.h"
19#include "tpcift.h"
20#include "tpctac.h"
21#include "tpcpar.h"
22#include "tpcli.h"
23#include "tpctacmod.h"
24#include "tpclinopt.h"
25/*****************************************************************************/
26
27/*****************************************************************************/
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.",
31 " ",
32 " ____ ____ ____ ____ ",
33 " | Cp |--K1->| C1 |--k3->| C2 |--k5->| C3 | compartments in series (s)",
34 " |____|<-k2--|____|<-k4--|____|<-k6--|____| ",
35 " ",
36 " ____ ____ ",
37 " ____ | |--k3->| C2 | compartments in parallel (p)",
38 " | |--K1->| |<-k4--|____| ",
39 " | Cp | | C1 | ____ ",
40 " |____|<-k2--| |--k5->| C3 | ",
41 " |____|<-k6--|____| ",
42 " ",
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.",
47 " ",
48 "Usage: @P [options] PTAC TTAC fittime results",
49 " ",
50 "Options:",
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)",
60// " k6p (compartments in parallel)",
61// " For model 'k6p' most model parameters cannot be solved.",
62 " -Vp=<ignored|fitted>",
63 " Vascular volume is ignored (default) or fitted; note that PTAC is",
64 " assumed to represent vascular blood curve.",
65 " -w1 | -wf",
66 " Sample weights are set to 1 (-w1) or to frame lengths (-wf);",
67 " by default weights in TTAC file are used, if available.",
68 " -mid",
69 " Use frame mid times even when start and end times are available.",
70 " -svg=<Filename>",
71 " Fitted and measured TACs are plotted in specified SVG file.",
72 " -fit=<Filename>",
73 " Fitted regional TTACs are written in specified file.",
74 " -lp=<Filename>",
75 " Parameters of linear model are saved in specified file.",
76 " -stdoptions", // List standard options like --help, -v, etc
77 " ",
78 "References:",
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.",
92 " ",
93 "See also: fitk4, fitk5, patlak, logan, imglhdv, fitdelay, taccbv",
94 " ",
95 "Keywords: TAC, modelling, compartmental model, LLSQ",
96 0};
97/*****************************************************************************/
98
99/*****************************************************************************/
100/* Turn on the globbing of the command line, since it is disabled by default in
101 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
102 In Unix&Linux wildcard command line processing is enabled by default. */
103/*
104#undef _CRT_glob
105#define _CRT_glob -1
106*/
107int _dowildcard = -1;
108/*****************************************************************************/
109
110/*****************************************************************************/
111#define MAX_LLSQ_N 7
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[] = {
117 "unknown",
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};
122/*****************************************************************************/
123
124/*****************************************************************************/
128int main(int argc, char **argv)
129{
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];
133 int weights=0; // 0=default, 1=no weighting, 2=frequency
134 int mid=0; // 0=default, 1=use frame times even if start and end times exist.
135 double fitdur=nan("");
136 int method=METHOD_NNLS;
137 int model=MODEL_K4; //MODEL_UNKNOWN;
138 int vb_model=VB_IGNORED;
139 int ret;
140
141 /*
142 * Get arguments
143 */
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;
146 /* Options */
147 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
148 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
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) {
157 weights=1; continue;
158 } else if(strcasecmp(cptr, "WF")==0) {
159 weights=2; continue;
160 } else if(strcasecmp(cptr, "MID")==0) {
161 mid=1; continue;
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)
169 {
170 cptr+=3;
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) {
174 cptr+=6;
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);
184 return(1);
185 }
186 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
187 return(1);
188 } else break;
189
190 TPCSTATUS status; statusInit(&status);
191 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
192 status.verbose=verbose-3;
193
194 /* Print help or version? */
195 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
196 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
197 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
198
199 /* Process other arguments, starting from the first non-option */
200 if(ai<argc) strlcpy(ptacfile, argv[ai++], FILENAME_MAX);
201 if(ai<argc) strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
202 if(ai<argc) {
203 if(atofCheck(argv[ai], &fitdur)) {
204 fprintf(stderr, "Error: invalid fit time '%s'.\n", argv[ai]);
205 return(1);
206 }
207 if(fitdur<=0.0) fitdur=1.0E+99;
208 ai++;
209 }
210 if(ai<argc) strlcpy(resfile, argv[ai++], FILENAME_MAX);
211 if(ai<argc) {
212 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
213 return(1);
214 }
215 /* Did we get all the information that we need? */
216 if(!resfile[0]) {
217 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
218 return(1);
219 }
220
221
222 /* In verbose mode print arguments and options */
223 if(verbose>1) {
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);
236 }
237
238 /*
239 * Set model-dependent parameters
240 */
241 int llsq_n=0;
242 switch(model) {
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;
251 default: exit(1);
252 }
253 if(vb_model==VB_FITTED) llsq_n++;
254 if(verbose>2) printf("llsq_n := %d\n", llsq_n);
255
256
257 /*
258 * Read tissue and input data
259 */
260 if(verbose>1) printf("reading tissue and input data\n");
261 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
262 TAC ptac, ttac0; tacInit(&ptac); tacInit(&ttac0);
263 int fitSampleNr;
264 ret=tacReadModelingData(ttacfile, ptacfile, NULL, NULL, &fitdur, 0,
265 &fitSampleNr, &ttac0, &ptac, &status);
266 if(ret!=TPCERROR_OK) {
267 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
268 tacFree(&ttac0); tacFree(&ptac); return(2);
269 }
270 if(verbose>2) {
271 printf("fileformat := %s\n", tacFormattxt(ttac0.format));
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);
276 printf("xunit := %s\n", unitName(ttac0.tunit));
277 printf("yunit := %s\n", unitName(ttac0.cunit));
278 printf("fitdur := %g s\n", fitdur);
279 }
280 if(mid>0) ttac0.isframe=ptac.isframe=0;
281 if(fitSampleNr<llsq_n || ptac.sampleNr<llsq_n) {
282 fprintf(stderr, "Error: too few samples in specified fit duration.\n");
283 tacFree(&ttac0); tacFree(&ptac); return(2);
284 }
285//int origSampleNr=ttac0.sampleNr;
286 ttac0.sampleNr=fitSampleNr;
287
288 /* Add data weights, if requested */
289 if(weights==1) {
291 for(int i=0; i<ttac0.sampleNr; i++) ttac0.w[i]=1.0;
292 } else if(weights==2) {
293 if(tacWByFreq(&ttac0, ISOTOPE_UNKNOWN, &status)!=TPCERROR_OK) {
294 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
295 tacFree(&ttac0); tacFree(&ptac); return(2);
296 }
297 } else if(!tacIsWeighted(&ttac0)) {
298 if(verbose>0) fprintf(stderr, "Warning: data is not weighted.\n");
299 }
300
301
302 /*
303 * Interpolate and integrate PTAC to TTAC times
304 */
305 if(verbose>1) printf("integrating PTAC\n");
306 TAC input0; tacInit(&input0); // interpolated PTAC
307 TAC input1; tacInit(&input1); // 1st integral
308 TAC input2; tacInit(&input2); // 2nd integral
309 TAC input3; tacInit(&input3); // 3rd integral
310 ret=tacInterpolate(&ptac, &ttac0, &input0, &input1, &input2, &status);
311 if(ret!=TPCERROR_OK) {
312 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
313 tacFree(&ttac0); tacFree(&ptac);
314 tacFree(&input0); tacFree(&input1); tacFree(&input2);
315 return(3);
316 }
317 ret=tacDuplicate(&input2, &input3);
318 if(ret==TPCERROR_OK)
319 ret=liIntegrate(input2.x, input2.c[0].y, input2.sampleNr, input3.c[0].y, 3, 0);
320 if(ret!=TPCERROR_OK) {
321 fprintf(stderr, "Error: cannot make 3rd integral of PTAC.\n");
322 tacFree(&ttac0); tacFree(&ptac);
323 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
324 return(3);
325 }
326 /* Original PTAC should not be needed any more */
327 tacFree(&ptac);
328
329
330 /* Integrate TTAC */
331 if(verbose>1) printf("integrating TTAC\n");
332 TAC ttac1; tacInit(&ttac1); // 1st integral
333 TAC ttac2; tacInit(&ttac2); // 2nd integral
334 TAC ttac3; tacInit(&ttac3); // 3rd integral
335 ret=tacInterpolate(&ttac0, &ttac0, NULL, &ttac1, &ttac2, &status);
336 if(ret!=TPCERROR_OK) {
337 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
338 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2);
339 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
340 }
341 ret=tacDuplicate(&ttac2, &ttac3);
342 if(ret==TPCERROR_OK) {
343 for(int i=0; i<ttac2.tacNr; i++) {
344 ret=liIntegrate(ttac2.x, ttac2.c[i].y, ttac2.sampleNr, ttac3.c[i].y, 3, 0);
345 if(ret!=TPCERROR_OK) break;
346 }
347 }
348 if(ret!=TPCERROR_OK) {
349 fprintf(stderr, "Error: cannot make 3rd integral of TTAC.\n");
350 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
351 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
352 return(3);
353 }
354
355
356 /*
357 * Prepare the room for LLSQ parameters
358 */
359 if(verbose>1) printf("initializing LLSQ parameter data\n");
360 PAR lp; parInit(&lp);
361 ret=parAllocateWithTAC(&lp, &ttac0, MAX_LLSQ_N, &status);
362 if(ret!=TPCERROR_OK) {
363 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
364 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
365 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
366 return(4);
367 }
368 /* Copy titles & file names */
369 {
370 int i;
371 char buf[256];
372 time_t t=time(NULL);
373 /* set program name */
374 tpcProgramName(argv[0], 1, 1, buf, 256);
375 iftPut(&lp.h, "program", buf, 0, NULL);
376 /* set file names */
377 iftPut(&lp.h, "plasmafile", ptacfile, 0, NULL);
378 iftPut(&lp.h, "datafile", ttacfile, 0, NULL);
379 /* Fit method */
380 iftPut(&lp.h, "fitmethod", method_str[method], 0, NULL);
381 /* Model */
382 iftPut(&lp.h, "model", model_str[model], 0, NULL);
383 /* Set current time to results */
384 iftPut(&lp.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
385 /* Set fit times for each TAC */
386 for(i=0; i<lp.tacNr; i++) {
387 lp.r[i].dataNr=fitSampleNr;
388 lp.r[i].start=0.0;
389 lp.r[i].end=fitdur;
390 /* and nr of fitted parameters */
391 lp.r[i].fitNr=llsq_n;
392 }
393 /* Set the parameter names and units */
394 for(i=0; i<MAX_LLSQ_N; i++) {
395 sprintf(lp.n[i].name, "P%d", 1+i);
396 }
397 lp.parNr=llsq_n;
398 }
399
400
401 if(method==METHOD_NNLS) {
402
403 /*
404 * Allocate memory required by NNLS
405 */
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));
409 if(llsq_mat==NULL) {
410 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
411 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
412 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
413 parFree(&lp);
414 return(5);
415 }
416 double **llsq_a=(double**)malloc(llsq_n*sizeof(double*));
417 if(llsq_a==NULL) {
418 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
419 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
420 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
421 parFree(&lp); free(llsq_mat);
422 return(5);
423 }
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];
426 int indexp[llsq_n];
427 double *matbackup=llsq_mat+llsq_n*llsq_m;
428
429 /*
430 * Fit each regional TTAC
431 */
432 for(int ti=0; ti<ttac0.tacNr; ti++) {
433
434 if(verbose>1 && ttac0.tacNr>1) {
435 printf("Region %d %s\n", 1+ti, ttac0.c[ti].name); fflush(stdout);}
436
437 /* Setup data matrix A and vector B */
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]; // PTAC 1st integral
443 if(n>1) llsq_mat[mi+llsq_m]=-ttac1.c[ti].y[mi]; // TTAC 1st integral
444 if(n>2) llsq_mat[mi+2*llsq_m]=input2.c[0].y[mi]; // PTAC 2nd integral
445 if(n>3) llsq_mat[mi+3*llsq_m]=-ttac2.c[ti].y[mi]; // TTAC 2nd integral
446 if(n>4) llsq_mat[mi+4*llsq_m]=input3.c[0].y[mi]; // PTAC 3rd integral
447 if(n>5) llsq_mat[mi+5*llsq_m]=-ttac3.c[ti].y[mi]; // TTAC 3rd integral
448 if(vb_model==VB_FITTED)
449 llsq_mat[mi+(llsq_n-1)*llsq_m]=input0.c[0].y[mi]; // PTAC
450 }
451 if(verbose>5) {
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]);
457 }
458 }
459 /* Make a copy of A matrix for later use */
460 for(int i=0; i<llsq_n*llsq_m; i++) matbackup[i]=llsq_mat[i];
461
462 /* Apply data weights */
463 if(tacIsWeighted(&ttac0)) nnlsWght(llsq_n, llsq_m, llsq_a, llsq_b, ttac0.w);
464 /* Compute NNLS */
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");
468 if(ret>1) {
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;
471 r2=0.0;
472 } else if(ret==1) {
473 fprintf(stderr, "Warning: NNLS iteration max exceeded for %s\n", ttac0.c[ti].name);
474 }
475 if(verbose>4) {
476 printf("solution_vector: %g", llsq_wp[0]);
477 for(int ni=1; ni<llsq_n; ni++) printf(", %g", llsq_wp[ni]);
478 printf("\n");
479 }
480 for(int ni=0; ni<llsq_n; ni++) lp.r[ti].p[ni]=llsq_x[ni];
481 lp.r[ti].wss=r2;
482 lp.r[ti].dataNr=tacWSampleNr(&ttac0);
483 lp.r[ti].fitNr=llsq_n;
484
485 /* Compute fitted TAC (into ttac1 since it is otherwise not needed) */
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];
489 }
490
491 } // next TAC
492
493 /* Free allocated memory */
494 free(llsq_a); free(llsq_mat);
495
496 } else if(method==METHOD_BVLS) {
497
498 /*
499 * Allocate memory required by BVLS
500 */
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));
504 if(llsq_mat==NULL) {
505 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
506 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
507 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
508 parFree(&lp);
509 return(5);
510 }
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;
515
516 /*
517 * Fit each regional TTAC
518 */
519 for(int ti=0; ti<ttac0.tacNr; ti++) {
520
521 if(verbose>1 && ttac0.tacNr>1) {
522 printf("Region %d %s\n", 1+ti, ttac0.c[ti].name); fflush(stdout);}
523
524 /* Setup data matrix A and vector B */
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]; // PTAC 1st integral
530 if(n>1) llsq_mat[mi+llsq_m]=-ttac1.c[ti].y[mi]; // TTAC 1st integral
531 if(n>2) llsq_mat[mi+2*llsq_m]=input2.c[0].y[mi]; // PTAC 2nd integral
532 if(n>3) llsq_mat[mi+3*llsq_m]=-ttac2.c[ti].y[mi]; // TTAC 2nd integral
533 if(n>4) llsq_mat[mi+4*llsq_m]=input3.c[0].y[mi]; // PTAC 3rd integral
534 if(n>5) llsq_mat[mi+5*llsq_m]=-ttac3.c[ti].y[mi]; // TTAC 3rd integral
535 if(vb_model==VB_FITTED)
536 llsq_mat[mi+(llsq_n-1)*llsq_m]=input0.c[0].y[mi]; // PTAC
537 }
538 if(verbose>5) {
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]);
544 }
545 }
546 /* Make a copy of A matrix for later use */
547 for(int i=0; i<llsq_n*llsq_m; i++) matbackup[i]=llsq_mat[i];
548 /* Apply data weights */
549 if(tacIsWeighted(&ttac0)) llsqWght(llsq_n, llsq_m, NULL, llsq_mat, b, ttac0.w);
550 /* Set istate vector to indicate that all parameters are non-bound */
551 istate[llsq_n]=0; for(int ni=0; ni<llsq_n; ni++) istate[ni]=1+ni;
552 /* Set parameter limits */
553 if(vb_model==VB_FITTED) {bl[llsq_n-1]=0.0; bu[llsq_n-1]=1.0;}
554 switch(model) {
555 case MODEL_K1:
556 bl[0]=0.0; bu[0]=10.0;
557 break;
558 case MODEL_K2:
559 bl[0]=0.0; bu[0]=10.0;
560 bl[1]=0.0; bu[1]=10.0;
561 break;
562 case MODEL_K3:
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;
566 break;
567 case MODEL_K4:
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;
572 break;
573 case MODEL_K5S:
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;
579 break;
580 case MODEL_K5P:
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;
586 break;
587 case MODEL_K6S:
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;
594 break;
595 case MODEL_K6P:
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;
602 break;
603 default: exit(1);
604 }
605 /* Set max iterations */
606 iterNr=3*llsq_n;
607 /* Compute BVLS */
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");
611 r2=w[0];
612 if(ret!=0) {
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;
616 r2=0.0;
617 }
618 if(verbose>4) {
619 printf("solution_vector: %d", istate[0]);
620 for(int ni=1; ni<llsq_n; ni++) printf(", %d", istate[ni]);
621 printf("\n");
622 }
623 for(int ni=0; ni<llsq_n; ni++) lp.r[ti].p[ni]=x[ni];
624 lp.r[ti].wss=r2;
625 lp.r[ti].dataNr=tacWSampleNr(&ttac0);
626 lp.r[ti].fitNr=llsq_n;
627
628 /* Compute fitted TAC (into ttac1 since it is otherwise not needed) */
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];
632 }
633
634 } // next TAC
635
636 /* Free allocated memory */
637 free(llsq_mat);
638
639 } else {
640
641 fprintf(stderr, "Error: selected method not available.");
642 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
643 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
644 parFree(&lp);
645 return(1);
646
647 }
648
649
650 /*
651 * Print original LLSQ parameters on screen
652 */
653 if(verbose>1 && lp.tacNr<50)
654 parWrite(&lp, stdout, PAR_FORMAT_TSV_UK /*PAR_FORMAT_RES*/, 0, &status);
655
656
657 /*
658 * Save original LLSQ results, if requested
659 */
660 if(lpfile[0]) {
661 if(verbose>1) printf("writing %s\n", lpfile);
663 if(verbose>2) printf("result file format := %s\n", parFormattxt(lp.format));
665 FILE *fp; fp=fopen(lpfile, "w");
666 if(fp==NULL) {
667 fprintf(stderr, "Error: cannot open file for writing parameter file.\n");
668 ret=TPCERROR_FAIL;
669 } else {
670 ret=parWrite(&lp, fp, PAR_FORMAT_UNKNOWN, 1, &status);
671 fclose(fp);
672 if(ret!=TPCERROR_OK) fprintf(stderr, "Error: %s\n", errorMsg(status.error));
673 }
674 if(ret!=TPCERROR_OK) {
675 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
676 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
677 parFree(&lp);
678 return(11);
679 }
680 if(verbose>0) printf("Results saved in %s.\n", lpfile);
681 }
682
683
684
685 /*
686 * Prepare the room for CM parameters.
687 * Solve CM parameters from LLSQ parameters.
688 */
689 if(verbose>1) printf("initializing CM parameter data\n");
690 PAR cmpar; parInit(&cmpar);
691 ret=parAllocateWithTAC(&cmpar, &ttac0, MAX_LLSQ_N+4, &status);
692 if(ret!=TPCERROR_OK) {
693 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
694 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
695 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
696 parFree(&lp);
697 return(21);
698 }
699 /* Copy titles & file names */
700 {
701 int i;
702 char buf[256];
703 time_t t=time(NULL);
704 /* set program name */
705 tpcProgramName(argv[0], 1, 1, buf, 256);
706 iftPut(&cmpar.h, "program", buf, 0, NULL);
707 /* set file names */
708 iftPut(&cmpar.h, "plasmafile", ptacfile, 0, NULL);
709 iftPut(&cmpar.h, "datafile", ttacfile, 0, NULL);
710 /* Fit method */
711 iftPut(&cmpar.h, "fitmethod", method_str[method], 0, NULL);
712 /* Model */
713 iftPut(&cmpar.h, "model", model_str[model], 0, NULL);
714 /* Set current time to results */
715 iftPut(&cmpar.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
716 /* Set fit times for each TAC */
717 for(i=0; i<cmpar.tacNr; i++) {
718 cmpar.r[i].dataNr=fitSampleNr;
719 cmpar.r[i].start=0.0;
720 cmpar.r[i].end=fitdur;
721 /* and nr of fitted parameters */
722 cmpar.r[i].fitNr=llsq_n;
723 }
724 /* Set the parameter names and units */
725 cmpar.parNr=llsq_n;
726 double k1, k2, k3, k4, k5, k6, k1k2, k3k4, k5k6, Ki, Vt, Vp;
727 const double llimit=1.0E-06; // set to zero or NaN if lower than this
728 switch(model) {
729 case MODEL_K1:
730 i=0; strcpy(cmpar.n[i].name,"K1"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
731 i=1; strcpy(cmpar.n[i].name,"Vp"); cmpar.n[i].unit=UNIT_PERCENTAGE;
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;
736 }
737 break;
738 case MODEL_K2:
739 i=0; strcpy(cmpar.n[i].name,"K1"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
740 i=1; strcpy(cmpar.n[i].name,"k2"); //cmpar.n[i].unit=UNIT_PER_MIN;
741 i=2; strcpy(cmpar.n[i].name,"K1/k2"); //cmpar.n[i].unit=UNIT_ML_PER_ML;
742 i=3; strcpy(cmpar.n[i].name,"Vp"); cmpar.n[i].unit=UNIT_PERCENTAGE;
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];
746 k2=lp.r[ti].p[1];
747 if(k1<llimit) k1=k2=0.0;
748 if(k2<llimit) k2=0.0;
749 k1k2=k1/k2;
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;
754 }
755 cmpar.parNr+=1;
756 break;
757 case MODEL_K3:
758 i=0; strcpy(cmpar.n[i].name,"K1"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
759 i=1; strcpy(cmpar.n[i].name,"k2"); //cmpar.n[i].unit=UNIT_PER_MIN;
760 i=2; strcpy(cmpar.n[i].name,"k3"); //cmpar.n[i].unit=UNIT_PER_MIN;
761 i=3; strcpy(cmpar.n[i].name,"K1/k2"); //cmpar.n[i].unit=UNIT_ML_PER_ML;
762 i=4; strcpy(cmpar.n[i].name,"Ki"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
763 i=5; strcpy(cmpar.n[i].name,"Vp"); cmpar.n[i].unit=UNIT_PERCENTAGE;
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;
768 k3=lp.r[ti].p[1]-k2;
769 if(k1<llimit) k1=k2=k3=0.0;
770 if(k2<llimit) k2=k3=0.0;
771 if(k3<llimit) k3=0.0;
772 k1k2=k1/k2;
773 Ki=k1*k3/(k2+k3);
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;
780 }
781 cmpar.parNr+=2;
782 break;
783 case MODEL_K4:
784 i=0; strcpy(cmpar.n[i].name,"K1"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
785 i=1; strcpy(cmpar.n[i].name,"k2"); //cmpar.n[i].unit=UNIT_PER_MIN;
786 i=2; strcpy(cmpar.n[i].name,"k3"); //cmpar.n[i].unit=UNIT_PER_MIN;
787 i=3; strcpy(cmpar.n[i].name,"k4"); //cmpar.n[i].unit=UNIT_PER_MIN;
788 i=4; strcpy(cmpar.n[i].name,"K1/k2"); //cmpar.n[i].unit=UNIT_ML_PER_ML;
789 i=5; strcpy(cmpar.n[i].name,"k3/k4"); //cmpar.n[i].unit=UNIT_UNITLESS;
790 i=6; strcpy(cmpar.n[i].name,"Vt"); //cmpar.n[i].unit=UNIT_ML_PER_ML;
791 i=7; strcpy(cmpar.n[i].name,"Vp"); cmpar.n[i].unit=UNIT_PERCENTAGE;
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;
802 k1k2=k1/k2;
803 k3k4=k3/k4;
804 Vt=k1k2*(1.0+k3k4);
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;
813 }
814 cmpar.parNr+=3;
815 break;
816 case MODEL_K5S:
817 i=0; strcpy(cmpar.n[i].name,"K1"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
818 i=1; strcpy(cmpar.n[i].name,"k2"); //cmpar.n[i].unit=UNIT_PER_MIN;
819 i=2; strcpy(cmpar.n[i].name,"k3"); //cmpar.n[i].unit=UNIT_PER_MIN;
820 i=3; strcpy(cmpar.n[i].name,"k4"); //cmpar.n[i].unit=UNIT_PER_MIN;
821 i=4; strcpy(cmpar.n[i].name,"k5"); //cmpar.n[i].unit=UNIT_PER_MIN;
822 i=5; strcpy(cmpar.n[i].name,"K1/k2"); //cmpar.n[i].unit=UNIT_ML_PER_ML;
823 i=6; strcpy(cmpar.n[i].name,"k3/k4"); //cmpar.n[i].unit=UNIT_UNITLESS;
824 i=7; strcpy(cmpar.n[i].name,"Ki"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
825 i=8; strcpy(cmpar.n[i].name,"Vp"); cmpar.n[i].unit=UNIT_PERCENTAGE;
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;
838 k1k2=k1/k2;
839 k3k4=k3/k4;
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;
850 }
851 cmpar.parNr+=3;
852 break;
853 case MODEL_K5P:
854 i=0; strcpy(cmpar.n[i].name,"K1"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
855 i=1; strcpy(cmpar.n[i].name,"k2"); //cmpar.n[i].unit=UNIT_PER_MIN;
856 i=2; strcpy(cmpar.n[i].name,"k3"); //cmpar.n[i].unit=UNIT_PER_MIN;
857 i=3; strcpy(cmpar.n[i].name,"k4"); //cmpar.n[i].unit=UNIT_PER_MIN;
858 i=4; strcpy(cmpar.n[i].name,"k5"); //cmpar.n[i].unit=UNIT_PER_MIN;
859 i=5; strcpy(cmpar.n[i].name,"K1/k2"); //cmpar.n[i].unit=UNIT_ML_PER_ML;
860 i=6; strcpy(cmpar.n[i].name,"k3/k4"); //cmpar.n[i].unit=UNIT_UNITLESS;
861 i=7; strcpy(cmpar.n[i].name,"Ki"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
862 i=8; strcpy(cmpar.n[i].name,"Vp"); cmpar.n[i].unit=UNIT_PERCENTAGE;
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;
875 k1k2=k1/k2;
876 k3k4=k3/k4;
877 Ki=k1*k5/(k2+k5);
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;
887 }
888 cmpar.parNr+=3;
889 break;
890 case MODEL_K6S:
891 i=0; strcpy(cmpar.n[i].name,"K1"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
892 i=1; strcpy(cmpar.n[i].name,"k2"); //cmpar.n[i].unit=UNIT_PER_MIN;
893 i=2; strcpy(cmpar.n[i].name,"k3"); //cmpar.n[i].unit=UNIT_PER_MIN;
894 i=3; strcpy(cmpar.n[i].name,"k4"); //cmpar.n[i].unit=UNIT_PER_MIN;
895 i=4; strcpy(cmpar.n[i].name,"k5"); //cmpar.n[i].unit=UNIT_PER_MIN;
896 i=5; strcpy(cmpar.n[i].name,"k6"); //cmpar.n[i].unit=UNIT_PER_MIN;
897 i=6; strcpy(cmpar.n[i].name,"K1/k2"); //cmpar.n[i].unit=UNIT_ML_PER_ML;
898 i=7; strcpy(cmpar.n[i].name,"k3/k4"); //cmpar.n[i].unit=UNIT_UNITLESS;
899 i=8; strcpy(cmpar.n[i].name,"k5/k6"); //cmpar.n[i].unit=UNIT_UNITLESS;
900 i=9; strcpy(cmpar.n[i].name,"Vt"); //cmpar.n[i].unit=UNIT_ML_PER_ML;
901 i=10; strcpy(cmpar.n[i].name,"Vp"); cmpar.n[i].unit=UNIT_PERCENTAGE;
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;
916 k1k2=k1/k2;
917 k3k4=k3/k4;
918 k5k6=k5/k6;
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;
931 }
932 cmpar.parNr+=4;
933 break;
934 case MODEL_K6P:
935 i=0; strcpy(cmpar.n[i].name,"K1"); //cmpar.n[i].unit=UNIT_ML_PER_ML_MIN;
936 i=1; strcpy(cmpar.n[i].name,"k2"); //cmpar.n[i].unit=UNIT_PER_MIN;
937 i=2; strcpy(cmpar.n[i].name,"k3"); //cmpar.n[i].unit=UNIT_PER_MIN;
938 i=3; strcpy(cmpar.n[i].name,"k4"); //cmpar.n[i].unit=UNIT_PER_MIN;
939 i=4; strcpy(cmpar.n[i].name,"k5"); //cmpar.n[i].unit=UNIT_PER_MIN;
940 i=5; strcpy(cmpar.n[i].name,"k6"); //cmpar.n[i].unit=UNIT_PER_MIN;
941 i=6; strcpy(cmpar.n[i].name,"K1/k2"); //cmpar.n[i].unit=UNIT_ML_PER_ML;
942 i=7; strcpy(cmpar.n[i].name,"k3/k4"); //cmpar.n[i].unit=UNIT_UNITLESS;
943 i=8; strcpy(cmpar.n[i].name,"k5/k6"); //cmpar.n[i].unit=UNIT_UNITLESS;
944 i=9; strcpy(cmpar.n[i].name,"Vt"); //cmpar.n[i].unit=UNIT_ML_PER_ML;
945 i=10; strcpy(cmpar.n[i].name,"Vp"); cmpar.n[i].unit=UNIT_PERCENTAGE;
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;
952 k3=k4=k5=k6=nan(""); // cannot be solved
953 k1k2=k1/k2;
954 k3k4=k5k6=nan(""); // cannot be solved
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;
961 }
962 cmpar.parNr+=4;
963 break;
964 default: exit(1);
965 }
966 /* Copy R^2 etc */
967 for(int ti=0; ti<cmpar.tacNr; ti++) {
968 cmpar.r[ti].wss=lp.r[ti].wss;
969 cmpar.r[ti].dataNr=lp.r[ti].dataNr;
970 cmpar.r[ti].fitNr=lp.r[ti].fitNr;
971 }
972 }
973
974 /*
975 * Print CM parameters on screen
976 */
977 if(verbose>0 && lp.tacNr<80)
978 parWrite(&cmpar, stdout, PAR_FORMAT_TSV_UK /*PAR_FORMAT_RES*/, 0, &status);
979
980 /*
981 * Save CM results
982 */
983 {
984 if(verbose>1) printf("writing %s\n", resfile);
985 cmpar.format=parFormatFromExtension(resfile);
986 if(verbose>2) printf("result file format := %s\n", parFormattxt(cmpar.format));
988 FILE *fp; fp=fopen(resfile, "w");
989 if(fp==NULL) {
990 fprintf(stderr, "Error: cannot open file for writing parameter file.\n");
991 ret=TPCERROR_FAIL;
992 } else {
993 ret=parWrite(&cmpar, fp, PAR_FORMAT_UNKNOWN, 1, &status);
994 fclose(fp);
995 if(ret!=TPCERROR_OK) fprintf(stderr, "Error: %s\n", errorMsg(status.error));
996 }
997 if(ret!=TPCERROR_OK) {
998 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
999 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
1000 parFree(&lp); parFree(&cmpar);
1001 return(22);
1002 }
1003 if(verbose>0) printf("Results saved in %s.\n", resfile);
1004 }
1005
1006
1007
1008 /*
1009 * SVG plot of fitted and original data
1010 */
1011 if(svgfile[0]) {
1012
1013 if(verbose>1) printf("saving SVG plot\n");
1014 int i;
1015 char buf[128];
1016 sprintf(buf, "%s %s", method_str[method], model_str[model]);
1017 i=iftFindKey(&ttac0.h, "studynr", 0);
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);
1021 if(ret!=TPCERROR_OK) {
1022 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
1023 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
1024 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
1025 parFree(&lp); parFree(&cmpar);
1026 return(31);
1027 }
1028 if(verbose>0) printf("Plots written in %s.\n", svgfile);
1029 }
1030
1031
1032 /*
1033 * Save fitted TTACs
1034 */
1035 if(fitfile[0]) {
1036 if(verbose>1) printf("writing %s\n", fitfile);
1037 FILE *fp; fp=fopen(fitfile, "w");
1038 if(fp==NULL) {
1039 fprintf(stderr, "Error: cannot open file for writing fitted TTACs.\n");
1040 ret=TPCERROR_FAIL;
1041 } else {
1042 ret=tacWrite(&ttac1, fp, TAC_FORMAT_UNKNOWN, 1, &status);
1043 fclose(fp);
1044 if(ret!=TPCERROR_OK) fprintf(stderr, "Error: %s\n", errorMsg(status.error));
1045 }
1046 if(ret!=TPCERROR_OK) {
1047 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
1048 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
1049 parFree(&lp); parFree(&cmpar);
1050 return(32);
1051 }
1052 if(verbose>0) printf("fitted TACs saved in %s.\n", fitfile);
1053 }
1054
1055
1056 tacFree(&ttac0); tacFree(&ttac1); tacFree(&ttac2); tacFree(&ttac3);
1057 tacFree(&input0); tacFree(&input1); tacFree(&input2); tacFree(&input3);
1058 parFree(&lp); parFree(&cmpar);
1059
1060 return(0);
1061}
1062/*****************************************************************************/
1063
1064/*****************************************************************************/
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...
Definition bvls.c:32
int llsqWght(int N, int M, double **A, double *a, double *b, double *weight)
Definition bvls.c:425
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 iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
Definition ift.c:63
int iftFindKey(IFT *ift, const char *key, int start_index)
Definition iftfind.c:30
int liIntegrate(double *x, double *y, const int nr, double *yi, const int se, const int verbose)
Linear integration of TAC with trapezoidal method.
Definition integrate.c:33
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
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *wp, double *zzp, int *indexp)
Definition nnls.c:43
int nnlsWght(int N, int M, double **A, double *b, double *weight)
Definition nnls.c:259
void parFree(PAR *par)
Definition par.c:75
void parInit(PAR *par)
Definition par.c:25
char * parFormattxt(parformat c)
Definition pario.c:59
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
Definition pario.c:148
int parFormatFromExtension(const char *s)
Definition pario.c:102
int parAllocateWithTAC(PAR *par, TAC *tac, int parNr, TPCSTATUS *status)
Allocate PAR based on data in TAC.
Definition partac.c:90
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
Definition proginfo.c:406
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:169
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:339
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:114
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
char * errorMsg(tpcerror e)
Definition statusmsg.c:68
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
char * value
Definition tpcift.h:37
IFT_ITEM * item
Definition tpcift.h:57
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 fitNr
Definition tpcpar.h:58
int dataNr
Definition tpcpar.h:62
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
IFT h
Optional (but often useful) header information.
Definition tpctac.h:141
double * w
Definition tpctac.h:111
int isframe
Definition tpctac.h:95
TACC * c
Definition tpctac.h:117
weights weighting
Definition tpctac.h:115
unit tunit
Definition tpctac.h:109
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 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
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 tacReadModelingData(const char *tissuefile, const char *inputfile1, const char *inputfile2, const char *inputfile3, double *fitdur, int cutInput, int *fitSampleNr, TAC *tis, TAC *inp, TPCSTATUS *status)
Read tissue and input data for modelling.
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
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.
@ 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 libtpcpar.
@ 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 library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28
Header file for libtpctacmod.