8#include "tpcclibConfig.h"
21static char *info[] = {
22 "Simulation of PET tissue time-radioactivity concentration curve (TTAC) using",
23 "dual-input four-tissue compartmental models. Input consists of parent tracer",
24 "and metabolite concentration curves in arterial plasma (Cap and Cam) and",
25 "total radioactivity concentration in arterial blood (Cb).",
27 "Tissue compartments for parent tracer are in series [1] (by default):",
29 " _____ K1 ____ k3 ____ k5 ____ k7 ",
30 " | Cap | ----> | C1 | ----> | C2 | ----> | C3 | ----> ",
31 " |_____| <---- |____| <---- |____| <---- |____| ",
36 " | Cam | ----> | C4 | ",
37 " |_____| <---- |____| ",
40 " dC1(t)/dt = K1*Cap(T) - (k2+k3+km)*C1(T) + k4*C2(T) ",
41 " dC2(t)/dt = k3*C1(T) - (k4+k5)*C2(T) + k6*C3(T) ",
42 " dC3(t)/dt = k5*C2(T) - (k6+k7)*C3(T) ",
43 " dC4(t)/dt = K1m*Cam(T) + km*C1(T) - k2m*C4(T) ",
44 " Ct(T) = C1(T) + C2(T) + C3(T) + C4(T) ",
45 " Cvb(T) = Cab(T) - dCt(t)/dt / f ",
46 " Cpet(T)= Vb*fA*Cab(T) + Vb*(1-fA)*Cvb(T) + (1-Vb)*Ct(T) ",
48 ", or, optionally, the 2nd and 3rd tissue compartments are parallel [2],",
49 "often used to represent specific and non-specific binding:",
57 " _____ K1 ____ k3 ____ ",
58 " | Cap | ----> | C1 | ----> | C2 | ",
59 " |_____| <---- |____| <---- |____| ",
64 " | Cam | ----> | C4 | ",
65 " |_____| <---- |____| ",
68 " dC1(t)/dt = K1*Ca(T) - (k2+k3+k5+km)*C1(T) + k4*C2(T) + k6*C3(T) ",
69 " dC2(t)/dt = k3*C1(T) - k4*C2(T) ",
70 " dC3(t)/dt = k5*C2(T) - (k6+k7)*C3(T) ",
71 " dC4(t)/dt = K1m*Cam(T) + km*C1(T) - k2m*C4(T) ",
72 " Ct(T) = C1(T) + C2(T) + C3(T) + C4(T) ",
73 " Cvb(T) = Cab(T) - dCt(t)/dt / f ",
74 " Cpet(T)= Vb*fA*Cab(T) + Vb*(1-fA)*Cvb(T) + (1-Vb)*Ct(T) ",
76 "Usage: @P [options] parentfile metabolitefile bloodfile"
77 " K1 k2 k3 k4 k5 k6 k7 km K1m k2m Vb simfile",
81 " Model with parallel compartments C2 and C3 is applied.",
83 " Model with compartments C1, C2, and C3 in series is applied (default).",
85 " TACs of sub-compartments (C1, C2 and C3) are written (-sub)",
86 " or not written (-nosub, default) into the output file.",
87 " -f=<Perfusion (ml/(min*ml) or ml/(sec*ml))>",
88 " Difference between concentrations in venous and arterial blood can",
89 " be simulated if tissue perfusion (f>K1) is specified with this option",
90 " and arterial fraction of vascular volume is set with option -fA;",
91 " by default it is assumed that venous and arterial activities are",
93 " -fA=<Arterial fraction of vascular volume (%)>",
94 " Difference between concentrations in venous and arterial blood can",
95 " be simulated if arterial fraction of vascular volume is specified with",
96 " this option and tissue perfusion is set with option -f;",
97 " by default it is assumed that Vb consists of only arterial blood.",
100 "If the times in plasma file are in seconds, the units of rate constants",
101 "(k's) and blood flow (f) must also be specified as 1/sec.",
102 "For accurate results, plasma TAC should have very short sampling intervals.",
103 "To reduce the model, k7, k5, and k3 can be set to 0.",
105 "Simulated TACs are written in ASCII format with columns:",
107 " 2) Total tissue activity concentration (Cpet)",
108 " 3) Activity concentration in 1st tissue compartment, (1-Vb)*C1 (optional)",
109 " 4) Activity concentration in 2nd tissue compartment, (1-Vb)*C2 (optional)",
110 " 5) Activity concentration in 3rd tissue compartment, (1-Vb)*C3 (optional)",
111 " 6) Activity concentration in 4th tissue compartment, (1-Vb)*C4 (optional)",
112 " 7) Arterial contribution to tissue activity, Vb*fA*Cab (optional)",
113 " 8) Venous contribution to tissue activity, Vb*(1-fA)*Cvb (optional)",
116 "1. TPCMOD0001 Appendix B.",
117 "2. TPCMOD0001 Appendix C.",
119 "See also: sim_3tcm, tacadd, tacren, simframe, tacformat, dft2img",
121 "Keywords: TAC, simulation, modelling, compartmental model, dual-input",
140int main(
int argc,
char **argv)
142 int ai, help=0, version=0, verbose=1;
143 int fi, ri, ret, save_only_total=1;
146 double k1, k2, k3, k4, k5, k6, k7, km, k1m, k2m, f, Vb, fA;
147 double *t, *cap, *cam, *cab, *cpet, *ct1, *ct2, *ct3, *ct4, *ctab, *ctvb;
148 char pfile[FILENAME_MAX], mfile[FILENAME_MAX], bfile[FILENAME_MAX],
149 sfile[FILENAME_MAX], *cptr, tmp[FILENAME_MAX+128];
156 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
157 pfile[0]=mfile[0]=bfile[0]=sfile[0]=(char)0;
158 k1=k2=k3=k4=k5=k6=k7=km=k1m=k2m=Vb=-1.0;
162 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
163 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
166 if(strncasecmp(cptr,
"NOSUB", 5)==0) {
167 save_only_total=1;
continue;
168 }
else if(strncasecmp(cptr,
"SUB", 3)==0) {
169 save_only_total=0;
continue;
170 }
else if(strncasecmp(cptr,
"PARALLEL", 5)==0) {
171 parallel=1;
continue;
172 }
else if(strncasecmp(cptr,
"SERIES", 3)==0) {
173 parallel=0;
continue;
174 }
else if(strncasecmp(cptr,
"F=", 2)==0) {
176 }
else if(strncasecmp(cptr,
"FA=", 3)==0) {
178 if(ret==0 && fA>=0.0 && fA<100.0) {fA*=0.01;
continue;}
180 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
185 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
190 for(; ai<argc; ai++) {
192 strcpy(pfile, argv[ai]);
continue;
193 }
else if(!mfile[0]) {
194 strcpy(mfile, argv[ai]);
continue;
195 }
else if(!bfile[0]) {
196 strcpy(bfile, argv[ai]);
continue;
198 k1=
atof_dpi(argv[ai]);
if(k1<0.0) k1=0.0;
continue;
200 k2=
atof_dpi(argv[ai]);
if(k2<0.0) k2=0.0;
continue;
202 k3=
atof_dpi(argv[ai]);
if(k3<0.0) k3=0.0;
continue;
204 k4=
atof_dpi(argv[ai]);
if(k4<0.0) k4=0.0;
continue;
206 k5=
atof_dpi(argv[ai]);
if(k5<0.0) k5=0.0;
continue;
208 k6=
atof_dpi(argv[ai]);
if(k6<0.0) k6=0.0;
continue;
210 k7=
atof_dpi(argv[ai]);
if(k7<0.0) k7=0.0;
continue;
212 km=
atof_dpi(argv[ai]);
if(km<0.0) km=0.0;
continue;
214 k1m=
atof_dpi(argv[ai]);
if(k1m<0.0) k1m=0.0;
continue;
216 k2m=
atof_dpi(argv[ai]);
if(k2m<0.0) k2m=0.0;
continue;
219 if(ret==0 && Vb>=0.0 && Vb<100.0) {Vb*=0.01;
continue;}
220 }
else if(!sfile[0]) {
221 strcpy(sfile, argv[ai]);
continue;
223 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
229 if(!sfile[0] || Vb<0.0) {
tpcPrintUsage(argv[0], info, stdout);
return(1);}
231 if(f>0.0 && k1>0.0 && f<k1) {
232 fprintf(stderr,
"Error: f cannot be lower than K1!\n");
return(1);}
233 if(f>0.0 && k1m>0.0 && f<k1m) {
234 fprintf(stderr,
"Error: f cannot be lower than K1m!\n");
return(1);}
235 if(Vb<=0.0 && (fA<1.0 || f>0.0))
236 fprintf(stderr,
"Warning: options -fA and -f are ignored when Vb=0%%\n");
237 else if(f>0.0 && fA==1.0)
238 fprintf(stderr,
"Warning: option -f is ignored when fA=100%%\n");
239 if(k1>1.0E+08 || k2>1.0E+08 || k3>1.0E+08 || k4>1.0E+08 || k5>1.0E+08 ||
240 k6>1.0E+08 || k7>1.0E+08 || km>1.0E+08 || k1m>1.0E+08 || k2m>1.0E+08) {
241 fprintf(stderr,
"Error: too high rate constant.\n");
return(1);
246 printf(
"pfile := %s\n", pfile);
247 printf(
"mfile := %s\n", mfile);
248 printf(
"bfile := %s\n", bfile);
249 printf(
"sfile := %s\n", sfile);
250 printf(
"rate_constants := %g %g %g %g %g %g %g %g %g %g\n",
251 k1, k2, k3, k4, k5, k6, k7, km, k1m, k2m);
252 printf(
"Vb := %g\n", Vb);
253 printf(
"fA := %g\n", fA);
254 printf(
"f := %g\n", f);
255 printf(
"save_only_total := %d\n", save_only_total);
256 printf(
"parallel := %d\n", parallel);
263 if(verbose>1) printf(
"reading plasma parent TAC\n");
265 fprintf(stderr,
"Error in reading '%s': %s\n", pfile,
dfterrmsg);
269 fprintf(stderr,
"Error: too few samples in plasma data.\n");
273 fprintf(stderr,
"Error: plasma data contains more than one curve.\n");
276 if(plasma.
timeunit==TUNIT_UNKNOWN) {
278 if(verbose>=0) printf(
"assuming that time unit is min\n");
287 if(verbose>1) printf(
"reading plasma metabolite TAC\n");
289 fprintf(stderr,
"Error in reading '%s': %s\n", mfile,
dfterrmsg);
293 fprintf(stderr,
"Error: too few samples in metabolite data.\n");
297 fprintf(stderr,
"Error: metabolite data contains more than one curve.\n");
302 fprintf(stderr,
"Warning: metabolite TAC is shorter than parent TAC.\n");
306 fprintf(stderr,
"Error: cannot allocate memory for metabolite TAC.\n");
316 fprintf(stderr,
"Error: cannot interpolate metabolite data.\n");
323 fprintf(stderr,
"Warning: plasma metabolite concentration <= 0.\n");
330 if(verbose>1) printf(
"reading blood\n");
332 fprintf(stderr,
"Error in reading '%s': %s\n", bfile,
dfterrmsg);
336 fprintf(stderr,
"Error: too few samples in blood data.\n");
340 fprintf(stderr,
"Error: blood data contains more than one curve.\n");
345 fprintf(stderr,
"Warning: blood TAC is much shorter than plasma TAC.\n");
349 fprintf(stderr,
"Error: cannot allocate memory for blood TAC.\n");
359 fprintf(stderr,
"Error: cannot interpolate blood data.\n");
366 fprintf(stderr,
"Warning: blood concentration <= 0.\n");
371 strcpy(tmp,
"simulation_input.dat");
372 printf(
"Saving input in %s for testing.\n", tmp);
374 fprintf(stderr,
"Error in writing '%s': %s\n", tmp,
dfterrmsg);
382 if(verbose>1) printf(
"allocating memory\n");
387 "Error (%d): cannot allocate memory for simulated TACs.\n", ret);
393 for(fi=0; fi<sim.
frameNr; fi++) {
394 sim.
x[fi]=plasma.
x[fi];
395 sim.
x1[fi]=plasma.
x1[fi]; sim.
x2[fi]=plasma.
x2[fi];
398 for(ri=0; ri<sim.
voiNr; ri++) {
420 sim.
voi[ri].
size=100.0*(1.0-fA)*Vb;
430 if(verbose>1) printf(
"simulating\n");
431 t=sim.
x; cap=plasma.
voi[0].
y; cam=plasma.
voi[1].
y; cab=plasma.
voi[2].
y;
436 k1, k2, k3, k4, k5, k6, k7, km, k1m, k2m, f, Vb, fA,
437 cpet, ct1, ct2, ct3, ct4, ctab, ctvb, verbose-1);
440 k1, k2, k3, k4, k5, k6, k7, km, k1m, k2m, f, Vb, fA,
441 cpet, ct1, ct2, ct3, ct4, ctab, ctvb, verbose-1);
444 fprintf(stderr,
"Error (%d) in simulation.\n", ret);
452 if(verbose>1) printf(
"saving PET curves\n");
454 if(save_only_total) sim.
voiNr=1;
455 else if(Vb<=0.0) sim.
voiNr=5;
459 sprintf(tmp,
"# parentfile := %s\n", pfile); strcat(sim.
comments, tmp);
460 sprintf(tmp,
"# metabolitefile := %s\n", mfile); strcat(sim.
comments, tmp);
461 sprintf(tmp,
"# bloodfile := %s\n", bfile); strcat(sim.
comments, tmp);
462 strcpy(tmp,
"# model := ");
463 if(parallel==0) strcat(tmp,
"C4DIVS\n");
else strcat(tmp,
"C4DIVP\n");
465 sprintf(tmp,
"# K1 := %g\n", k1); strcat(sim.
comments, tmp);
466 sprintf(tmp,
"# k2 := %g\n", k2); strcat(sim.
comments, tmp);
467 sprintf(tmp,
"# k3 := %g\n", k3); strcat(sim.
comments, tmp);
468 sprintf(tmp,
"# k4 := %g\n", k4); strcat(sim.
comments, tmp);
469 sprintf(tmp,
"# k5 := %g\n", k5); strcat(sim.
comments, tmp);
470 sprintf(tmp,
"# k6 := %g\n", k6); strcat(sim.
comments, tmp);
471 sprintf(tmp,
"# k7 := %g\n", k7); strcat(sim.
comments, tmp);
472 sprintf(tmp,
"# km := %g\n", km); strcat(sim.
comments, tmp);
473 sprintf(tmp,
"# K1m := %g\n", k1m); strcat(sim.
comments, tmp);
474 sprintf(tmp,
"# k2m := %g\n", k2m); strcat(sim.
comments, tmp);
476 sprintf(tmp,
"# f := %g\n", f); strcat(sim.
comments, tmp);
477 sprintf(tmp,
"# Vb := %g [%%]\n", 100.0*Vb); strcat(sim.
comments, tmp);
478 sprintf(tmp,
"# fA := %g [%%]\n", 100.0*fA); strcat(sim.
comments, tmp);
488 fprintf(stderr,
"Error in writing '%s': %s\n", sfile,
dfterrmsg);
491 if(verbose>0) fprintf(stdout,
"simulated TAC(s) written in %s\n", sfile);
int atof_with_check(char *double_as_string, double *result_value)
double atof_dpi(char *str)
int dftAddmem(DFT *dft, int voiNr)
void dftSetComments(DFT *dft)
int dftSetmem(DFT *data, int frameNr, int voiNr)
int dftCopymainhdr(DFT *dft1, DFT *dft2)
int dftRead(char *filename, DFT *data)
int dftWrite(DFT *data, char *filename)
char * filenameGetExtension(char *s)
Get the last extension of a filename.
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_FORMAT_STANDARD
#define DFT_FORMAT_UNKNOWN
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
void tpcPrintBuild(const char *program, FILE *fp)
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Header file for libtpcmodel.
int simC4DIvp(double *t, double *ca1, double *ca2, double *cb, int nr, double k1, double k2, double k3, double k4, double k5, double k6, double k7, double km, double k1b, double k2b, double f, double vb, double fa, double *scpet, double *sct1, double *sct2, double *sct3, double *sct1b, double *sctab, double *sctvb, int verbose)
int simC4DIvs(double *t, double *ca1, double *ca2, double *cb, int nr, double k1, double k2, double k3, double k4, double k5, double k6, double k7, double km, double k1b, double k2b, double f, double vb, double fa, double *scpet, double *sct1, double *sct2, double *sct3, double *sct1b, double *sctab, double *sctvb, int verbose)
char comments[_DFT_COMMENT_LEN+1]
char voiname[MAX_REGIONSUBNAME_LEN+1]
char name[MAX_REGIONNAME_LEN+1]
char hemisphere[MAX_REGIONSUBNAME_LEN+1]
char place[MAX_REGIONSUBNAME_LEN+1]