9#include "tpcclibConfig.h"
23static char *info[] = {
24 "Simulation of PET tissue time-radioactivity concentration curve (TTAC)",
25 "in skeletal muscle [O-15]O2 PET studies from decay corrected arterial blood",
26 "[O-15]O2 and [O-15]H2O curves (oxygen and water BTACs).",
27 "The compartmental model for [O-15]O2 in skeletal muscle is:",
30 " _______________________________________ ",
32 " | O ----------> O + O -Mb | ",
33 " | 2 <---------- 2 2 | ",
38 " | H O ----------> H O | ",
39 " | 2 <---------- 2 | ",
41 " |______________|________________________| ",
44 " K1=perfusion (f, mL/min/dL), OER=k3/(k2+k3),",
45 " Ki=f*OER (mL/min/dL), and",
46 " Metabolic rate of oxygen MRO2=Ki*[O2]a (mmol/min/dL)",
48 "Usage: @P [options] obtacfile wbtacfile f OER ttacfile",
52 " TACs of sub-compartments are written (-sub)",
53 " or not written (-nosub, default) into the output file.",
55 " Simulated TACs are added to an existing tissue data file.",
56 " By default, existing file is overwritten.",
57 " -Vb=<Blood volume (%)>",
58 " Set the simulated blood volume; default is 3.5%.",
59 " -Af=<Arterial proportion (%)>",
60 " Set the simulated arterial proportion of total blood volume;",
63 " Set the partition coefficient of water; default is 0.99.",
65 " Set the K1/k2 for oxygen; by default the K1/k2 is estimated from",
66 " OER and saturation curves for hemoglobin and myoglobin.",
68 " Saturation of arterial blood hemoglobin; default is 0.97.",
70 " Half-saturation pressure for hemoglobin; default is 3.6 kPa.",
72 " Half-saturation pressure for myoglobin; default is 0.319 kPa.",
74 " Hill coefficient for hemoglobin; default is 2.7.",
76 " Concentration of myoglobin in muscle; default is 4.7 mg/g.",
78 " Concentration of hemoglobin in blood; default is 150 mg/g.",
80 " Blood flow (perfusion) is assumed to be given per perfusable tissue",
81 " volume excluding vascular volume. TTAC will still be simulated per",
82 " regional PET volume including vascular volume.",
84 " Enter a name (1-6 chars without spaces) for the simulated TTAC.",
86 " Save the simulated venous [O-15]O2 BTAC",
88 " Save the simulated venous [O-15]H2O BTAC",
91 "For accurate results, input BTACs should be noiseless and have very",
92 "short sampling intervals. Simulated curves can thereafter be interpolated",
93 "to represent PET frames using program simframe.",
94 "Calculated tissue activities are written in the specified file with",
95 "these data columns. Columns 2-6 will be saved optionally (-sub):",
97 " 1) Total regional radioactivity concentration (2+3+4+5+6)",
98 " 2) Labelled [O2] component of TTAC",
99 " 3) Labelled [H2O] component of TTAC",
100 " 4) Arterial BTAC component of TTAC",
101 " 5) Venous labelled [O2] component of TTAC",
102 " 6) Venous labelled [H2O] component of TTAC",
105 "1. Nuutila P, Peltoniemi P, Oikonen V, Larmola K, Kemppainen J, Takala T,",
106 " Sipila H, Oksanen A, Ruotsalainen U, Bolli GB, Yki-Jarvinen H.",
107 " Enhanced stimulation of glucose uptake by insulin increases",
108 " exercise-stimulated glucose uptake in skeletal muscle in humans: studies",
109 " using [15O]O2, [15O]H2O, [18F]fluoro-deoxy-glucose, and positron emission",
110 " tomography. Diabetes 2000; 49:1084-1091.",
111 "2. Oikonen V, Nuutila P, Sipila H, Tolvanen T, Peltoniemi P, Ruotsalainen U.",
112 " Quantification of oxygen consumption in skeletal muscle with PET and",
113 " oxygen-15 bolus. Eur J Nucl Med. 1998; 25: 1151.",
114 "3. Oikonen V. Modelling of low oxygen consumption. In: J. Knuuti, J. Rinne,",
115 " P.Tenhonen (ed.), Medical Applications of Cyclotrons VIII. Abstracts of",
116 " the VIII Symposium on the Medical Applications of Cyclotrons.",
117 " Annales Universitatis Turkuensis D346:16, 1999.",
119 "See also: fit_mo2, o2metab, o2_p2w, fit_o2bl, sim_o2bl, tacadd, simframe",
121 "Keywords: TAC, simulation, modelling, oxygen, skeletal muscle",
140int main(
int argc,
char **argv)
142 int ai, help=0, version=0, verbose=1;
143 char ofile[FILENAME_MAX], wfile[FILENAME_MAX], dfile[FILENAME_MAX];
144 char vofile[FILENAME_MAX], vwfile[FILENAME_MAX];
146 int save_only_total=1;
147 int flow_per_tissue=0;
148 int add_to_previous=0;
149 int K1k2_def_changed=0;
176 int n, ret, times_changed=0;
182 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
183 ofile[0]=wfile[0]=dfile[0]=vofile[0]=vwfile[0]=(char)0;
184 strcpy(voiname,
"Muscle");
185 fK1k2=Flow=OER=nan(
"");
188 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
189 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
191 if(strncasecmp(cptr,
"NOSUB", 5)==0) {
192 save_only_total=1;
continue;
193 }
else if(strncasecmp(cptr,
"SUB", 3)==0) {
194 save_only_total=0;
continue;
195 }
else if(strcasecmp(cptr,
"FPT")==0) {
196 flow_per_tissue=1;
continue;
197 }
else if(strcasecmp(cptr,
"ADD")==0) {
198 add_to_previous=1;
continue;
199 }
else if(strncasecmp(cptr,
"VOINAME=", 8)==0) {
202 fprintf(stderr,
"Error: invalid VOI name '%s'.\n", cptr+8);
return(1);}
204 }
else if(strncasecmp(cptr,
"VENAO=", 6)==0) {
205 n=
strlcpy(vofile, cptr+6, FILENAME_MAX);
206 if(n>0 && n<FILENAME_MAX)
continue;
207 }
else if(strncasecmp(cptr,
"VENAW=", 6)==0) {
208 n=
strlcpy(vwfile, cptr+6, FILENAME_MAX);
209 if(n>0 && n<FILENAME_MAX)
continue;
210 }
else if(strncasecmp(cptr,
"Vb=", 3)==0) {
212 }
else if(strncasecmp(cptr,
"Af=", 3)==0) {
214 }
else if(strncasecmp(cptr,
"pH2O=", 5)==0) {
216 }
else if(strncasecmp(cptr,
"K1k2=", 5)==0) {
218 }
else if(strncasecmp(cptr,
"sao2=", 5)==0) {
220 }
else if(strncasecmp(cptr,
"p50hb=", 6)==0) {
222 }
else if(strncasecmp(cptr,
"p50mb=", 6)==0) {
224 }
else if(strncasecmp(cptr,
"nhb=", 4)==0) {
226 }
else if(strncasecmp(cptr,
"hb=", 3)==0) {
228 }
else if(strncasecmp(cptr,
"mb=", 3)==0) {
231 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
236 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
241 for(; ai<argc; ai++) {
242 if(!ofile[0]) {
strlcpy(ofile, argv[ai], FILENAME_MAX);
continue;}
243 else if(!wfile[0]) {
strlcpy(wfile, argv[ai], FILENAME_MAX);
continue;}
246 else if(!dfile[0]) {
strlcpy(dfile, argv[ai], FILENAME_MAX);
continue;}
247 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
254 fprintf(stderr,
"Error: missing command-line argument.\n\n");
259 if(Af<0.0 || Af>1.0) {
260 fprintf(stderr,
"Error: invalid arterial fraction.\n");
return(1);
262 if(Af>0.0 && Af<0.01) {
264 fprintf(stderr,
"Warning: arterial fraction was set to %g%%.\n", 100.0*Af);
266 if(Vb<0.0 || Vb>=1.0) {
267 fprintf(stderr,
"Error: invalid blood volume.\n");
return(1);
269 if(Vb>0.0 && Vb<0.01) {
271 fprintf(stderr,
"Warning: arterial fraction was set to %g%%.\n", 100.0*Vb);
273 if(pH2O>1.0 || pH2O<=0.) {
274 fprintf(stderr,
"Error: invalid partition constant for water.\n");
277 if(OER>10.0 && OER<95.0) OER/=100.;
278 if(OER<=0.0 || OER>=1.0) {
279 fprintf(stderr,
"Error: invalid OER.\n");
return(1);
281 if(K1k2_def_changed!=0 && fK1k2>0.0)
282 fprintf(stderr,
"Warning: option(s) superseded by -K1k2.\n");
284 fprintf(stderr,
"Error: invalid SaO2.\n");
return(1);
286 if(
p50Hb<=0.0) {fprintf(stderr,
"Error: invalid p50Hb.\n");
return(1);}
287 if(
p50Mb<=0.0) {fprintf(stderr,
"Error: invalid p50Mb.\n");
return(1);}
288 if(
nHb<=0.0) {fprintf(stderr,
"Error: invalid nHb.\n");
return(1);}
289 if(
cMb<=0.0) {fprintf(stderr,
"Error: invalid [Mb].\n");
return(1);}
290 if(
cHb<=0.0) {fprintf(stderr,
"Error: invalid [Hb].\n");
return(1);}
295 printf(
"save_only_total := %d\n", save_only_total);
296 printf(
"flow_per_tissue := %d\n", flow_per_tissue);
297 printf(
"add_to_previous := %d\n", add_to_previous);
298 printf(
"ofile := %s\n", ofile);
299 printf(
"wfile := %s\n", wfile);
300 printf(
"dfile := %s\n", dfile);
301 if(vofile[0]) printf(
"vofile := %s\n", vofile);
302 if(vwfile[0]) printf(
"vwfile := %s\n", vwfile);
303 printf(
"Vb := %g%%\n", 100.*Vb);
304 printf(
"Af := %g%%\n", 100.*Af);
305 printf(
"pH2O := %g\n", pH2O);
306 printf(
"Flow := %g mL/dL/min\n", 6000.*Flow);
307 printf(
"OER := %g\n", OER);
308 printf(
"SaO2 := %g\n",
SaO2);
309 printf(
"p50Hb := %g\n",
p50Hb);
310 printf(
"p50Mb := %g\n",
p50Mb);
311 printf(
"nHb := %g\n",
nHb);
312 printf(
"cMb := %g\n",
cMb);
313 printf(
"cHb := %g\n",
cHb);
314 if(!isnan(fK1k2)) printf(
"fK1k2 := %g\n", fK1k2);
315 if(voiname[0]) printf(
"voiname := %s\n", voiname);
322 if(verbose>1) printf(
"reading '%s'\n", ofile);
324 fprintf(stderr,
"Error in reading '%s': %s\n", ofile,
dfterrmsg);
328 fprintf(stderr,
"Error: not enough input samples for decent simulation.\n");
335 fprintf(stderr,
"Error: missing sample(s) in %s\n", ofile);
339 fprintf(stderr,
"Warning: [O-15]O2 BTAC file may not be valid.\n");
345 if(verbose>0) fprintf(stdout,
"Note: sample times assumed to be in min.\n");
348 if(verbose>0) fprintf(stdout,
"Note: sample times assumed to be in sec.\n");
354 fprintf(stderr,
"Note: Oxygen BTAC sample times are converted to sec.\n");
361 if(verbose>1) printf(
"reading '%s'\n", wfile);
363 fprintf(stderr,
"Error in reading '%s': %s\n", wfile,
dfterrmsg);
367 fprintf(stderr,
"Error: not enough samples for decent simulation.\n");
372 fprintf(stderr,
"Error: missing sample(s) in %s\n", wfile);
378 fprintf(stderr,
"Warning: [O-15]H2O BTAC file may not be valid.\n");
384 if(verbose>0) fprintf(stdout,
"Note: sample times assumed to be in min.\n");
387 if(verbose>0) fprintf(stdout,
"Note: sample times assumed to be in sec.\n");
393 fprintf(stderr,
"Note: Radiowater BTAC sample times are converted to sec.\n");
398 fprintf(stderr,
"Error: [O-15]H2O BTAC is shorter than [O-15]O2 BTAC.\n");
402 fprintf(stderr,
"Warning: [O-15]H2O BTAC is shorter than [O-15]O2 BTAC.\n");
405 fprintf(stderr,
"Error: cannot allocate more memory.\n");
412 fprintf(stderr,
"Error: cannot interpolate [O-15]H2O BTAC.\n");
423 for(
int ri=0; ri<input.
voiNr && !ret; ri++) {
431 fprintf(stderr,
"Error: Cannot integrate input BTACs.\n");
439 if(verbose>1) printf(
"allocating memory for simulated data\n");
441 fprintf(stderr,
"Error: cannot allocate memory for simulated TTACs.\n");
453 for(
int fi=0; fi<input.
frameNr; fi++) {
454 data.
x[fi]=input.
x[fi];
455 data.
x1[fi]=input.
x1[fi]; data.
x2[fi]=input.
x2[fi];
466 for(
int ri=1; ri<data.
voiNr; ri++) {
471 for(
int ri=0; ri<data.
voiNr; ri++)
479 if(verbose>1) printf(
"simulating TTACs\n");
480 double k1=Flow;
if(flow_per_tissue==0) k1/=(1.0-Vb);
483 if(!isnan(fK1k2)) k1k2=fK1k2;
486 double k3=k2o*OER/(1.0-OER);
490 printf(
"Vt_o := %g\n", k1/(k2o+k3));
492 printf(
"K1*k3/(k2+k3) := %g\n", v);
496 if(k2w>0.0) printf(
"Vt_w := %g\n", (v+k1)/k2w);
500 input.
frameNr, k1, k2o, k3, k1, k2w, Vb, Af,
507 fprintf(stderr,
"Error in simulation (%d).\n", ret);
517 if(verbose>1) printf(
"saving simulated TTAC.\n");
520 if(save_only_total!=0) data.
voiNr=1;
522 if(add_to_previous!=0 && access(dfile, 0)!=-1) {
523 if(verbose>0) printf(
"adding to existing file\n");
528 fprintf(stderr,
"Error in reading '%s': %s\n", dfile,
dfterrmsg);
532 printf(
"existing %d TACs with %d frames\n",prevdft.
voiNr,prevdft.
frameNr);
534 for(
int ri=0; ri<data.
voiNr; ri++) {
535 ret=
dftAdd(&prevdft, &data, ri);
537 fprintf(stderr,
"Error: cannot add simulated TAC in %s\n", dfile);
552 fprintf(stderr,
"Error in writing '%s': %s\n", dfile,
dfterrmsg);
556 if(verbose>=0) fprintf(stdout,
"Simulated TTAC(s) written in %s\n", dfile);
566 strcpy(data.
voi[0].
name,
"Venous_O2");
568 fprintf(stderr,
"Error in writing '%s': %s\n", vofile,
dfterrmsg);
572 fprintf(stdout,
"Simulated venous [O-15]O2 BTAC written in %s\n", vofile);
576 strcpy(data.
voi[0].
name,
"Venous_H2O");
578 fprintf(stderr,
"Error in writing '%s': %s\n", vwfile,
dfterrmsg);
582 fprintf(stdout,
"Simulated venous [O-15]H2O BTAC written in %s\n", vwfile);
int atof_with_check(char *double_as_string, double *result_value)
int dftCopyvoihdr(DFT *dft1, int from, DFT *dft2, int to)
int dftAddmem(DFT *dft, int voiNr)
void dftSetComments(DFT *dft)
int dftSortByFrame(DFT *dft)
int dftSetmem(DFT *data, int frameNr, int voiNr)
int dftAdd(DFT *data1, DFT *data2, int voi)
int dft_nr_of_NA(DFT *dft)
int dftCopymainhdr(DFT *dft1, DFT *dft2)
int dftRead(char *filename, DFT *data)
int dftWrite(DFT *data, char *filename)
void dftSec2min(DFT *dft)
void dftMin2sec(DFT *dft)
char * filenameGetExtension(char *s)
Get the last extension of a filename.
int petintegral(double *x1, double *x2, double *y, int nr, double *ie, double *iie)
Integrate PET TAC data to frame mid times.
int integrate(double *x, double *y, int nr, double *yi)
int interpolate(double *x, double *y, int nr, double *newx, double *newy, double *newyi, double *newyii, int newnr)
Linear interpolation and integration.
Header file for libtpccurveio.
#define DFT_DECAY_CORRECTED
#define DFT_TIME_STARTEND
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
int rnameCatenate(char *rname, int max_rname_len, char *name1, char *name2, char *name3, char space)
int rnameSplit(char *rname, char *name1, char *name2, char *name3, int max_name_len)
#define MAX_REGIONNAME_LEN
size_t strlcpy(char *dst, const char *src, size_t dstsize)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
void tpcPrintBuild(const char *program, FILE *fp)
#define MAX_REGIONSUBNAME_LEN
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Header file for libtpcmodel.
int simOxygen(double *t, double *ca1, double *ca2, double *ca1i, double *ca2i, const int n, const double k1a, const double k2a, const double km, const double k1b, const double k2b, const double vb, const double fa, double *scpet, double *sct1, double *sct2, double *sctab, double *sctvb1, double *sctvb2, double *scvb1, double *scvb2, const int verbose)
double mo2k1k2(const double OER, const double SaO2, const double p50Hb, const double p50Mb, const double nHb, const double cHb, const double cMb, const int verbose)
Calculates K1/k2 ratio for [O-15]O2 in muscle, based on OER.
Header file for libtpcmodext.
char radiopharmaceutical[32]
char voiname[MAX_REGIONSUBNAME_LEN+1]
char name[MAX_REGIONNAME_LEN+1]
char hemisphere[MAX_REGIONSUBNAME_LEN+1]
char place[MAX_REGIONSUBNAME_LEN+1]