TPCCLIB
Loading...
Searching...
No Matches
p2t_v3c.c
Go to the documentation of this file.
1
9/*****************************************************************************/
10#include "tpcclibConfig.h"
11/*****************************************************************************/
12#include <stdio.h>
13#include <stdlib.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 "Deprecated, use sim_3tcm instead.",
25 " ",
26 "Simulation of PET tissue time-radioactivity concentration curve (TAC)",
27 "from arterial plasma (Ca) and blood (Cb) TACs, based on three-tissue",
28 "compartmental model, where the compartments are in series (default):",
29 " ",
30 " ____ K1 ____ k3 ____ k5 ____ ",
31 " | Ca | ----> | C1 | ----> | C2 | ----> | C3 | ",
32 " |____| <---- |____| <---- |____| <---- |____| ",
33 " k2 k4 k6 ",
34 " ",
35 " dC1(t)/dt = K1*Ca(T) - (k2+k3)*C1(T) + k4*C2(T) ",
36 " dC2(t)/dt = k3*C1(T) - (k4+k5)*C2(T) + k6*C3(T) ",
37 " dC3(t)/dt = k5*C2(T) - k6*C3(T) ",
38 " Ct(T) = C1(T) + C2(T) + C3(T) ",
39 " Cvb(T) = Cab(T) - dCt(t)/dt / f ",
40 " Cpet(T)= Vb*fA*Cab(T) + Vb*(1-fA)*Cvb(T) + (1-Vb)*Ct(T) ",
41 " ",
42 ", or, optionally, three-tissue compartmental model, where the 2nd and 3rd",
43 "tissue compartments are parallel, often used to represent specific and",
44 "non-specific binding:",
45 " ",
46 " ____ K1 ____ k3 ____ ",
47 " | Ca | ----> | C1 | ----> | C2 | ",
48 " |____| <---- |____| <---- |____| ",
49 " k2 k4 ",
50 " | ^ ",
51 " k5 | | k6 ",
52 " v | ",
53 " ____ ",
54 " | C3 | ",
55 " |____| ",
56 " ",
57 " dC1(t)/dt = K1*Ca(T) - (k2+k3+k5)*C1(T) + k4*C2(T) + k6*C3(T) ",
58 " dC2(t)/dt = k3*C1(T) - k4*C2(T) ",
59 " dC3(t)/dt = k5*C1(T) - k6*C3(T) ",
60 " Ct(T) = C1(T) + C2(T) + C3(T) ",
61 " Cvb(T) = Cab(T) - dCt(t)/dt / f ",
62 " Cpet(T)= Vb*fA*Cab(T) + Vb*(1-fA)*Cvb(T) + (1-Vb)*Ct(T) ",
63 " ",
64 "Usage: @P [options] plasmafile bloodfile K1 k2 k3 k4 k5 k6 f Vb fA simfile",
65 " ",
66 "Options:",
67 " -paral[lel]",
68 " Model with parallel compartments C2 and C3 is applied.",
69 " -ser[ies]",
70 " Model with compartments C1, C2, and C3 in series is applied (default).",
71 " -sub | -nosub",
72 " TACs of sub-compartments (C1, C2 and C3) are written (-sub, default)",
73 " or not written (-nosub) into the simfile.",
74 " -stdoptions", // List standard options like --help, -v, etc
75 " ",
76 "Enter blood flow (f) in units (ml/(min*ml)); set f=0 to assume that f>>K1",
77 "and Cvb=Cab. Enter the vascular volume fraction (Vb) and its arterial",
78 "fraction (fA) as percentages.",
79 "If the times in input files are in seconds, the units of rate constants",
80 "(k's) and blood flow (f) must also be specified as 1/sec.",
81 "For accurate results, plasma TAC should have very short sampling intervals.",
82 "To reduce the model, k5 or k3 can be set to 0.",
83 " ",
84 "Example:",
85 " @P -nosub plasma.dat blood.dat 0.3 0.2 0.1 0.2 0 0 0.6 5 30 sim.dat",
86 " ",
87 "Simulated TACs are written in ASCII format with columns:",
88 " 1) Sample time",
89 " 2) Total tissue activity concentration (Cpet)",
90 " 3) Activity concentration in 1st tissue compartment, (1-Vb)*C1",
91 " 4) Activity concentration in 2nd tissue compartment, (1-Vb)*C2",
92 " 5) Activity concentration in 3rd tissue compartment, (1-Vb)*C3",
93 " 6) Arterial contribution to tissue activity, Vb*fA*Cab",
94 " 7) Venous contribution to tissue activity, Vb*(1-fA)*Cvb",
95 " ",
96 "References:",
97 "1. TPCMOD0001.",
98 " ",
99 "See also: sim_3tcm, p2t_3c, p2t_di, tacadd, tacren, simframe, dft2img",
100 " ",
101 "Keywords: TAC, simulation, modelling, compartmental model",
102 0};
103/*****************************************************************************/
104
105/*****************************************************************************/
106/* Turn on the globbing of the command line, since it is disabled by default in
107 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
108 In Unix&Linux wildcard command line processing is enabled by default. */
109/*
110#undef _CRT_glob
111#define _CRT_glob -1
112*/
113int _dowildcard = -1;
114/*****************************************************************************/
115
116/*****************************************************************************/
120int main(int argc, char **argv)
121{
122 int ai, help=0, version=0, verbose=1;
123 int ret;
124 int fi, ri;
125 int save_only_total=0;
126 int parallel=0;
127 DFT plasma, sim;
128 double k1, k2, k3, k4, k5, k6, f, Vb, fA;
129 double *t, *ca, *cab, *cpet, *ct1, *ct2, *ct3, *ctab, *ctvb;
130 char pfile[FILENAME_MAX], bfile[FILENAME_MAX], sfile[FILENAME_MAX];
131 char tmp[FILENAME_MAX+128], *cptr;
132
133
134
135 /*
136 * Get arguments
137 */
138 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
139 dftInit(&plasma); dftInit(&sim);
140 pfile[0]=bfile[0]=sfile[0]=(char)0;
141 k1=k2=k3=k4=k5=k6=f=Vb=fA=-1.0;
142 /* Options */
143 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
144 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
145 cptr=argv[ai]+1;
146 if(strncasecmp(cptr, "NOSUB", 5)==0) {
147 save_only_total=1; continue;
148 } else if(strncasecmp(cptr, "SUB", 3)==0) {
149 save_only_total=0; continue;
150 } else if(strncasecmp(cptr, "PARALLEL", 5)==0) {
151 parallel=1; continue;
152 } else if(strncasecmp(cptr, "SERIES", 3)==0) {
153 parallel=0; continue;
154 }
155 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
156 return(1);
157 } else break;
158
159 /* Print help or version? */
160 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
161 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
162 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
163
164 /* Process other arguments, starting from the first non-option */
165 for(; ai<argc; ai++) {
166 if(!pfile[0]) {
167 strcpy(pfile, argv[ai]); continue;
168 } else if(!bfile[0]) {
169 strcpy(bfile, argv[ai]); continue;
170 } else if(k1<0.0) {
171 k1=atof_dpi(argv[ai]); if(k1>0.0) continue;
172 } else if(k2<0.0) {
173 k2=atof_dpi(argv[ai]); if(k2>=0.0) continue;
174 } else if(k3<0.0) {
175 k3=atof_dpi(argv[ai]); if(k3>=0.0) continue;
176 } else if(k4<0.0) {
177 k4=atof_dpi(argv[ai]); if(k4>=0.0) continue;
178 } else if(k5<0.0) {
179 k5=atof_dpi(argv[ai]); if(k5>=0.0) continue;
180 } else if(k6<0.0) {
181 k6=atof_dpi(argv[ai]); if(k6>=0.0) continue;
182 } else if(f<0.0) {
183 f=atof_dpi(argv[ai]); if(f>=0.0) continue;
184 } else if(Vb<0.0) {
185 Vb=0.01*atof_dpi(argv[ai]); if(Vb<0.0) Vb=0.0; continue;
186 } else if(fA<0.0) {
187 fA=0.01*atof_dpi(argv[ai]); if(fA<1.0E-012) fA=0.0; continue;
188 } else if(!sfile[0]) {
189 strcpy(sfile, argv[ai]); continue;
190 } else {
191 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
192 return(1);
193 }
194 }
195
196 /* Is something missing? */
197 if(!sfile[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
198 if(k1<=0.0) {fprintf(stderr, "Error: k1 must be > 0.\n"); return(1);}
199 if(f>0.0 && f<k1) {
200 fprintf(stderr, "Error: f cannot be lower than K1!\n"); return(1);}
201 if(Vb>=1.0 || fA<=0.0 || fA>1.0) {
202 fprintf(stderr, "Error: invalid value of Vb!\n"); return(1);}
203 if(fA<=0.0 || fA>1.0) {
204 fprintf(stderr, "Error: invalid value of fA!\n"); return(1);}
205 if(k1>1.0E+08 || k2>1.0E+08 || k3>1.0E+08 || k4>1.0E+08 ||
206 k5>1.0E+08 || k6>1.0E+08) {
207 fprintf(stderr, "Error: too high rate constant.\n"); return(1);
208 }
209
210 /* In verbose mode print arguments and options */
211 if(verbose>1) {
212 printf("pfile := %s\n", pfile);
213 printf("bfile := %s\n", bfile);
214 printf("sfile := %s\n", sfile);
215 printf("parameters := %g %g %g %g %g %g\n", k1, k2, k3, k4, k5, k6);
216 printf("f := %g\n", f);
217 printf("Vb := %g\n", Vb);
218 printf("fA := %g\n", fA);
219 printf("save_only_total := %d\n", save_only_total);
220 printf("parallel := %d\n", parallel);
221 }
222
223
224 /*
225 * Read plasma data
226 */
227 if(verbose>1) printf("reading plasma\n");
228 if(dftRead(pfile, &plasma)) {
229 fprintf(stderr, "Error in reading '%s': %s\n", pfile, dfterrmsg);
230 dftEmpty(&plasma);
231 return(2);
232 }
233 if(plasma.frameNr<3) {
234 fprintf(stderr, "Error: too few samples in plasma data.\n");
235 dftEmpty(&plasma); return(2);
236 }
237 if(plasma.voiNr>1) {
238 fprintf(stderr, "Error: plasma data contains more than one curve.\n");
239 dftEmpty(&plasma); return(2);
240 }
241 if(plasma.timeunit==TUNIT_UNKNOWN) {
242 plasma.timeunit=TUNIT_MIN;
243 if(verbose>=0) printf("assuming that time unit is min\n");
244 }
245
246 /*
247 * Read blood data; interpolate it to the plasma times
248 */
249 if(verbose) printf("reading blood\n");
250 if(dftRead(bfile, &sim)) {
251 fprintf(stderr, "Error in reading '%s': %s\n", bfile, dfterrmsg);
252 dftEmpty(&plasma); dftEmpty(&sim); return(3);
253 }
254 if(sim.frameNr<3) {
255 fprintf(stderr, "Error: too few samples in blood data.\n");
256 dftEmpty(&plasma); dftEmpty(&sim); return(3);
257 }
258 if(sim.voiNr>1) {
259 fprintf(stderr, "Error: blood data contains more than one curve.\n");
260 dftEmpty(&plasma); dftEmpty(&sim); return(3);
261 }
262 /* Check that blood has been measured for long enough */
263 if(sim.x[sim.frameNr-1] < 0.67*plasma.x[plasma.frameNr-1]) {
264 fprintf(stderr, "Warning: blood TAC is much shorter than plasma TAC.\n");
265 }
266 /* Allocate memory for interpolated blood data */
267 if(dftAddmem(&plasma, 1)) {
268 fprintf(stderr, "Error: cannot allocate memory for blood TAC.\n");
269 dftEmpty(&plasma); dftEmpty(&sim); return(3);
270 }
271 strcpy(plasma.voi[1].voiname, "Blood");
272 strcpy(plasma.voi[1].name, plasma.voi[1].voiname);
273 /* Interpolate */
274 ret=interpolate(sim.x, sim.voi[0].y, sim.frameNr, plasma.x, plasma.voi[1].y,
275 NULL, NULL, plasma.frameNr);
276 dftEmpty(&sim);
277 if(ret) {
278 fprintf(stderr, "Error: cannot interpolate blood data.\n");
279 dftEmpty(&plasma); return(3);
280 }
281 if(verbose>9) dftPrint(&plasma);
282
283
284 /*
285 * Allocate memory for simulated tissue data.
286 */
287 if(verbose>1) printf("allocating memory\n");
288 /* allocate */
289 ret=dftSetmem(&sim, plasma.frameNr, 6);
290 if(ret) {
291 fprintf(stderr,
292 "Error (%d): cannot allocate memory for simulated TACs.\n", ret);
293 dftEmpty(&plasma); return(4);
294 }
295 sim.frameNr=plasma.frameNr; sim.voiNr=6;
296 /* Copy times & header info */
297 dftCopymainhdr(&plasma, &sim);
298 for(fi=0; fi<sim.frameNr; fi++) {
299 sim.x[fi]=plasma.x[fi];
300 sim.x1[fi]=plasma.x1[fi]; sim.x2[fi]=plasma.x2[fi];
301 }
302 /* column headers */
303 for(ri=0; ri<sim.voiNr; ri++) {
304 sim.voi[ri].sw=0;
305 switch(ri) {
306 case 0: strcpy(sim.voi[ri].voiname, "Cpet");
307 sim.voi[ri].size=100.0;
308 break;
309 case 1: strcpy(sim.voi[ri].voiname, "C1");
310 sim.voi[ri].size=100.*(1.-Vb);
311 break;
312 case 2: strcpy(sim.voi[ri].voiname, "C2");
313 sim.voi[ri].size=100.*(1.-Vb);
314 break;
315 case 3: strcpy(sim.voi[ri].voiname, "C3");
316 sim.voi[ri].size=100.*(1.-Vb);
317 break;
318 case 4: strcpy(sim.voi[ri].voiname, "Cab");
319 sim.voi[ri].size=100.0*fA*Vb;
320 break;
321 case 5: strcpy(sim.voi[ri].voiname, "Cvb");
322 sim.voi[ri].size=100.0*(1.0-fA)*Vb;
323 break;
324 }
325 strcpy(sim.voi[ri].hemisphere, ""); strcpy(sim.voi[ri].place, "");
326 strcpy(sim.voi[ri].name, sim.voi[ri].voiname);
327 }
328
329 /*
330 * Simulate TACs
331 */
332 if(verbose>1) printf("simulating\n");
333 t=sim.x; ca=plasma.voi[0].y; cab=plasma.voi[1].y;
334 cpet=sim.voi[0].y; ct1=sim.voi[1].y; ct2=sim.voi[2].y; ct3=sim.voi[3].y;
335 ctab=sim.voi[4].y; ctvb=sim.voi[5].y;
336 if(parallel==0)
337 ret=simC3vs(t, ca, cab, sim.frameNr, k1, k2, k3, k4, k5, k6, f, Vb, fA,
338 cpet, ct1, ct2, ct3, ctab, ctvb);
339 else
340 ret=simC3vp(t, ca, cab, sim.frameNr, k1, k2, k3, k4, k5, k6, f, Vb, fA,
341 cpet, ct1, ct2, ct3, ctab, ctvb);
342 dftEmpty(&plasma);
343 if(ret!=0) {
344 fprintf(stderr, "Error (%d) in simulation.\n", ret);
345 dftEmpty(&sim); return(8);
346 }
347
348
349 /*
350 * Save simulated TACs
351 */
352 if(verbose>1) printf("saving PET curves\n");
354 if(save_only_total) sim.voiNr=1;
355 /* Set comments */
356 dftSetComments(&sim);
357 sprintf(tmp, "# plasmafile := %s\n", pfile); strcat(sim.comments, tmp);
358 sprintf(tmp, "# bloodfile := %s\n", bfile); strcat(sim.comments, tmp);
359 strcpy(tmp, "# model := ");
360 if(parallel==0) strcat(tmp, "C3VS\n"); else strcat(tmp, "C3VP\n");
361 strcat(sim.comments, tmp);
362 sprintf(tmp, "# K1 := %g\n", k1); strcat(sim.comments, tmp);
363 sprintf(tmp, "# k2 := %g\n", k2); strcat(sim.comments, tmp);
364 sprintf(tmp, "# k3 := %g\n", k3); strcat(sim.comments, tmp);
365 sprintf(tmp, "# k4 := %g\n", k4); strcat(sim.comments, tmp);
366 sprintf(tmp, "# k5 := %g\n", k5); strcat(sim.comments, tmp);
367 sprintf(tmp, "# k6 := %g\n", k6); strcat(sim.comments, tmp);
368 sprintf(tmp, "# f := %g\n", f); strcat(sim.comments, tmp);
369 sprintf(tmp, "# Vb := %g [%%]\n", 100.0*Vb); strcat(sim.comments, tmp);
370 sprintf(tmp, "# fA := %g [%%]\n", 100.0*fA); strcat(sim.comments, tmp);
371 /* Set file format to PMOD, if extension is .tac */
372 if(!strcasecmp(filenameGetExtension(sfile), ".tac"))
374 /* Some format has to be set anyway, and simple format would lose information */
377 /* Write file */
378 if(dftWrite(&sim, sfile)) {
379 fprintf(stderr, "Error in writing '%s': %s\n", sfile, dfterrmsg);
380 dftEmpty(&sim); return(11);
381 }
382 if(verbose>0) fprintf(stdout, "simulated TAC(s) written in %s\n", sfile);
383 dftEmpty(&sim);
384
385 return(0);
386}
387/*****************************************************************************/
388
389/*****************************************************************************/
double atof_dpi(char *str)
Definition decpoint.c:59
void dftInit(DFT *data)
Definition dft.c:38
char dfterrmsg[64]
Definition dft.c:6
int dftAddmem(DFT *dft, int voiNr)
Definition dft.c:107
void dftSetComments(DFT *dft)
Definition dft.c:1326
int dftSetmem(DFT *data, int frameNr, int voiNr)
Definition dft.c:57
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
void dftPrint(DFT *data)
Definition dftio.c:538
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
char * filenameGetExtension(char *s)
Get the last extension of a filename.
Definition filename.c:139
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.
#define DFT_FORMAT_PMOD
#define DFT_FORMAT_STANDARD
#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 tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
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 simC3vp(double *t, double *ca, double *cb, int nr, double k1, double k2, double k3, double k4, double k5, double k6, double f, double vb, double fa, double *cpet, double *cta, double *ctb, double *ctc, double *ctab, double *ctvb)
Definition simulate.c:373
int simC3vs(double *t, double *ca, double *cb, int nr, double k1, double k2, double k3, double k4, double k5, double k6, double f, double vb, double fa, double *cpet, double *cta, double *ctb, double *ctc, double *ctab, double *ctvb)
Definition simulate.c:243
int _type
Voi * voi
int timeunit
double * x1
char comments[_DFT_COMMENT_LEN+1]
int voiNr
double * x2
int frameNr
double * x
double size
char voiname[MAX_REGIONSUBNAME_LEN+1]
char sw
double * y
char name[MAX_REGIONNAME_LEN+1]
char hemisphere[MAX_REGIONSUBNAME_LEN+1]
char place[MAX_REGIONSUBNAME_LEN+1]