TPCCLIB
Loading...
Searching...
No Matches
o2metab.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 <unistd.h>
14#include <string.h>
15#include <math.h>
16/*****************************************************************************/
17#include "libtpcmisc.h"
18#include "libtpcmodel.h"
19#include "libtpccurveio.h"
20/*****************************************************************************/
21
22/*****************************************************************************/
23static char *info[] = {
24 "Calculates the blood time-activity curves (BTACs) of labelled water and",
25 "oxygen from arterial blood TAC measured after [O-15]O2 bolus using",
26 "a dedicated [O-15]O2 metabolite model (1, 2, 3) to be used as input in",
27 "[O-15]O2 model.",
28 " ",
29 "Usage: @P [Options] btacfile parameterfile obtacfile wtacfile",
30 " ",
31 "Options:",
32 " -stdoptions", // List standard options like --help, -v, etc
33 " ",
34 "Model parameters for k3 model (k1, k1+k3, delay) or k4 model (k1, k3,",
35 "k3/k4, delay) can be given in a RES or IFT file made by program fit_o2bl.",
36 "Parameters and data units are assumed to be in seconds, in case units",
37 "are not given in the files.",
38 " ",
39 "References:",
40 "1. Huang S-C et al. Modelling approach for separating blood time-activity",
41 " curves in positron emission tomographic studies.",
42 " Phys Med Biol. 1991;36(6):749-761.",
43 "2. Iida H et al. Modelling approach to eliminate the need to separate",
44 " arterial plasma in oxygen-15 inhalation positron emission tomography.",
45 " J Nucl Med. 1993;34:1333-1340.",
46 "3. Kudomi N et al. A physiologic model for recirculation water correction",
47 " in CMRO2 assessment with 15O2 inhalation PET.",
48 " J Cereb Blood Flow Metab. 2009;29(2):355-364.",
49 " ",
50 "See also: fit_o2bl, sim_o2bl, o2_p2w, fit_mo2, b2t_mo2, taccalc, tac2svg",
51 " ",
52 "Keywords: input, oxygen, blood, metabolite correction",
53 0};
54/*****************************************************************************/
55
56/*****************************************************************************/
57/* Turn on the globbing of the command line, since it is disabled by default in
58 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
59 In Unix&Linux wildcard command line processing is enabled by default. */
60/*
61#undef _CRT_glob
62#define _CRT_glob -1
63*/
64int _dowildcard = -1;
65/*****************************************************************************/
66
67/*****************************************************************************/
71int main(int argc, char **argv)
72{
73 int ai, help=0, version=0, verbose=1;
74 int ret;
75 char blofile[FILENAME_MAX], parfile[FILENAME_MAX],
76 oxyfile[FILENAME_MAX], watfile[FILENAME_MAX];
77 double k1, k2, k3, k4, delay, k3k4, k1k3;
78 DFT blood, sim;
79 RES res;
80 IFT ift;
81
82
83 /*
84 * Get arguments
85 */
86 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
87 dftInit(&blood); dftInit(&sim); resInit(&res); iftInit(&ift);
88 blofile[0]=parfile[0]=oxyfile[0]=watfile[0]=(char)0;
89 k1=k2=k3=k4=k3k4=k1k3=nan(""); delay=0.0;
90 /* Options */
91 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
92 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
93 //cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
94 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
95 return(1);
96 } else break;
97
98 /* Print help or version? */
99 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
100 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
101 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
102
103 /* Process other arguments, starting from the first non-option */
104 for(; ai<argc; ai++) {
105 if(!blofile[0]) {strlcpy(blofile, argv[ai], FILENAME_MAX); continue;}
106 if(!parfile[0]) {strlcpy(parfile, argv[ai], FILENAME_MAX); continue;}
107 if(!oxyfile[0]) {strlcpy(oxyfile, argv[ai], FILENAME_MAX); continue;}
108 if(!watfile[0]) {strlcpy(watfile, argv[ai], FILENAME_MAX); continue;}
109 fprintf(stderr, "Error: too many arguments: '%s'.\n", argv[ai]);
110 return(1);
111 }
112
113 /* Is something missing? */
114 if(!watfile[0]) {
115 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
116 return(1);
117 }
118
119 /* In verbose mode print arguments and options */
120 if(verbose>1) {
121 printf("blofile := %s\n", blofile);
122 printf("parfile := %s\n", parfile);
123 printf("oxyfile := %s\n", oxyfile);
124 printf("watfile := %s\n", watfile);
125 }
126
127 /* Read parameter file */
128 if(verbose>1) printf("reading parameters in %s\n", parfile);
129 /* First, try RES format */
130 if(resRead(parfile, &res, verbose-2)==0) {
131 if(verbose>2) printf("result format\n");
132 ret=res2ift(&res, &ift, verbose-3);
133 resEmpty(&res);
134 if(ret) {
135 fprintf(stderr, "Error in converting results.\n");
136 dftEmpty(&blood); dftEmpty(&sim); iftEmpty(&ift);
137 return(3);
138 }
139 /* If not RES then try IFT */
140 } else if(iftRead(&ift, parfile, 1, 0)==0) {
141 if(verbose>2) printf("ift format\n");
142 } else {
143 fprintf(stderr, "Error: cannot read '%s'\n", parfile);
144 dftEmpty(&blood); dftEmpty(&sim); iftEmpty(&ift);
145 return(2);
146 }
147 /* Now try to find the required parameters */
148 int i, n; char key[12]; double v; int u; char buf1[128], buf2[128];
149 /* k1 */
150 strcpy(key, "k1"); i=iftGet(&ift, key, 0);
151 if(i<0) {
152 fprintf(stderr, "Error: k1 not found in '%s'.\n", parfile);
153 dftEmpty(&blood); dftEmpty(&sim); iftEmpty(&ift);
154 return(4);
155 }
156 n=sscanf(ift.item[i].value, "%128s %128s", buf1, buf2);
157 if(n==0 || atof_with_check(buf1, &v)) {
158 fprintf(stderr, "Error: valid k1 not found in '%s'.\n", parfile);
159 dftEmpty(&blood); dftEmpty(&sim); iftEmpty(&ift);
160 return(4);
161 }
162 if(n>1) {u=petCunitId(buf2); if(u==CUNIT_PER_MIN) v/=60.0;}
163 k1=v; if(verbose>2) printf("k1 := %g\n", k1);
164 /* delay; if not found, keep it at zero */
165 strcpy(key, "delay"); i=iftGet(&ift, key, 0);
166 if(i<0) strcpy(key, "delayt");
167 i=iftGet(&ift, key, 0);
168 if(i<0) strcpy(key, "timedelay");
169 i=iftGet(&ift, key, 0);
170 if(i>=0) {
171 n=sscanf(ift.item[i].value, "%128s %128s", buf1, buf2);
172 if(n==0 || atof_with_check(buf1, &v)) {
173 fprintf(stderr, "Error: valid delay not found in '%s'.\n", parfile);
174 dftEmpty(&blood); dftEmpty(&sim); iftEmpty(&ift);
175 return(4);
176 }
177 if(n>1) {u=petTunitId(buf2); if(u==TUNIT_MIN) v*=60.0;}
178 delay=v; if(verbose>2) printf("delay := %g\n", k1);
179 }
180 /* k3 */
181 strcpy(key, "k3"); i=iftGet(&ift, key, 0);
182 if(i>=0) {
183 n=sscanf(ift.item[i].value, "%128s %128s", buf1, buf2);
184 if(n>0 && !atof_with_check(buf1, &v)) {
185 if(n>1) {u=petCunitId(buf2); if(u==CUNIT_PER_MIN) v/=60.0;}
186 k3=v; if(verbose>2) printf("k3 := %g\n", k3);
187 }
188 }
189 /* k3/k4 */
190 strcpy(key, "k3/k4"); i=iftGet(&ift, key, 0);
191 if(i>=0) {
192 n=sscanf(ift.item[i].value, "%128s %128s", buf1, buf2);
193 if(n>0 && !atof_with_check(buf1, &v)) {
194 k3k4=v; if(verbose>2) printf("k3/k4 := %g\n", k3k4);
195 }
196 }
197 /* k1+k3 */
198 strcpy(key, "k1+k3"); i=iftGet(&ift, key, 0);
199 if(i>=0) {
200 n=sscanf(ift.item[i].value, "%128s %128s", buf1, buf2);
201 if(n>0 && !atof_with_check(buf1, &v)) {
202 if(n>1) {u=petCunitId(buf2); if(u==CUNIT_PER_MIN) v/=60.0;}
203 k1k3=v; if(verbose>2) printf("k1+k3 := %g\n", k1k3);
204 }
205 }
206 /* check what we got */
207 k2=k1;
208 if(isnan(k3) && isnan(k1k3)) {
209 fprintf(stderr, "Error: missing k3 or k1+k3 in '%s'.\n", parfile);
210 dftEmpty(&blood); dftEmpty(&sim); iftEmpty(&ift);
211 return(4);
212 }
213 if(!isnan(k3)) {
214 if(isnan(k3k4)) {
215 fprintf(stderr, "Error: missing k3/k4 in '%s'.\n", parfile);
216 dftEmpty(&blood); dftEmpty(&sim); iftEmpty(&ift);
217 return(4);
218 }
219 if(k3k4<=1.0E-100) k4=0.0; else k4=k3/k3k4;
220 }
221 if(isnan(k3)) {k3=k1k3-k1; k4=0.0;}
222 if(verbose>1) {
223 printf("k2 := %g\n", k2);
224 printf("k3 := %g\n", k3);
225 printf("k4 := %g\n", k4);
226 }
227 if(k1<0.0 || k3<0.0 || k4<0.0) {
228 fprintf(stderr, "Error: invalid parameter value(s) in '%s'.\n", parfile);
229 dftEmpty(&blood); dftEmpty(&sim); iftEmpty(&ift);
230 return(4);
231 }
232 iftEmpty(&ift);
233
234
235 /*
236 * Read blood file
237 */
238 if(verbose>1) printf("reading %s\n", blofile);
239 if(dftRead(blofile, &blood)) {
240 fprintf(stderr, "Error in reading '%s': %s\n", blofile, dfterrmsg);
241 return(5);
242 }
243 if(blood.voiNr>1) {
244 blood.voiNr=1;
245 fprintf(stderr, "Warning: input file contains extra column(s).\n");
246 }
247 if(blood.frameNr<3) {
248 fprintf(stderr, "Error: blood data not valid.\n");
249 dftEmpty(&blood); dftEmpty(&sim);
250 return(5);
251 }
252 /* Make sure that sample times are in seconds */
253 int times_changed=0;
254 if(blood.timeunit==TUNIT_UNKNOWN && blood.x[blood.frameNr-1]<15.0) {
255 fprintf(stderr, "Warning: assuming that BTAC sample times are in minutes.\n");
256 blood.timeunit=TUNIT_MIN;
257 }
258 if(blood.timeunit==TUNIT_MIN) {
259 dftMin2sec(&blood); times_changed=1;
260 }
261
262
263 /*
264 * Allocate memory for simulated water and oxygen TACs
265 */
266 if(dftdup(&blood, &sim)) {
267 fprintf(stderr, "Error: cannot allocate memory for simulated TACs.\n");
268 dftEmpty(&blood); dftEmpty(&sim);
269 return(6);
270 }
271 strcpy(sim.voi[0].hemisphere, ""); strcpy(sim.voi[0].place, "");
272
273 /*
274 * Simulate the water TAC
275 */
276 if(verbose>1) printf("simulating\n");
277 ret=simC3s(blood.x, blood.voi[0].y, blood.frameNr, k1, k2, k3, k4, 0, 0,
278 blood.voi[0].y2, blood.voi[0].y3, NULL, NULL);
279 if(ret) {
280 fprintf(stderr, "Error in simulation of metabolism (%d).\n", ret);
281 dftEmpty(&blood); dftEmpty(&sim); return(7);
282 }
283 /* Correct simulated water TAC for delay */
284 for(int i=0; i<blood.frameNr; i++) blood.x1[i]=blood.x[i]+delay;
286 ret=interpolate(blood.x1, blood.voi[0].y3, blood.frameNr, sim.x,
287 sim.voi[0].y, sim.voi[0].y2, NULL, sim.frameNr);
288 if(ret) {
289 fprintf(stderr, "Error in simulation of delay (%d).\n", ret);
290 dftEmpty(&blood); dftEmpty(&sim); return(8);
291 }
292 /* Write the file */
293 if(verbose>1) printf("writing O15-water TAC in %s\n", watfile);
294 if(times_changed) dftSec2min(&sim);
295 strcpy(sim.voi[0].voiname, "Water");
296 strcpy(sim.voi[0].name, sim.voi[0].voiname);
297 if(dftWrite(&sim, watfile)) {
298 fprintf(stderr, "Error in writing '%s': %s\n", watfile, dfterrmsg);
299 dftEmpty(&blood); dftEmpty(&sim); return(11);
300 }
301 if(verbose==1) printf("O15-water BTAC written in %s\n", watfile);
302
303 /*
304 * Calculate the oxygen-15 blood TAC
305 */
306 /* Subtract delayed water TAC from blood curve; this equals O15-oxygen */
307 for(int i=0; i<sim.frameNr; i++)
308 sim.voi[0].y[i]=blood.voi[0].y[i]-sim.voi[0].y[i];
309 /* Write the file */
310 if(verbose>1) printf("writing O15-oxygen TAC in %s\n", oxyfile);
311 strcpy(sim.voi[0].voiname, "Oxygen");
312 strcpy(sim.voi[0].name, sim.voi[0].voiname);
313 if(dftWrite(&sim, oxyfile)) {
314 fprintf(stderr, "Error in writing '%s': %s\n", oxyfile, dfterrmsg);
315 dftEmpty(&blood); dftEmpty(&sim); return(12);
316 }
317 if(verbose==1) printf("O15-oxygen BTAC written in %s\n", oxyfile);
318
319
320 dftEmpty(&blood); dftEmpty(&sim);
321 return(0);
322}
323/*****************************************************************************/
324
325/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
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 dftEmpty(DFT *data)
Definition dft.c:20
int dftRead(char *filename, DFT *data)
Definition dftio.c:22
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
void dftSec2min(DFT *dft)
Definition dftunit.c:160
void dftMin2sec(DFT *dft)
Definition dftunit.c:145
void iftEmpty(IFT *ift)
Definition ift.c:60
void iftInit(IFT *ift)
Definition ift.c:45
int iftRead(IFT *ift, char *filename, int is_key_required, int verbose)
Definition iftfile.c:24
int iftGet(IFT *ift, char *key, int verbose)
Definition iftsrch.c:15
int interpolate(double *x, double *y, int nr, double *newx, double *newy, double *newyi, double *newyii, int newnr)
Linear interpolation and integration.
Definition integr.c:28
Header file for libtpccurveio.
void resInit(RES *res)
Definition result.c:52
#define DFT_TIME_MIDDLE
int resRead(char *filename, RES *res, int verbose)
Definition result.c:199
int res2ift(RES *res, IFT *ift, int verbose)
Definition resift.c:14
void resEmpty(RES *res)
Definition result.c:22
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
int petCunitId(const char *unit)
Definition petunits.c:74
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
int petTunitId(const char *timeunit)
Definition petunits.c:187
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
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
int timetype
Voi * voi
int timeunit
double * x1
int voiNr
int frameNr
double * x
IFT_KEY_AND_VALUE * item
Definition libtpcmisc.h:279
double * y2
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
char name[MAX_REGIONNAME_LEN+1]
double * y3
char hemisphere[MAX_REGIONSUBNAME_LEN+1]
char place[MAX_REGIONSUBNAME_LEN+1]