8#include "tpcclibConfig.h"
24static char *info[] = {
25 "Simulation of PET tissue time-radioactivity concentration curves (TACs)",
26 "from arterial plasma (Ca) and blood (Cb) TACs, based on three-tissue",
27 "compartmental model, where the compartments are in series (default):",
29 " ____ K1 ____ k3 ____ k5 ____ ",
30 " | Ca | ----> | C1 | ----> | C2 | ----> | C3 | ",
31 " |____| <---- |____| <---- |____| <---- |____| ",
34 " dC1(t)/dt = K1*Ca(T) - (k2+k3)*C1(T) + k4*C2(T) ",
35 " dC2(t)/dt = k3*C1(T) - (k4+k5)*C2(T) + k6*C3(T) ",
36 " dC3(t)/dt = k5*C2(T) - k6*C3(T) ",
37 " Ct(T) = C1(T) + C2(T) + C3(T) ",
38 " Cvb(T) = Cab(T) - dCt(t)/dt / f ",
39 " Cpet(T)= Vb*fA*Cab(T) + Vb*(1-fA)*Cvb(T) + (1-Vb)*Ct(T) ",
41 ", or, optionally, three-tissue compartmental model, where the 2nd and 3rd",
42 "tissue compartments are parallel, often used to represent specific and",
43 "non-specific binding:",
45 " ____ K1 ____ k3 ____ ",
46 " | Ca | ----> | C1 | ----> | C2 | ",
47 " |____| <---- |____| <---- |____| ",
56 " dC1(t)/dt = K1*Ca(T) - (k2+k3+k5)*C1(T) + k4*C2(T) + k6*C3(T) ",
57 " dC2(t)/dt = k3*C1(T) - k4*C2(T) ",
58 " dC3(t)/dt = k5*C1(T) - k6*C3(T) ",
59 " Ct(T) = C1(T) + C2(T) + C3(T) ",
60 " Cvb(T) = Cab(T) - dCt(t)/dt / f ",
61 " Cpet(T)= Vb*fA*Cab(T) + Vb*(1-fA)*Cvb(T) + (1-Vb)*Ct(T) ",
63 "Usage: @P [options] parfile [plasmafile bloodfile simfile]",
67 " Model with parallel compartments C2 and C3 is applied, overriding",
68 " possible model settings in parameter file.",
70 " Model with compartments C1, C2, and C3 in series is applied, overriding",
71 " possible model settings in parameter file.",
73 " Vascular volume is modelled as (1, default)",
74 " Cpet(T)= Vb*fA*Cab(T) + Vb*(1-fA)*Cvb(T) + (1-Vb)*Ct(T)",
76 " Cpet(T)= Vb*fA*Cab(T) + Vb*(1-fA)*Cvb(T) + Ct(T).",
78 " TACs of sub-compartments (C1, C2 and C3) are written (-sub)",
79 " or not written (-nosub, default) into the simfile.",
82 "To create a template parameter file, do not enter names for input and",
83 "simulated TACs. Obligatory parameters are:",
84 "K1, k2 (or K1/k2), k3, k4 (or k3/k4), k5, k6 (or k5/k6), and Vb.",
85 "Additionally, values for perfusion (f), arterial fraction of Vb (fA), and",
86 "delay time (dT) can be set; otherwise it is assumed that f>>K1, Cvb=Cab,",
88 "If parameter file does not contain units, then per min and per mL units",
89 "are assumed, except sec for dT.",
90 "For accurate results, plasma TAC should have very short sampling intervals.",
91 "To reduce the model, k5 or k3 can be set to 0.",
92 "When blood file is not used (Vb=0), 'none' can be entered in its place.",
94 "See also: simdisp, p2t_di, sim_rtcm, tacadd, simframe, tacformat, dft2img",
96 "Keywords: TAC, simulation, modelling, compartmental model",
115int main(
int argc,
char **argv)
117 int ai, help=0, version=0, verbose=1;
118 char plafile[FILENAME_MAX], blofile[FILENAME_MAX],
119 simfile[FILENAME_MAX], parfile[FILENAME_MAX];
121 unsigned int model=0;
122 unsigned int parNr=0;
123 int save_only_total=1;
133 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
134 plafile[0]=blofile[0]=simfile[0]=parfile[0]=(char)0;
138 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
140 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
141 if(strncasecmp(cptr,
"NOSUB", 5)==0) {
142 save_only_total=1;
continue;
143 }
else if(strncasecmp(cptr,
"SUB", 3)==0) {
144 save_only_total=0;
continue;
145 }
else if(strncasecmp(cptr,
"PARALLEL", 5)==0) {
147 }
else if(strncasecmp(cptr,
"SERIES", 3)==0) {
149 }
else if(strncasecmp(cptr,
"VVM=", 4)==0) {
150 if(
atoiCheck(cptr+4, &vvm)==0 && vvm>=1 && vvm<=2) {vvm--;
continue;}
152 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
161 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
166 if(ai<argc)
strlcpy(parfile, argv[ai++], FILENAME_MAX);
167 if(ai<argc)
strlcpy(plafile, argv[ai++], FILENAME_MAX);
168 if(ai<argc)
strlcpy(blofile, argv[ai++], FILENAME_MAX);
169 if(ai<argc)
strlcpy(simfile, argv[ai++], FILENAME_MAX);
171 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
177 fprintf(stderr,
"Error: missing parameter file; use option --help\n");
180 if(plafile[0] && !simfile[0]) {
181 fprintf(stderr,
"Error: missing filename.\n");
184 if(strcasecmp(blofile,
"NONE")==0) strcpy(blofile, plafile);
189 if(model!=0) printf(
"model := %s\n",
modelCode(model));
190 printf(
"parfile := %s\n", parfile);
191 printf(
"plafile := %s\n", plafile);
192 printf(
"blofile := %s\n", blofile);
193 printf(
"simfile := %s\n", simfile);
194 printf(
"save_only_total := %d\n", save_only_total);
195 printf(
"model := %s\n",
modelCode(model));
196 if(model!=0) printf(
"parallel := %d\n", parallel);
197 printf(
"vvm := %d\n", 1+vvm);
209 fprintf(stderr,
"Error: cannot allocate memory for parameters.\n");
232 for(
int i=0; i<par.
tacNr; i++) {
233 sprintf(par.
r[i].
name,
"tac%d", 1+i);
277 if(verbose>1) printf(
"writing %s\n", parfile);
278 FILE *fp; fp=fopen(parfile,
"w");
280 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", parfile);
293 if(verbose>1) fprintf(stdout,
"reading %s\n", parfile);
294 if(
parRead(&par, parfile, &status)) {
295 fprintf(stderr,
"Error: %s (%s)\n",
errorMsg(status.
error), parfile);
302 for(
int i=0; i<par.
tacNr; i++) par.
r[i].
model=model;
305 for(
int i=0; i<par.
tacNr; i++) {
315 fprintf(stderr,
"Error: model %s not supported.\n",
modelCode(par.
r[i].
model));
316 parFree(&par); fflush(stderr);
return(3);
321 for(
int i=0; i<par.
tacNr; i++) {
326 fprintf(stderr,
"Error: invalid parameters for selected model.\n");
340 fprintf(stderr,
"Error: required parameters not available.\n");
348 if(verbose>1) fprintf(stdout,
"reading input TACs\n");
352 fprintf(stderr,
"Error: %s (input files)\n",
errorMsg(status.
error));
357 printf(
"tacNr := %d\n", input.
tacNr);
358 printf(
"sampleNr := %d\n", input.
sampleNr);
364 fprintf(stderr,
"Error: too few samples in input TAC.\n");
368 fprintf(stderr,
"Warning: too few samples for reliable simulation.\n"); fflush(stderr);
376 if(verbose>1) {fprintf(stdout,
"checking parameters and data units\n"); fflush(stdout);}
380 if(verbose>2) {printf(
" Vb\n"); fflush(stdout);}
387 if(verbose>1) printf(
"Note: converting Vb from percentage to fractions.\n");
389 for(
int j=0; j<par.
tacNr; j++) par.
r[j].
p[i]*=0.01;
394 if(verbose>2) {printf(
" fA\n"); fflush(stdout);}
401 if(verbose>1) printf(
"Note: converting fA from percentage to fractions.\n");
403 for(
int j=0; j<par.
tacNr; j++) par.
r[j].
p[i]*=0.01;
409 if(verbose>2) {printf(
" f\n"); fflush(stdout);}
412 if(verbose>1) printf(
"Note: converting f from per dL to per mL.\n");
414 for(
int j=0; j<par.
tacNr; j++) par.
r[j].
p[i]*=0.01;
417 if(verbose>1) printf(
"Note: converting f from per sec to per min.\n");
420 for(
int j=0; j<par.
tacNr; j++) par.
r[j].
p[i]*=60.;
422 if(verbose>1) printf(
"Note: converting f from per min to per sec.\n");
425 for(
int j=0; j<par.
tacNr; j++) par.
r[j].
p[i]/=60.;
430 if(verbose>2) {printf(
" dT\n"); fflush(stdout);}
435 if(verbose>1) printf(
"Note: converting dT from sec to min.\n");
437 for(
int j=0; j<par.
tacNr; j++) par.
r[j].
p[i]/=60.;
439 if(verbose>1) printf(
"Note: converting dT from min to sec.\n");
441 for(
int j=0; j<par.
tacNr; j++) par.
r[j].
p[i]*=60.;
445 for(
int ri=1; ri<=6; ri++) {
446 char rcname[3]; sprintf(rcname,
"k%d", ri);
448 if(verbose>2) {printf(
" %s\n", rcname); fflush(stdout);}
451 for(
int j=0; j<par.
tacNr; j++)
452 printf(
" %s %s=%g %s\n", par.
r[j].
name, rcname, par.
r[j].
p[i],
unitName(punit));
454 if(verbose>1) printf(
"Note: converting %s from per sec to per min.\n", rcname);
457 for(
int j=0; j<par.
tacNr; j++) par.
r[j].
p[i]*=60.;
459 if(verbose>1) printf(
"Note: converting %s from per min to per sec.\n", rcname);
462 for(
int j=0; j<par.
tacNr; j++) par.
r[j].
p[i]/=60.;
473 if(verbose>1) fprintf(stdout,
"allocating space for simulated TACs\n");
486 for(
int j=0; j<sim.
sampleNr; j++) sim.
x[j]=input.
x[j];
492 if(verbose>1) printf(
"simulating\n");
494 double *ppy=input.
c[0].
y;
495 double *pby=input.
c[0].
y;
if(input.
tacNr>1) pby=input.
c[1].
y;
496 for(
int i=0; i<par.
tacNr; i++) {
497 if(verbose>2) printf(
"simulating %s\n", sim.
c[i].
name);
501 double *ppet=sim.
c[i].
y;
508 double K1, k2, k3, k4, k5, k6, Vb, Flow, fA, dT;
509 K1=k2=k3=k4=k5=k6=Vb=Flow=fA=dT=nan(
"");
514 if(isnormal(f)) k2=K1/f;
520 if(isnormal(f)) k4=k3/f;
526 if(isnormal(f)) k6=k5/f;
534 if(!(K1>=0.0) || k2<0 || k3<0 || k4<0 || k5<0 || k6<0) {
535 fprintf(stderr,
"Error: invalid rate constant.\n");
538 if(K1==0.0) {k2=k3=k4=k5=k6=0.0;}
539 if(k3==0.0) {k4=0.0;
if(!parallel) k5=k6=0.0;}
541 if(isnan(Vb) || Vb==0.0) {Flow=fA=nan(
"");}
542 if(isnan(Flow) || Flow==0.0 || isnan(fA) || fA==0.0 || fA==1.0) {Flow=fA=nan(
"");}
543 if(Vb<0.0 || Vb>1.0) {
544 fprintf(stderr,
"Error: invalid vascular volume.\n");
548 fprintf(stderr,
"Error: invalid perfusion value (f<K1).\n");
551 if(fA<0.0 || fA>1.0) {
552 fprintf(stderr,
"Error: invalid fA value.\n");
556 printf(
"K1 := %g\n", K1);
557 printf(
"k2 := %g\n", k2);
558 printf(
"k3 := %g\n", k3);
559 printf(
"k4 := %g\n", k4);
560 printf(
"k5 := %g\n", k5);
561 printf(
"k6 := %g\n", k6);
562 printf(
"Vb := %g\n", Vb);
563 printf(
"f := %g\n", Flow);
564 printf(
"fA := %g\n", fA);
565 printf(
"dT := %g\n", dT);
569 if(save_only_total==0) {
571 if(Vb>0.0 || k3>0.0 || k5>0.0) n++;
575 if(Vb>0.0 && fA<1.0 && Flow>0.0) n++;
577 fprintf(stderr,
"Error: cannot allocate memory for simulations.\n");
585 sim.
tacNr++; n--; currentTacNr++;
591 sim.
tacNr++; n--; currentTacNr++;
597 sim.
tacNr++; n--; currentTacNr++;
604 sim.
tacNr++; n--; currentTacNr++;
606 if(n>0 && Vb>0.0 && fA<1.0 && Flow>0.0) {
610 sim.
tacNr++; n--; currentTacNr++;
614 if(isnan(K1)) K1=0.0;
615 if(isnan(k2)) k2=0.0;
616 if(isnan(k3)) k3=0.0;
617 if(isnan(k4)) k4=0.0;
618 if(isnan(k5)) k5=0.0;
619 if(isnan(k6)) k6=0.0;
621 for(
int i=0; i<sim.
sampleNr; i++) ppet[i]=pby[i];
622 if(isnan(fA)) fA=1.0;
623 if(pcab!=NULL)
for(
int i=0; i<sim.
sampleNr; i++) pcab[i]=fA*pby[i];
624 if(fA<1.0 && pcab!=NULL)
for(
int i=0; i<sim.
sampleNr; i++) pcvb[i]=(1.0-fA)*pby[i];
627 if(isnan(Flow)) Flow=0.0;
628 if(isnan(fA)) fA=1.0;
630 ret=
simC3vs(px, ppy, pby, sim.
sampleNr, K1, k2, k3, k4, k5, k6, Flow, Vb, fA, vvm,
631 ppet, pc1, pc2, pc3, pcab, pcvb);
633 ret=
simC3vp(px, ppy, pby, sim.
sampleNr, K1, k2, k3, k4, k5, k6, Flow, Vb, fA, vvm,
634 ppet, pc1, pc2, pc3, pcab, pcvb);
638 ppet, pc1, pc2, pc3);
641 ppet, pc1, pc2, pc3);
644 fprintf(stderr,
"Error: invalid data for simulation.\n");
645 if(verbose>1) printf(
"sim_return_code := %d\n", ret);
649 if(!isnan(dT) && fabs(dT)>1.0E-20) {
650 for(
int j=0; j<currentTacNr; j++) {
652 printf(
" delay for %s[%d/%d]\n", sim.
c[i].
name, 1+j, currentTacNr); fflush(stdout);}
656 fprintf(stderr,
"Error: invalid delay time for simulation.\n");
657 if(verbose>2) printf(
"sim_return_code := %d\n", ret);
670 if(verbose>1) printf(
"writing %s\n", simfile);
671 FILE *fp; fp=fopen(simfile,
"w");
673 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", simfile);
679 fprintf(stderr,
"Error (%d): %s\n", ret,
errorMsg(status.
error));
682 if(verbose>=0) {printf(
"%s saved.\n", simfile); fflush(stdout);}
int tacDelay(TAC *tac, double dt, int ti, TPCSTATUS *status)
Move TAC y values (concentrations) in time, keeping sample times (x values) intact.
int atoiCheck(const char *s, int *v)
char * modelCode(const unsigned int i)
unsigned int modelParNr(const unsigned int code)
unsigned int modelCodeIndex(const char *s)
int parAllocate(PAR *par, int parNr, int tacNr)
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
int parRead(PAR *par, const char *fname, TPCSTATUS *status)
double parGetParameter(PAR *d, const char *par_name, const int ti)
void parValueRange(PAR *d, const int i, double *pmin, double *pmax)
int parFindParameter(PAR *d, const char *par_name)
int tacAllocateWithPAR(TAC *tac, PAR *par, int sampleNr, TPCSTATUS *status)
Allocate TAC based on data in PAR.
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)
int simC3p(double *t, double *ca, const int nr, const double k1, const double k2, const double k3, const double k4, const double k5, const double k6, double *ct, double *cta, double *ctb, double *ctc)
int simC3vp(double *t, double *ca, double *cb, const int nr, const double k1, const double k2, const double k3, const double k4, const double k5, const double k6, const double f, const double vb, const double fa, const int vvm, double *cpet, double *cta, double *ctb, double *ctc, double *ctab, double *ctvb)
int simC3vs(double *t, double *ca, double *cb, const int nr, const double k1, const double k2, const double k3, const double k4, const double k5, const double k6, const double f, const double vb, const double fa, const int vvm, double *cpet, double *cta, double *ctb, double *ctc, double *ctab, double *ctvb)
int simC3s(double *t, double *ca, const int nr, double k1, double k2, double k3, double k4, double k5, double k6, double *ct, double *cta, double *ctb, double *ctc)
void statusInit(TPCSTATUS *s)
char * errorMsg(tpcerror e)
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
char name[MAX_PARNAME_LEN+1]
char name[MAX_TACNAME_LEN+1]
char name[MAX_TACNAME_LEN+1]
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacAllocateMore(TAC *tac, int tacNr)
char * tacFormattxt(tacformat c)
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Header file for libtpccm.
Header file for library libtpcextensions.
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ UNIT_UNKNOWN
Unknown unit.
@ UNIT_ML_PER_DL_MIN
mL/(dL*min)
@ UNIT_ML_PER_ML_SEC
mL/(mL*sec)
@ UNIT_PERCENTAGE
Percentage (%).
char * unitName(int unit_code)
Header file for library libtpcift.
Header file for libtpcpar.
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Header file for library libtpctac.
@ TAC_FORMAT_PMOD
PMOD TAC format.
Header file for libtpctacmod.