TPCCLIB
Loading...
Searching...
No Matches
b2t_h2o.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <math.h>
14/*****************************************************************************/
15#include "libtpcmisc.h"
16#include "libtpcmodel.h"
17#include "libtpccurveio.h"
18/*****************************************************************************/
19
20/*****************************************************************************/
21static char *info[] = {
22 "Simulation of PET tissue time-radioactivity concentration curve (TTAC)",
23 "in [O-15]H2O PET studies from decay corrected arterial blood TAC based on",
24 "the one-tissue compartment model.",
25 " ",
26 "Usage: @P [options] bloodfile f p E Vb fA simfile",
27 " ",
28 "Perfusion (f) must be given in units mL/(min*100 mL), partition coefficient",
29 "(p) in units mL/mL, and vascular volume (Vb) and the arterial fraction of it",
30 "(fA) as percentages.",
31 "By default, blood flow (perfusion) and tissue concentratios are",
32 "assumed to represented per PET volume (including vascular volume).",
33 "Extraction coefficient, E=1-exp(-PS/f), can usually be set to 1.0.",
34 "Blood sample times must be in seconds, unless specified in the file.",
35 "For accurate results, blood input TAC should be noiseless and have very",
36 "short sampling intervals. Simulated curves can thereafter be interpolated",
37 "to represent PET frames using program fr4sim.",
38 " ",
39 "Options:",
40 " -sub | -nosub",
41 " TACs of sub-compartments are written (-sub)",
42 " or not written (-nosub, default) into the output file.",
43 " -add",
44 " Simulated TACs are added to an existing tissue data file.",
45 " By default, existing file is overwritten.",
46 " -fpt",
47 " Blood flow (perfusion) is assumed to be given per perfusable tissue",
48 " volume excluding vascular volume. TAC will still be simulated per",
49 " regional PET volume including vascular volume.",
50 " -voiname=<text>",
51 " Enter a name (1-6 chars without spaces) for the simulated TAC",
52 " -vena=<filename>",
53 " Save the simulated venous blood TAC",
54 " -stdoptions", // List standard options like --help, -v, etc
55 " ",
56 "Simulated TACs are written in ASCII format with columns:",
57 " 1) Sample time (s)",
58 " 2) Total tissue activity concentration (Cpet)",
59 " 3) Activity concentration in tissue, (1-Vb)*Ct (optional)",
60 " 4) Arterial contribution to tissue activity, Vb*fA*Cab (optional)",
61 " 5) Venous contribution to tissue activity, Vb*(1-fA)*Cvb (optional)",
62 " ",
63 "See also: fit_h2o, sim_mbf, sim_3tcm, avgbolus, tacadd, simframe, tacunit",
64 " ",
65 "Keywords: TAC, simulation, modelling, perfusion, radiowater",
66 0};
67/*****************************************************************************/
68
69/*****************************************************************************/
70/* Turn on the globbing of the command line, since it is disabled by default in
71 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
72 In Unix&Linux wildcard command line processing is enabled by default. */
73/*
74#undef _CRT_glob
75#define _CRT_glob -1
76*/
77int _dowildcard = -1;
78/*****************************************************************************/
79
80/*****************************************************************************/
84int main(int argc, char **argv)
85{
86 int ai, help=0, version=0, verbose=1;
87 int ri, fi, ret;
88 int save_only_total=1;
89 int flow_per_tissue=0;
90 int add_to_previous=0;
91 int tunit;
92 char bfile[FILENAME_MAX], tfile[FILENAME_MAX], vfile[FILENAME_MAX];
93 char *cptr, voiname[MAX_REGIONNAME_LEN+1];
94 double Flow, pH2O, E, Vb, fA, Va, Vv;
95 double K1, k2;
96 DFT blood, dft;
97
98
99 /*
100 * Get arguments
101 */
102 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
103 bfile[0]=tfile[0]=vfile[0]=voiname[0]=(char)0;
104 Flow=pH2O=E=Vb=fA=Va=Vv=-1.0;
105 dftInit(&blood); dftInit(&dft);
106 /* Options */
107 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
108 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
109 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
110 if(strncasecmp(cptr, "NOSUB", 5)==0) {
111 save_only_total=1; continue;
112 } else if(strncasecmp(cptr, "SUB", 3)==0) {
113 save_only_total=0; continue;
114 } else if(strcasecmp(cptr, "FPT")==0) {
115 flow_per_tissue=1; continue;
116 } else if(strcasecmp(cptr, "ADD")==0) {
117 add_to_previous=1; continue;
118 } else if(strncasecmp(cptr, "VOINAME=", 8)==0) {
119 ret=strlcpy(voiname, cptr+8, MAX_REGIONNAME_LEN);
120 if(ret<1 || ret>=MAX_REGIONNAME_LEN) {
121 fprintf(stderr, "Error: invalid VOI name '%s'.\n", cptr+8); return(1);}
122 continue;
123 } else if(strncasecmp(cptr, "VENA=", 5)==0) {
124 ret=strlcpy(vfile, cptr+5, FILENAME_MAX);
125 if(ret<1 || ret>=FILENAME_MAX) {
126 fprintf(stderr, "Error: invalid VOI name '%s'.\n", cptr+5); return(1);}
127 continue;
128 }
129 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
130 return(1);
131 } else break;
132
133 /* Print help or version? */
134 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
135 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
136 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
137
138
139 /* Process other arguments, starting from the first non-option */
140 if(ai<argc) {strlcpy(bfile, argv[ai], FILENAME_MAX); ai++;}
141 if(ai<argc) {
142 Flow=atof_dpi(argv[ai])/6000.;
143 if(!(Flow>=0.0)) {fprintf(stderr, "invalid f (%s).\n", argv[ai]); return(1);}
144 ai++;
145 }
146 if(ai<argc) {
147 pH2O=atof_dpi(argv[ai]);
148 if(!(pH2O>=0.0)) {fprintf(stderr, "invalid pH2O (%s).\n", argv[ai]); return(1);}
149 ai++;
150 }
151 if(ai<argc) {
152 E=atof_dpi(argv[ai]);
153 if(!(E>=0.0) || E>1.0) {fprintf(stderr, "invalid E (%s).\n", argv[ai]); return(1);}
154 ai++;
155 }
156 if(ai<argc) {
157 Vb=atof_dpi(argv[ai])/100.;
158 if(!(Vb>=0.0) || Vb>1.0) {fprintf(stderr, "invalid Vb (%s).\n", argv[ai]); return(1);}
159 ai++;
160 }
161 if(ai<argc) {
162 fA=atof_dpi(argv[ai])/100.;
163 if(!(fA>=0.0) || fA>1.0) {fprintf(stderr, "invalid fA (%s).\n", argv[ai]); return(1);}
164 ai++;
165 }
166 if(ai<argc) {strlcpy(tfile, argv[ai], FILENAME_MAX); ai++;}
167 if(ai<argc) {fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]); return(1);}
168
169 /* Did we get all the information that we need? */
170 if(!tfile[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
171
172 /* Calculate Va and Vb */
173 Va=fA*Vb; Vv=(1.0-fA)*Vb;
174 if(E<=0. || E>1. || Va<0. || Va>=1. || Vv<0. || Vv>=1. || Va+Vv>=1.) {
175 fprintf(stderr, "Erroneous parameter values.\n");
176 return(1);
177 }
178
179
180 /* In verbose mode print arguments and options */
181 if(verbose>1) {
182 printf("bfile := %s\n", bfile);
183 printf("tfile := %s\n", tfile);
184 printf("save_only_total := %d\n", save_only_total);
185 printf("flow_per_tissue := %d\n", flow_per_tissue);
186 printf("add_to_previous := %d\n", add_to_previous);
187 if(vfile[0]) printf("vfile := %s\n", vfile);
188 if(voiname[0]) printf("voiname := %s\n", voiname);
189 printf("Flow := %g\n", Flow);
190 printf("pH2O := %g\n", pH2O);
191 printf("E := %g\n", E);
192 printf("Vb := %g\n", Vb);
193 printf("fA := %g\n", fA);
194 printf("Va := %g\n", Va);
195 printf("Vv := %g\n", Vv);
196 }
197
198
199 /*
200 * Read blood data
201 */
202 if(verbose>1) printf("reading blood TAC in %s\n", bfile);
203 if(dftRead(bfile, &blood)) {
204 fprintf(stderr, "Error in reading '%s': %s\n", bfile, dfterrmsg);
205 dftEmpty(&blood); return(2);
206 }
207 if(blood.frameNr<2) {
208 fprintf(stderr, "Error: too few samples in '%s'.\n", bfile);
209 dftEmpty(&blood); return(2);
210 }
211 if(blood.frameNr<4) {
212 fprintf(stderr, "Warning: few samples in '%s'.\n", bfile);
213 }
214 if(blood.voiNr>1) {
215 fprintf(stderr, "Error: blood data contains more than one curve.\n");
216 dftEmpty(&blood); return(2);
217 }
218 if(blood.timeunit==TUNIT_UNKNOWN) {
219 blood.timeunit=TUNIT_SEC;
220 if(verbose>=0) printf("assuming that blood time unit is sec\n");
221 }
222 tunit=blood.timeunit; // save original time units
223 if(blood.timeunit!=TUNIT_SEC) {
224 ret=dftTimeunitConversion(&blood, TUNIT_SEC);
225 if(ret) {
226 fprintf(stderr, "Error: cannot convert blood data sample times to sec.\n");
227 dftEmpty(&blood); return(2);
228 }
229 }
230 strcpy(blood.voi[0].voiname, "Blood");
231 strcpy(blood.voi[0].name, blood.voi[0].voiname);
232
233
234 /*
235 * Allocate memory for simulated data
236 */
237 if(verbose>1) printf("allocating memory for simulated TACs\n");
238 ret=dftSetmem(&dft, blood.frameNr, 4);
239 if(ret) {
240 fprintf(stderr, "Error in allocating memory for simulated data.\n");
241 dftEmpty(&blood); dftEmpty(&dft); return(3);
242 }
243 dft.frameNr=blood.frameNr; dft.voiNr=4;
244 /* Copy times & header info */
245 dftCopymainhdr(&blood, &dft);
246 for(fi=0; fi<dft.frameNr; fi++) {
247 dft.x[fi]=blood.x[fi]; dft.x1[fi]=blood.x1[fi]; dft.x2[fi]=blood.x2[fi];
248 }
249 strcpy(dft.isotope, "O-15");
250 strcpy(dft.radiopharmaceutical, "[O-15]H2O");
251 strcpy(dft.injectionTime, blood.injectionTime);
252 strcpy(dft.scanStartTime, blood.scanStartTime);
253 dft.timeunit=blood.timeunit;
255 for(ri=0; ri<dft.voiNr; ri++) {
256 strcpy(dft.voi[ri].place, "");
257 dft.voi[ri].size=100.;
258 }
259 if(strlen(voiname)==0) {
260 strcpy(dft.voi[0].voiname, "Total"); strcpy(dft.voi[0].hemisphere, "Cpet");
261 } else {
262 strcpy(dft.voi[0].name, voiname);
263 rnameSplit(voiname, dft.voi[0].voiname, dft.voi[0].hemisphere,
265 }
266 strcpy(dft.voi[1].voiname, "Tissue"); strcpy(dft.voi[1].hemisphere, "Ct");
267 strcpy(dft.voi[2].voiname, "Artery"); strcpy(dft.voi[2].hemisphere, "Ca");
268 dft.voi[2].size=100.*Va;
269 strcpy(dft.voi[3].voiname, "Vena"); strcpy(dft.voi[3].hemisphere, "Cv");
270 dft.voi[3].size=100.*Vv;
271 for(ri=1; ri<dft.voiNr; ri++)
272 strcpy(dft.voi[ri].name, dft.voi[ri].voiname);
273
274
275 /*
276 * Simulate TACs
277 */
278 if(verbose>1) printf("simulating tissue data\n");
279 K1=Flow*E; if(flow_per_tissue==0) K1/=(1.0-Va-Vv);
280 k2=K1/pH2O;
281 if(verbose>1) printf("K1 := %g\nk2 := %g\n", K1, k2);
282 ret=simC3s(blood.x, blood.voi[0].y, blood.frameNr, K1, k2, 0., 0., 0., 0.,
283 dft.voi[1].y, NULL, NULL, NULL);
284 if(ret) {
285 fprintf(stderr, "Error %d in simulating tissue data.\n", ret);
286 dftEmpty(&blood); dftEmpty(&dft); return(5);
287 }
288 if(verbose>2) printf("simulating PET curves\n");
289 for(fi=0; fi<dft.frameNr; fi++) {
290 dft.voi[2].y[fi]=blood.voi[0].y[fi];
291 dft.voi[3].y[fi]=(1.0-E)*blood.voi[0].y[fi] + (E/pH2O)*dft.voi[1].y[fi];
292 }
293
294
295 /*
296 * Save vena TAC if required
297 */
298 if(vfile[0]) {
299 if(verbose>0) printf("saving vena data in %s\n", vfile);
301 DFT temp;
302 dftInit(&temp); dftdup(&dft, &temp); dftCopyvoi(&temp, 3, 0); temp.voiNr=1;
303 dftTimeunitConversion(&temp, tunit);
304 dftSetComments(&temp);
305 if(ret!=0 || dftWrite(&temp, vfile)!=0) {
306 fprintf(stderr, "Error: cannot save vena data in %s\n", vfile);
307 if(verbose>1) fprintf(stderr, "Error: %s\n", dfterrmsg);
308 dftEmpty(&temp); dftEmpty(&blood); dftEmpty(&dft); return(11);
309 }
310 dftEmpty(&temp);
311 }
312
313
314 /* Calculate the activities per PET volume */
315 for(fi=0; fi<dft.frameNr; fi++) {
316 dft.voi[1].y[fi]*=(1.0-Va-Vv);
317 dft.voi[2].y[fi]*=Va;
318 dft.voi[3].y[fi]*=Vv;
319 dft.voi[0].y[fi]=dft.voi[1].y[fi]+dft.voi[2].y[fi]+dft.voi[3].y[fi];
320 }
321 /* Set data info */
322 sprintf(dft.comments,
323 "# Flow := %g\n# pH2O :=%g\n# E := %g\n# Va := %g\n# Vv := %g\n",
324 Flow, pH2O, E, Va, Vv);
325 /* Blood is not needed anymore */
326 dftEmpty(&blood);
327 /* Convert sample times to original units */
328 dftTimeunitConversion(&dft, tunit);
329
330
331 /*
332 * Write simulated TACs
333 */
334 if(verbose>1) printf("saving PET curves\n");
336 if(save_only_total) dft.voiNr=1;
337 /* Set file format to PMOD, if extension is .tac */
338 if(add_to_previous==0 && !strcasecmp(filenameGetExtension(tfile), ".tac"))
340 /* Some format has to be set anyway, and simple format would lose information */
343 dftSetComments(&dft);
344 if(add_to_previous!=0 && access(tfile, 0)!=-1) {
345 if(verbose>0) printf("adding to existing file\n");
346 DFT prevdft;
347 /* read previous file */
348 dftInit(&prevdft);
349 if(dftRead(tfile, &prevdft)) {
350 fprintf(stderr, "Error in reading '%s': %s\n", tfile, dfterrmsg);
351 dftEmpty(&prevdft); dftEmpty(&dft); return(2);
352 }
353 if(verbose>2) printf("existing %d TACs with %d frames\n",
354 prevdft.voiNr, prevdft.frameNr);
355 /* add present simulations */
356 for(ri=0; ri<dft.voiNr; ri++) {
357 ret=dftAdd(&prevdft, &dft, ri);
358 if(ret) {
359 fprintf(stderr, "Error: cannot add simulated TAC in %s\n", tfile);
360 dftEmpty(&prevdft); dftEmpty(&dft); return(13);
361 }
362 }
363 /* save that */
364 ret=dftWrite(&prevdft, tfile);
365 /* Clear it from memory */
366 dftEmpty(&prevdft);
367 } else {
368 /* save only present simulations */
369 ret=dftWrite(&dft, tfile);
370 }
371 if(ret) {
372 fprintf(stderr, "Error in writing '%s': %s\n", tfile, dfterrmsg);
373 dftEmpty(&dft);
374 return(12);
375 }
376 if(verbose>=0) fprintf(stdout, "simulated TAC(s) written in %s\n", tfile);
377
378 /* Free memory */
379 dftEmpty(&dft);
380
381 return(0);
382}
383/*****************************************************************************/
384
385/*****************************************************************************/
double atof_dpi(char *str)
Definition decpoint.c:59
void dftInit(DFT *data)
Definition dft.c:38
int dftdup(DFT *dft1, DFT *dft2)
Definition dft.c:655
char dfterrmsg[64]
Definition dft.c:6
void dftSetComments(DFT *dft)
Definition dft.c:1326
int dftCopyvoi(DFT *data, int from, int to)
Definition dft.c:472
int dftSetmem(DFT *data, int frameNr, int voiNr)
Definition dft.c:57
int dftAdd(DFT *data1, DFT *data2, int voi)
Definition dft.c:188
void dftEmpty(DFT *data)
Definition dft.c:20
int dftCopymainhdr(DFT *dft1, DFT *dft2)
Definition dft.c:561
int dftRead(char *filename, DFT *data)
Definition dftio.c:22
int DFT_NR_OF_DECIMALS
Definition dftio.c:13
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
int dftTimeunitConversion(DFT *dft, int tunit)
Definition dftunit.c:119
char * filenameGetExtension(char *s)
Get the last extension of a filename.
Definition filename.c:139
Header file for libtpccurveio.
#define DFT_FORMAT_PMOD
#define DFT_FORMAT_STANDARD
#define DFT_DECAY_CORRECTED
#define DFT_FORMAT_PLAIN
#define DFT_FORMAT_UNKNOWN
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
int rnameSplit(char *rname, char *name1, char *name2, char *name3, int max_name_len)
Definition rname.c:14
#define MAX_REGIONNAME_LEN
Definition libtpcmisc.h:154
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
#define MAX_REGIONSUBNAME_LEN
Definition libtpcmisc.h:158
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
Header file for libtpcmodel.
int simC3s(double *t, double *ca, int nr, double k1, double k2, double k3, double k4, double k5, double k6, double *ct, double *cta, double *ctb, double *ctc)
Definition simulate.c:27
char scanStartTime[20]
char decayCorrected
int _type
Voi * voi
int timeunit
double * x1
char comments[_DFT_COMMENT_LEN+1]
int voiNr
double * x2
char injectionTime[20]
int frameNr
char isotope[8]
double * x
char radiopharmaceutical[32]
double size
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
char name[MAX_REGIONNAME_LEN+1]
char hemisphere[MAX_REGIONSUBNAME_LEN+1]
char place[MAX_REGIONSUBNAME_LEN+1]