TPCCLIB
Loading...
Searching...
No Matches
taccbvp.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "tpcclibConfig.h"
10/*****************************************************************************/
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <math.h>
15/*****************************************************************************/
16#include "tpcextensions.h"
17#include "tpcift.h"
18#include "tpctac.h"
19#include "tpcmodels.h"
20#include "tpcpar.h"
21#include "tpcfunc.h"
22#include "tpctacmod.h"
23/*****************************************************************************/
24
25/*****************************************************************************/
26static char *info[] = {
27 "Estimate Vb and Ct based on blood curve (BTAC), assuming that at BTAC peak",
28 "tissue concentration is zero, thus Vb=Ct/Cb.",
29 "Vb is then reduced to assure that other TACs remain non-negative.",
30 "The name or number of BTAC inside TAC file must be given.",
31 " ",
32 "Do not use this oversimplified method for quantitative analyses!",
33 " ",
34 "Usage: @P [options] tacfile BTAC [outputfile]",
35 " ",
36 "Options:",
37 " -par=<filename>",
38 " Estimated Vb is written in file.",
39 " -stdoptions", // List standard options like --help, -v, etc
40 " ",
41 "See also: imgcbvp, taccbv, tacpeak, taccalc",
42 " ",
43 "Keywords: TAC, peak, vascular fraction",
44 0};
45/*****************************************************************************/
46
47/*****************************************************************************/
48/* Turn on the globbing of the command line, since it is disabled by default in
49 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
50 In Unix&Linux wildcard command line processing is enabled by default. */
51/*
52#undef _CRT_glob
53#define _CRT_glob -1
54*/
55int _dowildcard = -1;
56/*****************************************************************************/
57
58/*****************************************************************************/
62int main(int argc, char **argv)
63{
64 int ai, help=0, version=0, verbose=1;
65 char tacfile[FILENAME_MAX], parfile[FILENAME_MAX], corfile[FILENAME_MAX];
66 char bname[MAX_TACNAME_LEN+1];
67
68
69 /*
70 * Get arguments
71 */
72 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
73 tacfile[0]=parfile[0]=corfile[0]=(char)0;
74 bname[0]=(char)0;
75 /* Options */
76 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
77 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
78 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
79 if(strncasecmp(cptr, "PAR=", 4)==0) {
80 strlcpy(parfile, cptr+4, FILENAME_MAX); if(strlen(parfile)>0) continue;
81 }
82 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
83 return(1);
84 } else break; // tac name argument may start with '-'
85
86 TPCSTATUS status; statusInit(&status);
87 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
88 status.verbose=verbose-1;
89
90 /* Print help or version? */
91 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
92 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
93 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
94
95
96 /* Arguments */
97 if(ai<argc) strlcpy(tacfile, argv[ai++], FILENAME_MAX);
98 if(ai<argc) strlcpy(bname, argv[ai++], MAX_TACNAME_LEN+1);
99 if(ai<argc) strlcpy(corfile, argv[ai++], FILENAME_MAX);
100 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
101
102 /* Is something missing? */
103 if(!bname[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
104
105 /* In verbose mode print arguments and options */
106 if(verbose>1) {
107 for(ai=0; ai<argc; ai++) printf("%s ", argv[ai]);
108 printf("\n");
109 printf("tacfile := %s\n", tacfile);
110 printf("bname := %s\n", bname);
111 if(parfile[0]) printf("parfile := %s\n", parfile);
112 if(corfile[0]) printf("corfile := %s\n", corfile);
113 }
114
115
116 /*
117 * Read the file
118 */
119 if(verbose>1) printf("reading %s\n", tacfile);
120 TAC tac; tacInit(&tac);
121 if(tacRead(&tac, tacfile, &status)!=TPCERROR_OK) {
122 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
123 tacFree(&tac); return(2);
124 }
125 if(verbose>2) {
126 printf("fileformat := %s\n", tacFormattxt(tac.format));
127 printf("tacNr := %d\n", tac.tacNr);
128 printf("sampleNr := %d\n", tac.sampleNr);
129 printf("xunit := %s\n", unitName(tac.tunit));
130 printf("yunit := %s\n", unitName(tac.cunit));
131 }
132 if(tac.tacNr<1) {
133 fprintf(stderr, "Error: invalid file.\n");
134 tacFree(&tac); return(2);
135 } else if(tac.tacNr<2) {
136 if(verbose>0) fprintf(stderr, "Error: file contains just one TAC.\n");
137 tacFree(&tac); return(2);
138 }
139 /* Check NaNs */
140 if(tacNaNs(&tac)>0) {
141 fprintf(stderr, "Error: data contains missing values.\n");
142 tacFree(&tac); return(2);
143 }
144 /* Sort the data by sample times (x) */
145 if(tacSortByTime(&tac, &status)!=TPCERROR_OK) {
146 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
147 tacFree(&tac); return(2);
148 }
149 /* Get x range */
150 double xmin, xmax;
151 if(tacXRange(&tac, &xmin, &xmax)!=0) {
152 fprintf(stderr, "Error: invalid data sample times.\n");
153 tacFree(&tac); return(2);
154 }
155 if(verbose>1) {
156 printf("xmin := %g\n", xmin);
157 printf("xmax := %g\n", xmax);
158 }
159 /* Take average of any duplicate samples */
160 if(tacMultipleSamples(&tac, 1, &tac, verbose-2)!=0) {
161 fprintf(stderr, "Error: cannot process duplicate samples.\n");
162 tacFree(&tac); return(2);
163 }
164 if(tac.sampleNr<3) {
165 fprintf(stderr, "Error: too few samples.\n");
166 tacFree(&tac); return(2);
167 }
168
169 /* Select the LV BTAC */
170 int ib=-1;
171 {
172 int n=tacSelectTACs(&tac, bname, 1, NULL);
173 if(n<1) {
174 fprintf(stderr, "Error: specified BTAC not found in %s.\n", tacfile);
175 tacFree(&tac); return(3);
176 } else if(n>1) {
177 fprintf(stderr, "Error: %d TACs match '%s' in %s.\n", n, bname, tacfile);
178 tacFree(&tac); return(3);
179 }
180 ib=tacFirstSelected(&tac);
181 if(verbose>1) {
182 printf("BTAC name := %s\n", tac.c[ib].name);
183 printf("BTAC index := %d\n", ib);
184 }
185 }
186
187
188 /*
189 * Prepare space for results
190 */
191 if(verbose>1) printf("preparing space for parameters\n");
192 PAR par; parInit(&par);
193 if(parAllocateWithTAC(&par, &tac, 1, &status)!=TPCERROR_OK) {
194 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
195 tacFree(&tac); return(3);
196 }
197 par.tacNr=tac.tacNr;
198 par.parNr=1;
200 for(int i=0; i<tac.tacNr; i++) {
201 par.r[i].model=0;
202 par.r[i].dataNr=tacWSampleNr(&tac);
203 par.r[i].start=xmin;
204 par.r[i].end=xmax;
205 }
206 /* Set parameter names */
207 strcpy(par.n[0].name, "Vb");
208
209
210 /*
211 * Search BTAC peak.
212 * Note that duplicate samples were removed above, and data is sorted by x.
213 */
214 if(verbose>1) printf("searching peak\n");
215 double bpeak=tac.c[ib].y[0];
216 int ipeak=0;
217 for(int i=1; i<tac.sampleNr; i++)
218 if(tac.c[ib].y[i]>bpeak) {bpeak=tac.c[ib].y[i]; ipeak=i;}
219 if(verbose>1) {
220 printf(" maxv := %g\n", bpeak);
221 printf(" maxx := %g\n", tac.x[ipeak]);
222 }
223 /* If peak is not the first sample, then add previous sample */
224 if(ipeak>0) bpeak+=tac.c[ib].y[ipeak-1];
225 if(verbose>2) {
226 printf(" bpeak := %g\n", bpeak);
227 }
228
229 /*
230 * Estimate Vb and correct TACs
231 */
232 for(int ci=0; ci<tac.tacNr; ci++) if(ci!=ib) {
233
234 /* Set any negative values to zero */
235 for(int i=0; i<tac.sampleNr; i++) if(tac.c[ci].y[i]<0.0) tac.c[ci].y[i]=0.0;
236
237 /* Calculate the maximum of Vb that is possible in this pixel from T/B ratio */
238 double tpeak=tac.c[ci].y[ipeak];
239 if(ipeak>0) tpeak+=tac.c[ci].y[ipeak-1];
240 double vb=tpeak/bpeak;
241 if(verbose>2) printf(" tpeak[%d] := %g\n", ci, tpeak);
242
243 if(vb>=1.0) { // this pixel must be mostly blood
244 for(int i=0; i<tac.sampleNr; i++) tac.c[ci].y[i]=0.0;
245 par.r[ci].p[0]=vb;
246 continue;
247 }
248
249 /* Make initial BV corrected TTAC */
250 double ct[tac.sampleNr], ctmin=0.0;
251 int ictmin=0;
252 for(int i=0; i<tac.sampleNr; i++) {
253 ct[i]=tac.c[ci].y[i]-vb*tac.c[ib].y[i];
254 if(ct[i]<ctmin) {ctmin=ct[i]; ictmin=i;}
255 }
256 /* Make Vb smaller to prevent negative TAC values and correct again */
257 if(ctmin<0.0) {
258 vb+=ctmin/tac.c[ib].y[ictmin];
259 for(int i=0; i<tac.sampleNr; i++) {
260 ct[i]=tac.c[ci].y[i]-vb*tac.c[ib].y[i];
261 if(ct[i]<0.0) ct[i]=0.0;
262 }
263 }
264 /* Put corrected TAC in place */
265 for(int i=0; i<tac.sampleNr; i++) tac.c[ci].y[i]=ct[i];
266 /* Store the Vb */
267 par.r[ci].p[0]=vb;
268 }
269
270 /* Set Vb=1 for the BTAC */
271 par.r[ib].p[0]=1.0;
272
273
274 /*
275 * Print and save parameters
276 */
277 if(verbose>0 || !parfile[0]) parWrite(&par, stdout, PAR_FORMAT_TSV_UK, 1, NULL);
278 if(parfile[0]) {
279 /* Save file */
280 if(verbose>1) printf(" saving %s\n", parfile);
281 FILE *fp=fopen(parfile, "w");
282 if(fp==NULL) {
283 fprintf(stderr, "Error: cannot open file for writing.\n");
284 tacFree(&tac); parFree(&par); return(11);
285 }
286 int ret=parWrite(&par, fp, PAR_FORMAT_UNKNOWN, 1, &status);
287 fclose(fp);
288 if(ret!=TPCERROR_OK) {
289 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
290 tacFree(&tac); parFree(&par); return(12);
291 }
292 if(verbose>0) printf("parameters saved in %s\n", parfile);
293 }
294
295 /*
296 * If requested, save Vb-corrected tissue data.
297 */
298 if(corfile[0]) {
299 int ret=TPCERROR_OK;
300 FILE *fp; fp=fopen(corfile, "w");
301 if(fp==NULL) {
302 fprintf(stderr, "Error: cannot open file for writing '%s'.\n", corfile);
303 ret=TPCERROR_FAIL;
304 } else {
305 ret=tacWrite(&tac, fp, TAC_FORMAT_PMOD, 1, &status);
306 fclose(fp);
307 if(ret!=TPCERROR_OK) fprintf(stderr, "Error: %s\n", errorMsg(status.error));
308 }
309 if(ret!=TPCERROR_OK) {
310 tacFree(&tac); parFree(&par);
311 return(21);
312 }
313 if(verbose>0) printf("Corrected TACs saved in %s.\n", corfile);
314 }
315
316 tacFree(&tac); parFree(&par);
317 return(0);
318}
319/*****************************************************************************/
320
321/*****************************************************************************/
void parFree(PAR *par)
Definition par.c:75
void parInit(PAR *par)
Definition par.c:25
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
Definition pario.c:148
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
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
Definition tpcpar.h:100
int format
Definition tpcpar.h:102
int parNr
Definition tpcpar.h:108
int tacNr
Definition tpcpar.h:104
PARR * r
Definition tpcpar.h:114
PARN * n
Definition tpcpar.h:112
char name[MAX_PARNAME_LEN+1]
Definition tpcpar.h:82
int dataNr
Definition tpcpar.h:62
unsigned int model
Definition tpcpar.h:48
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
TACC * c
Definition tpctac.h:117
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 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 tacNaNs(TAC *tac)
Definition tacnan.c:71
int tacSortByTime(TAC *d, TPCSTATUS *status)
Definition tacorder.c:74
int tacMultipleSamples(TAC *d1, const int fixMode, TAC *d2, const int verbose)
Check TAC data for multiple samples with the same sample time. Optionally replace the multiple sample...
Definition tacorder.c:336
int tacSelectTACs(TAC *d, const char *region_name, int reset, TPCSTATUS *status)
Definition tacselect.c:24
int tacFirstSelected(TAC *d)
Definition tacselect.c:122
unsigned int tacWSampleNr(TAC *tac)
Definition tacw.c:219
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Definition tacx.c:124
Header file for library libtpcextensions.
#define MAX_TACNAME_LEN
Max length of TAC ID name (not including trailing zero).
@ TPCERROR_FAIL
General error.
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
Header file for libtpcfunc.
Header file for library libtpcift.
Header file for libtpcmodels.
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_PMOD
PMOD TAC format.
Definition tpctac.h:33
Header file for libtpctacmod.