TPCCLIB
Loading...
Searching...
No Matches
llsqrk2.c
Go to the documentation of this file.
1
9/*****************************************************************************/
10#include "tpcclibConfig.h"
11/*****************************************************************************/
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <math.h>
16/*****************************************************************************/
17#include "tpcextensions.h"
18#include "tpcift.h"
19#include "tpctac.h"
20#include "tpcpar.h"
21#include "tpcli.h"
22#include "tpctacmod.h"
23#include "tpclinopt.h"
24/*****************************************************************************/
25
26/*****************************************************************************/
27static char *info[] = {
28 "LLSQ fitting of reference tissue input model in case of one tissue",
29 "compartment. Compartmental model is transformed into general linear least",
30 "squares functions.",
31 " ",
32 "Radioactivity concentration in region(s)-of-interest is given in TTAC file;",
33 "data must be corrected for physical decay.",
34 "Radioactivity concentration in reference region (RTAC) is given in separate",
35 "file, or as name or number of the reference region inside the TTAC file.",
36 "Sample times must be in minutes in all data files, unless specified inside",
37 "the files. TTAC file should include weights.",
38 " ",
39 "Usage: @P [options] TTAC RTAC results",
40 " ",
41 "Options:",
42 " -end=<Fit end time (min)>",
43 " Use data from 0 to end time; by default, model is fitted to all frames.",
44 " -w1 | -wf",
45 " Sample weights are set to 1 (-w1) or to frame lengths (-wf);",
46 " by default weights in TTAC file are used, if available.",
47 " -model=<R1 | R2>",
48 " Use two-parameter model (R1, default), or three-parameter model (R2).",
49/*
50 " -k2r=<value>",
51 " k2r is fixed to given value, three-parameter model is set, and BVLS",
52 " is used instead of NNLS.",
53 " HIDDEN because does not yet work correctly but fixed R1*k2r instead.",
54*/
55 " -svg=<Filename>",
56 " Fitted and measured TACs are plotted in specified SVG file.",
57 " -fit=<Filename>",
58 " Fitted regional TTACs are written in specified file.",
59 " -stdoptions", // List standard options like --help, -v, etc
60 " ",
61 "References:",
62 "1. Blomqvist G. On the construction of functional maps in positron emission",
63 " tomography. J Cereb Blood Flow Metab 1984;4:629-632.",
64 "2. Gjedde A, Wong DF. Modeling neuroreceptor binding of radioligands",
65 " in vivo. In: Quantitative imaging: neuroreceptors, neurotransmitters,",
66 " and enzymes. (Eds. Frost JJ, Wagner HM Jr). Raven Press, 1990, 51-79.",
67 "3. Lawson CL & Hanson RJ. Solving least squares problems.",
68 " Prentice-Hall, 1974.",
69 " ",
70 "See also: lhsol, bfmsrtm, taccbv",
71 " ",
72 "Keywords: TAC, modelling, compartmental model, LLSQ",
73 0};
74/*****************************************************************************/
75
76/*****************************************************************************/
77/* Turn on the globbing of the command line, since it is disabled by default in
78 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
79 In Unix&Linux wildcard command line processing is enabled by default. */
80/*
81#undef _CRT_glob
82#define _CRT_glob -1
83*/
84int _dowildcard = -1;
85/*****************************************************************************/
86
87/*****************************************************************************/
88#define MAX_LLSQ_N 3
89enum {METHOD_UNKNOWN, METHOD_NNLS, METHOD_BVLS};
90static char *method_str[] = {"unknown", "NNLS", "BVLS", 0};
91/*****************************************************************************/
92enum {MODEL_UNKNOWN, MODEL_R1, MODEL_R1R2};
93static char *model_str[] = {"unknown", "R1", "R1R2", 0};
94/*****************************************************************************/
95
96/*****************************************************************************/
100int main(int argc, char **argv)
101{
102 int ai, help=0, version=0, verbose=1;
103 char ttacfile[FILENAME_MAX], rtacfile[FILENAME_MAX], resfile[FILENAME_MAX],
104 fitfile[FILENAME_MAX], svgfile[FILENAME_MAX];
105 int weights=0; // 0=default, 1=no weighting, 2=frequency
106 double fitdur=nan("");
107 double fixed_k2r=nan("");
108 int method=METHOD_UNKNOWN;
109 int model=MODEL_UNKNOWN;
110 int ret;
111
112 /*
113 * Get arguments
114 */
115 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
116 ttacfile[0]=rtacfile[0]=resfile[0]=fitfile[0]=svgfile[0]=(char)0;
117 /* Options */
118 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
119 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
120 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
121 if(strncasecmp(cptr, "SVG=", 4)==0) {
122 strlcpy(svgfile, cptr+4, FILENAME_MAX); if(strlen(svgfile)>0) continue;
123 } else if(strncasecmp(cptr, "FIT=", 4)==0) {
124 strlcpy(fitfile, cptr+4, FILENAME_MAX); if(strlen(fitfile)>0) continue;
125 } else if(strcasecmp(cptr, "W1")==0) {
126 weights=1; continue;
127 } else if(strcasecmp(cptr, "WF")==0) {
128 weights=2; continue;
129 } else if(strncasecmp(cptr, "END=", 4)==0) {
130 if(atofCheck(cptr+4, &fitdur)==0) {
131 if(fitdur<=0.0) fitdur=1.0E+99;
132 continue;
133 } else {
134 fprintf(stderr, "Error: invalid fit time '%s'.\n", argv[ai]);
135 return(1);
136 }
137 } else if(strncasecmp(cptr, "K2R=", 4)==0) {
138 if(atofCheck(cptr+4, &fixed_k2r)==0 && fixed_k2r>0.0) continue;
139 fprintf(stderr, "Error: invalid k2r '%s'.\n", argv[ai]); return(1);
140 } else if(strcasecmp(cptr, "NNLS")==0) {
141 method=METHOD_NNLS; continue;
142 } else if(strcasecmp(cptr, "BVLS")==0) {
143 method=METHOD_BVLS; continue;
144 } else if(strncasecmp(cptr, "MODEL=", 6)==0) {
145 cptr+=6;
146 if(strcasecmp(cptr, "R1") ==0) {model=MODEL_R1; continue;}
147 if(strcasecmp(cptr, "R2") ==0) {model=MODEL_R1R2; continue;}
148 if(strcasecmp(cptr, "R1R2")==0) {model=MODEL_R1R2; continue;}
149 fprintf(stderr, "Error: invalid model '%s'.\n", cptr);
150 return(1);
151 }
152 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
153 return(1);
154 } else break;
155
156 TPCSTATUS status; statusInit(&status);
157 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
158 status.verbose=verbose-3;
159
160 /* Print help or version? */
161 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
162 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
163 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
164
165 /* Process other arguments, starting from the first non-option */
166 if(ai<argc) strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
167 if(ai<argc) strlcpy(rtacfile, argv[ai++], FILENAME_MAX);
168 if(ai<argc) strlcpy(resfile, argv[ai++], FILENAME_MAX);
169 if(ai<argc) {
170 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
171 return(1);
172 }
173 /* Did we get all the information that we need? */
174 if(!resfile[0]) {
175 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
176 return(1);
177 }
178 /* Set default parameter values, if not set by user */
179 if(isnan(fitdur)) fitdur=1.0E+99;
180 if(method==METHOD_UNKNOWN) method=METHOD_NNLS;
181 if(model==MODEL_UNKNOWN) model=MODEL_R1;
182 /* If user fixed k2r, then model should include it */
183 if(!isnan(fixed_k2r) && model==MODEL_R1) {
184 model=MODEL_R1R2;
185 }
186 /* If user fixed k2r, then method should allow it */
187 if(!isnan(fixed_k2r) && method==METHOD_NNLS) {
188 method=METHOD_BVLS;
189 }
190
191
192 /* In verbose mode print arguments and options */
193 if(verbose>1) {
194 printf("ttacfile := %s\n", ttacfile);
195 printf("rtacfile := %s\n", rtacfile);
196 printf("resfile := %s\n", resfile);
197 printf("fitfile := %s\n", fitfile);
198 printf("svgfile := %s\n", svgfile);
199 printf("method := %s\n", method_str[method]);
200 printf("model := %s\n", model_str[model]);
201 printf("required_fittime := %g min\n", fitdur);
202 printf("weights := %d\n", weights);
203 if(!isnan(fixed_k2r)) printf("fixed_k2r := %g\n", fixed_k2r);
204 fflush(stdout);
205 }
206
207
208
209 /*
210 * Read TAC files
211 */
212 TAC ttac; tacInit(&ttac);
213
214 /* Read tissue TAC file */
215 if(verbose>1) printf("reading %s\n", ttacfile);
216 ret=tacRead(&ttac, ttacfile, &status);
217 if(ret!=TPCERROR_OK) {
218 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
219 tacFree(&ttac); return(2);
220 }
221 if(verbose>2) {
222 printf("fileformat := %s\n", tacFormattxt(ttac.format));
223 printf("tacNr := %d\n", ttac.tacNr);
224 printf("sampleNr := %d\n", ttac.sampleNr);
225 printf("xunit := %s\n", unitName(ttac.tunit));
226 printf("yunit := %s\n", unitName(ttac.cunit));
227 printf("midxrange := %g - %g\n", ttac.x[0], ttac.x[ttac.sampleNr-1]);
228 }
229 if(tacVerifyTimeOrder(&ttac, &status)) {
230 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
231 tacFree(&ttac); return(2);
232 }
233
234 /* Read reference tissue TAC file */
235 if(verbose>1) {printf("reading %s\n", rtacfile); fflush(stdout);}
236 int refindex;
237 ret=tacReadReference(&ttac, rtacfile, NULL, &refindex, &status);
238 if(ret==0) {
239 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
240 tacFree(&ttac); return(2);
241 }
242 if(ret>1) {
243 fprintf(stderr, "Warning: several reference regions found: %s selected.\n",
244 ttac.c[refindex].name);
245 } else if(verbose>1) {
246 printf("reference_region := %s\n", ttac.c[refindex].name); fflush(stderr);
247 }
248
249 /* Try to fix missing values, if any */
250 if(tacFixNaNs(&ttac)) {
251 fprintf(stderr, "Error: missing sample(s) in data.\n"); fflush(stderr);
252 tacFree(&ttac); return(2);
253 }
254
255 /* Convert sample times to minutes */
256 if(tacXUnitConvert(&ttac, UNIT_MIN, &status)) {
257 fprintf(stderr, "Warning: %s\n", errorMsg(status.error)); fflush(stderr);
258 // Do not stop in error, assume that user has set units correctly
259 }
260
261 /* Remove small frame overlaps and gaps */
262 if(tacCorrectFrameOverlap(&ttac, &status)) {
263 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
264 tacFree(&ttac); return(2);
265 }
266 if(verbose>2) {
267 printf("fileformat := %s\n", tacFormattxt(ttac.format));
268 printf("tacNr := %d\n", ttac.tacNr);
269 printf("sampleNr := %d\n", ttac.sampleNr);
270 printf("xunit := %s\n", unitName(ttac.tunit));
271 printf("yunit := %s\n", unitName(ttac.cunit));
272 printf("midxrange := %g - %g\n", ttac.x[0], ttac.x[ttac.sampleNr-1]);
273 }
274
275
276
277 /* Add data weights, if requested */
278 if(weights==1) {
280 for(int i=0; i<ttac.sampleNr; i++) ttac.w[i]=1.0;
281 } else if(weights==2) {
282 if(tacWByFreq(&ttac, ISOTOPE_UNKNOWN, &status)!=TPCERROR_OK) {
283 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
284 tacFree(&ttac); return(2);
285 }
286 } else if(!tacIsWeighted(&ttac)) {
287 if(verbose>0) fprintf(stderr, "Warning: data is not weighted.\n");
288 }
289
290 /* Set fit duration */
291 int origSampleNr=ttac.sampleNr;
292 double starttime=0.0;
293 double endtime=fitdur;
294 int fitSampleNr=tacFittime(&ttac, &starttime, &endtime, NULL, NULL, &status);
295 if(fitSampleNr<0) {
296 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
297 tacFree(&ttac); return(2);
298 } else if(fitSampleNr<4) {
299 fprintf(stderr, "Error: too few data points for a decent fit.\n");
300 tacFree(&ttac); return(2);
301 }
302 if(verbose>1) {
303 printf("starttime := %g\n", starttime);
304 printf("endtime := %g\n", endtime);
305 //printf("first := %d\n", first);
306 //printf("last := %d\n", last);
307 printf("fitSampleNr := %d\n", fitSampleNr);
308 printf("origSampleNr := %d\n", origSampleNr);
309 fflush(stdout);
310 }
311 fitdur=endtime;
312 ttac.sampleNr=fitSampleNr;
313
314
315
316 /*
317 * Calculate AUC curves
318 */
319 TAC auc; tacInit(&auc);
320 if(tacInterpolate(&ttac, &ttac, NULL, &auc, NULL, &status)!=TPCERROR_OK) {
321 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
322 tacFree(&ttac); return(3);
323 }
324 if(verbose>3) {
325 printf("\nAUC 0-%g:\n", auc.x[fitSampleNr-1]);
326 for(int ti=0; ti<auc.tacNr; ti++)
327 printf(" %s\t%g\n", auc.c[ti].name, auc.c[ti].y[fitSampleNr-1]);
328 fflush(stdout);
329 }
330
331 /*
332 * Set model-dependent parameters
333 */
334 int llsq_n=0;
335 switch(model) {
336 case MODEL_R1: llsq_n=2; break;
337 case MODEL_R1R2: llsq_n=3; break;
338 default: exit(1);
339 }
340 if(verbose>2) printf("llsq_n := %d\n", llsq_n);
341
342
343 /*
344 * Prepare the room for LLSQ parameters
345 */
346 if(verbose>1) printf("initializing LLSQ parameter data\n");
347 PAR lp; parInit(&lp);
348 ret=parAllocateWithTAC(&lp, &ttac, MAX_LLSQ_N, &status);
349 if(ret!=TPCERROR_OK) {
350 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
351 tacFree(&ttac); tacFree(&auc); return(4);
352 }
353 /* Copy titles & file names */
354 {
355 int i;
356 char buf[256];
357 time_t t=time(NULL);
358 /* set program name */
359 tpcProgramName(argv[0], 1, 1, buf, 256);
360 iftPut(&lp.h, "program", buf, 0, NULL);
361 /* set file names */
362 iftPut(&lp.h, "datafile", ttacfile, 0, NULL);
363 iftPut(&lp.h, "refname", ttac.c[refindex].name, 0, NULL);
364 /* Fit method */
365 iftPut(&lp.h, "fitmethod", method_str[method], 0, NULL);
366 /* Model */
367 iftPut(&lp.h, "model", model_str[model], 0, NULL);
368 /* Set current time to results */
369 iftPut(&lp.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
370 /* Set fit times for each TAC */
371 for(i=0; i<lp.tacNr; i++) {
372 lp.r[i].dataNr=fitSampleNr;
373 lp.r[i].start=0.0;
374 lp.r[i].end=fitdur;
375 /* and nr of fitted parameters */
376 lp.r[i].fitNr=llsq_n;
377 }
378 /* Set the parameter names and units */
379 for(i=0; i<MAX_LLSQ_N; i++) {
380 sprintf(lp.n[i].name, "P%d", 1+i);
381 }
382 lp.parNr=llsq_n;
383 }
384
385
386 if(method==METHOD_NNLS) {
387
388 /*
389 * Allocate memory required by NNLS
390 */
391 if(verbose>1) printf("allocating memory for NNLS\n");
392 int llsq_m=fitSampleNr;
393 double *llsq_mat=(double*)malloc((2*llsq_n*llsq_m)*sizeof(double));
394 if(llsq_mat==NULL) {
395 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
396 tacFree(&ttac); tacFree(&auc); parFree(&lp); return(5);
397 }
398 double **llsq_a=(double**)malloc(llsq_n*sizeof(double*));
399 if(llsq_a==NULL) {
400 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
401 tacFree(&ttac); tacFree(&auc); parFree(&lp); free(llsq_mat); return(5);
402 return(5);
403 }
404 for(int ni=0; ni<llsq_n; ni++) llsq_a[ni]=llsq_mat+ni*llsq_m;
405 double r2, llsq_b[llsq_m], llsq_x[llsq_n], llsq_wp[llsq_n], llsq_zz[llsq_m];
406 int indexp[llsq_n];
407 double *matbackup=llsq_mat+llsq_n*llsq_m;
408
409 /*
410 * Fit each regional TTAC (except reference TAC)
411 */
412 if(verbose>1) printf("solving NNLS\n");
413 for(int ti=0; ti<ttac.tacNr; ti++) if(ti!=refindex) {
414
415 if(verbose>2 && ttac.tacNr>2) {
416 printf("Region %d %s\n", 1+ti, ttac.c[ti].name); fflush(stdout);}
417
418 /* Setup data matrix A and vector B */
419 for(int mi=0; mi<llsq_m; mi++)
420 llsq_b[mi]=ttac.c[ti].y[mi];
421 if(model==MODEL_R1) {
422 for(int mi=0; mi<llsq_m; mi++) {
423 llsq_mat[mi]=ttac.c[refindex].y[mi]; // RTAC
424 llsq_mat[mi+llsq_m]=auc.c[refindex].y[mi]-auc.c[ti].y[mi]; // RTAC - TTAC integral
425 }
426 } else {
427 for(int mi=0; mi<llsq_m; mi++) {
428 llsq_mat[mi]=ttac.c[refindex].y[mi]; // RTAC
429 llsq_mat[mi+llsq_m]=auc.c[refindex].y[mi]; // RTAC integral
430 llsq_mat[mi+2*llsq_m]=-auc.c[ti].y[mi]; // -TTAC integral
431 }
432 }
433 if(verbose>10) {
434 printf("Matrix A and vector B:\n");
435 for(int mi=0; mi<llsq_m; mi++) {
436 printf("%.2e", llsq_a[0][mi]);
437 for(int ni=1; ni<llsq_n; ni++) printf(", %.2e", llsq_a[ni][mi]);
438 printf("; %.3e\n", llsq_b[mi]);
439 }
440 }
441 /* Make a copy of A matrix for later use */
442 for(int i=0; i<llsq_n*llsq_m; i++) matbackup[i]=llsq_mat[i];
443
444 /* Apply data weights */
445 if(tacIsWeighted(&ttac)) nnlsWght(llsq_n, llsq_m, llsq_a, llsq_b, ttac.w);
446 /* Compute NNLS */
447 if(verbose>3) printf("starting NNLS...\n");
448 ret=nnls(llsq_a, llsq_m, llsq_n, llsq_b, llsq_x, &r2, llsq_wp, llsq_zz, indexp);
449 if(verbose>3) printf(" ... done.\n");
450 if(ret>1) {
451 fprintf(stderr, "Warning: no NNLS solution for %s\n", ttac.c[ti].name);
452 for(int ni=0; ni<llsq_n; ni++) llsq_x[ni]=0.0;
453 r2=0.0;
454 } else if(ret==1) {
455 fprintf(stderr, "Warning: NNLS iteration max exceeded for %s\n", ttac.c[ti].name);
456 }
457 if(verbose>5) {
458 printf("solution_vector: %g", llsq_wp[0]);
459 for(int ni=1; ni<llsq_n; ni++) printf(", %g", llsq_wp[ni]);
460 printf("\n");
461 }
462 for(int ni=0; ni<llsq_n; ni++) lp.r[ti].p[ni]=llsq_x[ni];
463 lp.r[ti].wss=r2;
464 lp.r[ti].dataNr=tacWSampleNr(&ttac);
465 lp.r[ti].fitNr=llsq_n;
466
467 /* Compute fitted TAC (into auc since it is otherwise not needed) */
468 for(int mi=0; mi<llsq_m; mi++) {
469 auc.c[ti].y[mi]=0.0;
470 for(int ni=0; ni<llsq_n; ni++) auc.c[ti].y[mi]+=llsq_x[ni]*matbackup[mi+ni*llsq_m];
471 }
472
473 } // next TAC
474
475 /* Free allocated memory */
476 free(llsq_a); free(llsq_mat);
477
478 } else if(method==METHOD_BVLS) {
479
480 /*
481 * Allocate memory required by BVLS
482 */
483 if(verbose>1) printf("allocating memory for BVLS\n");
484 int llsq_m=fitSampleNr;
485 double *llsq_mat=(double*)malloc((2*llsq_n*llsq_m)*sizeof(double));
486 if(llsq_mat==NULL) {
487 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
488 tacFree(&ttac); tacFree(&auc); parFree(&lp); return(5);
489 }
490 double b[llsq_m], x[MAX_LLSQ_N], bl[MAX_LLSQ_N], bu[MAX_LLSQ_N], w[llsq_n], zz[llsq_m];
491 double act[llsq_m*(llsq_n+2)], r2;
492 int istate[llsq_n+1], iterNr;
493 double *matbackup=llsq_mat+llsq_n*llsq_m;
494
495 /*
496 * Fit each regional TTAC (except reference TAC)
497 */
498 if(verbose>1) printf("solving BVLS\n");
499 for(int ti=0; ti<ttac.tacNr; ti++) if(ti!=refindex) {
500
501 if(verbose>2 && ttac.tacNr>2) {
502 printf("Region %d %s\n", 1+ti, ttac.c[ti].name); fflush(stdout);}
503
504 /* Setup data matrix A and vector B */
505 for(int mi=0; mi<llsq_m; mi++)
506 b[mi]=ttac.c[ti].y[mi];
507 if(model==MODEL_R1) {
508 for(int mi=0; mi<llsq_m; mi++) {
509 llsq_mat[mi]=ttac.c[refindex].y[mi]; // RTAC
510 llsq_mat[mi+llsq_m]=auc.c[refindex].y[mi]-auc.c[ti].y[mi]; // RTAC - TTAC integral
511 }
512 } else {
513 for(int mi=0; mi<llsq_m; mi++) {
514 llsq_mat[mi]=ttac.c[refindex].y[mi]; // RTAC
515 llsq_mat[mi+llsq_m]=auc.c[refindex].y[mi]; // RTAC integral
516 llsq_mat[mi+2*llsq_m]=-auc.c[ti].y[mi]; // -TTAC integral
517 }
518 }
519 if(verbose>10) {
520 printf("Matrix A and vector B:\n");
521 for(int mi=0; mi<llsq_m; mi++) {
522 printf("%.2e", llsq_mat[mi]);
523 for(int ni=1; ni<llsq_n; ni++) printf(", %.2e", llsq_mat[mi+ni*llsq_m]);
524 printf("; %.3e\n", b[mi]);
525 }
526 }
527 /* Make a copy of A matrix for later use */
528 for(int i=0; i<llsq_n*llsq_m; i++) matbackup[i]=llsq_mat[i];
529 /* Apply data weights */
530 if(tacIsWeighted(&ttac)) llsqWght(llsq_n, llsq_m, NULL, llsq_mat, b, ttac.w);
531 /* Set istate vector to indicate that all parameters are non-bound */
532 istate[llsq_n]=0; for(int ni=0; ni<llsq_n; ni++) istate[ni]=1+ni;
533 if(!isnan(fixed_k2r)) {
534 /* Set istate vector to indicate that: */
535 istate[llsq_n]=1; // one parameter is bound
536 istate[0]=2; // 1+index of that one bound parameter is 2
537 istate[1]=1; // 1+index of first active parameter is 1
538 istate[2]=3; // 1+index of second active parameter is 3
539 }
540 /* Set parameter limits */
541 if(model==MODEL_R1) {
542 bl[0]=0.0; bu[0]=100.0;
543 bl[1]=0.0; bu[1]=10.0;
544 } else {
545 bl[0]=0.0; bu[0]=100.0;
546 bl[1]=0.0; bu[1]=10.0;
547 bl[2]=0.0; bu[2]=10.0;
548 if(!isnan(fixed_k2r)) {
549 bl[1]=bu[1]=fixed_k2r;
550 }
551 }
552 /* Set max iterations */
553 iterNr=4*llsq_n;
554 /* Compute BVLS */
555 if(verbose>3) printf("starting BVLS...\n");
556 if(isnan(fixed_k2r))
557 ret=bvls(0, llsq_m, llsq_n, llsq_mat, b, bl, bu, x, w, act, zz, istate, &iterNr, verbose-3);
558 else
559 ret=bvls(1, llsq_m, llsq_n, llsq_mat, b, bl, bu, x, w, act, zz, istate, &iterNr, verbose-3);
560 if(verbose>3) printf(" ... done.\n");
561 r2=w[0];
562 if(ret!=0) {
563 if(ret==-1) fprintf(stderr, "Warning: BVLS iteration max exceeded for %s\n", ttac.c[ti].name);
564 else fprintf(stderr, "Warning: no BVLS solution for %s\n", ttac.c[ti].name);
565 for(int ni=0; ni<llsq_n; ni++) x[ni]=0.0;
566 r2=0.0;
567 }
568 if(verbose>5) {
569 printf("solution_vector: %d", istate[0]);
570 for(int ni=1; ni<llsq_n; ni++) printf(", %d", istate[ni]);
571 printf("\n");
572 }
573 for(int ni=0; ni<llsq_n; ni++) lp.r[ti].p[ni]=x[ni];
574 lp.r[ti].wss=r2;
575 lp.r[ti].dataNr=tacWSampleNr(&ttac);
576 lp.r[ti].fitNr=llsq_n;
577
578 /* Compute fitted TAC (into auc since it is otherwise not needed) */
579 for(int mi=0; mi<llsq_m; mi++) {
580 auc.c[ti].y[mi]=0.0;
581 for(int ni=0; ni<llsq_n; ni++) auc.c[ti].y[mi]+=x[ni]*matbackup[mi+ni*llsq_m];
582 }
583
584 } // next TAC
585
586 /* Free allocated memory */
587 free(llsq_mat);
588
589 } else {
590
591 fprintf(stderr, "Error: selected method not available.");
592 tacFree(&ttac); tacFree(&auc); parFree(&lp);
593 return(1);
594
595 }
596
597
598 /*
599 * Print original LLSQ parameters on screen
600 */
601 if(verbose>2 && lp.tacNr<50) {
602 parWrite(&lp, stdout, PAR_FORMAT_TSV_UK, 0, &status);
603 fflush(stdout);
604 }
605
606 /*
607 * Prepare the room for CM parameters.
608 * Solve CM parameters from LLSQ parameters.
609 */
610 if(verbose>1) printf("initializing CM parameter data\n");
611 PAR cmpar; parInit(&cmpar);
612 ret=parAllocateWithTAC(&cmpar, &ttac, MAX_LLSQ_N+4, &status);
613 if(ret!=TPCERROR_OK) {
614 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
615 tacFree(&ttac); tacFree(&auc); parFree(&lp);
616 return(21);
617 }
618 iftFree(&cmpar.h);
619 /* Copy titles & file names & parameter values */
620 {
621 int i;
622 char buf[256];
623 time_t t=time(NULL);
624 /* set program name */
625 tpcProgramName(argv[0], 1, 1, buf, 256);
626 iftPut(&cmpar.h, "program", buf, 0, NULL);
627 /* set file names */
628 iftPut(&cmpar.h, "datafile", ttacfile, 0, NULL);
629 iftPut(&cmpar.h, "refname", ttac.c[refindex].name, 0, NULL);
630 /* Study number */
631 if(tacGetHeaderStudynr(&ttac.h, buf, NULL)==TPCERROR_OK)
632 iftPut(&cmpar.h, "study_number", buf, 0, NULL);
633 /* Fit method */
634 iftPut(&cmpar.h, "fitmethod", method_str[method], 0, NULL);
635 /* Model */
636 iftPut(&cmpar.h, "model", model_str[model], 0, NULL);
637 /* Set current time to results */
638 iftPut(&cmpar.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
639 /* Set fit times for each TAC */
640 for(i=0; i<cmpar.tacNr; i++) {
641 cmpar.r[i].dataNr=fitSampleNr;
642 cmpar.r[i].start=0.0;
643 cmpar.r[i].end=lp.r[i].end;
644 /* and nr of fitted and saved parameters */
645 cmpar.r[i].fitNr=lp.r[i].fitNr;
646 /* and WSS */
647 cmpar.r[i].wss=lp.r[i].wss;
648 }
649 /* Set the parameter names and units */
650 if(model==MODEL_R1) {
651 cmpar.parNr=llsq_n;
652 i=0; strcpy(cmpar.n[i].name,"R1");
653 i++; strcpy(cmpar.n[i].name,"k2"); cmpar.n[i].unit=UNIT_PER_MIN;
654 } else {
655 cmpar.parNr=llsq_n;
656 i=0; strcpy(cmpar.n[i].name,"R1");
657 i++; strcpy(cmpar.n[i].name,"k2"); cmpar.n[i].unit=UNIT_PER_MIN;
658 i++; strcpy(cmpar.n[i].name,"k2r"); cmpar.n[i].unit=UNIT_PER_MIN;
659 cmpar.parNr+=2; // two derived parameters
660 i++; strcpy(cmpar.n[i].name,"R2");
661 i++; strcpy(cmpar.n[i].name,"pRatio");
662 }
663 /* Set parameters */
664 if(model==MODEL_R1) {
665 for(i=0; i<cmpar.tacNr; i++) {
666 cmpar.r[i].p[0]=lp.r[i].p[0];
667 cmpar.r[i].p[1]=lp.r[i].p[1];
668 }
669 } else {
670 for(i=0; i<cmpar.tacNr; i++) {
671 double R1, k2, k2r, R2, pRatio;
672 R1=lp.r[i].p[0]; k2=lp.r[i].p[2]; k2r=lp.r[i].p[1]/lp.r[i].p[0];
673 R2=k2/k2r; pRatio=R1/R2;
674 cmpar.r[i].p[0]=R1;
675 cmpar.r[i].p[1]=k2;
676 cmpar.r[i].p[2]=k2r;
677 cmpar.r[i].p[3]=R2;
678 cmpar.r[i].p[4]=pRatio;
679 }
680 }
681 }
682 /* Delete reference TAC from parameters */
683 parDeleteTAC(&cmpar, refindex);
684
685 /*
686 * Print CM parameters on screen
687 */
688 if(verbose>0 && lp.tacNr<80) parWrite(&cmpar, stdout, PAR_FORMAT_TSV_UK, 0, &status);
689
690
691 /*
692 * Save CM results
693 */
694 {
695 if(verbose>1) printf("writing %s\n", resfile);
696 cmpar.format=parFormatFromExtension(resfile);
697 if(verbose>2) printf("result file format := %s\n", parFormattxt(cmpar.format));
699 FILE *fp; fp=fopen(resfile, "w");
700 if(fp==NULL) {
701 fprintf(stderr, "Error: cannot open file for writing parameter file.\n");
702 ret=TPCERROR_FAIL;
703 } else {
704 ret=parWrite(&cmpar, fp, PAR_FORMAT_UNKNOWN, 1, &status);
705 fclose(fp);
706 if(ret!=TPCERROR_OK) fprintf(stderr, "Error: %s\n", errorMsg(status.error));
707 }
708 if(ret!=TPCERROR_OK) {
709 tacFree(&ttac); tacFree(&auc); parFree(&lp); parFree(&cmpar); return(22);
710 }
711 if(verbose>0) printf("Results saved in %s.\n", resfile);
712 }
713
714 /* Replace 'fitted' (AUC of) reference TAC with original measured TAC */
715 for(int i=0; i<auc.sampleNr; i++) auc.c[refindex].y[i]=ttac.c[refindex].y[i];
716
717
718 /*
719 * SVG plot of fitted and original data
720 */
721 if(svgfile[0]) {
722 if(verbose>1) printf("saving SVG plot\n");
723 int i;
724 char buf[128];
725 sprintf(buf, "%s %s", method_str[method], model_str[model]);
726 i=iftFindKey(&ttac.h, "studynr", 0);
727 if(i<0) i=iftFindKey(&ttac.h, "study_number", 0);
728 if(i>=0) {strcat(buf, ": "); strcat(buf, ttac.h.item[i].value);}
729 ret=tacPlotFitSVG(&ttac, &auc, buf, 0.0, nan(""), 0.0, nan(""), svgfile, &status);
730 if(ret!=TPCERROR_OK) {
731 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
732 tacFree(&ttac); tacFree(&auc); parFree(&lp); parFree(&cmpar);
733 return(31);
734 }
735 if(verbose>0) printf("Plots written in %s.\n", svgfile);
736 }
737
738
739 /*
740 * Save fitted TTACs
741 */
742 if(fitfile[0]) {
743 if(verbose>1) printf("writing %s\n", fitfile);
744 FILE *fp; fp=fopen(fitfile, "w");
745 if(fp==NULL) {
746 fprintf(stderr, "Error: cannot open file for writing fitted TTACs.\n");
747 ret=TPCERROR_FAIL;
748 } else {
749 ret=tacWrite(&auc, fp, TAC_FORMAT_UNKNOWN, 1, &status);
750 fclose(fp);
751 if(ret!=TPCERROR_OK) fprintf(stderr, "Error: %s\n", errorMsg(status.error));
752 }
753 if(ret!=TPCERROR_OK) {
754 tacFree(&ttac); tacFree(&auc); parFree(&lp); parFree(&cmpar);
755 return(32);
756 }
757 if(verbose>0) printf("fitted TACs saved in %s.\n", fitfile);
758 }
759
760
761 tacFree(&ttac); tacFree(&auc); parFree(&lp); parFree(&cmpar);
762
763 return(0);
764}
765/*****************************************************************************/
766
767/*****************************************************************************/
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
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 iftFindKey(IFT *ift, const char *key, int start_index)
Definition iftfind.c:30
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
int parDeleteTAC(PAR *par, int ti)
Definition par.c:519
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
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
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
int tacGetHeaderStudynr(IFT *h, char *s, TPCSTATUS *status)
Definition tacift.c:26
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
int tacFittime(TAC *d, double *startTime, double *endTime, int *first, int *last, TPCSTATUS *status)
int tacReadReference(TAC *tis, const char *reference, TAC *ref, int *refIndex, TPCSTATUS *status)
Read reference tissue TAC.
int tacFixNaNs(TAC *tac)
Definition tacnan.c:121
int tacVerifyTimeOrder(TAC *d, TPCSTATUS *status)
Definition tacorder.c:25
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:23
int tacIsWeighted(TAC *tac)
Definition tacw.c:24
unsigned int tacWSampleNr(TAC *tac)
Definition tacw.c:219
int tacWByFreq(TAC *tac, isotope isot, TPCSTATUS *status)
Definition tacw.c:134
int 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
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_MIN
minutes
@ UNIT_PER_MIN
1/min
@ 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.