TPCCLIB
Loading...
Searching...
No Matches
sim_3tcm.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <math.h>
14/*****************************************************************************/
15#include "tpcextensions.h"
16#include "tpcift.h"
17#include "tpctac.h"
18#include "tpcpar.h"
19#include "tpctacmod.h"
20#include "tpccm.h"
21/*****************************************************************************/
22
23/*****************************************************************************/
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):",
28 " ",
29 " ____ K1 ____ k3 ____ k5 ____ ",
30 " | Ca | ----> | C1 | ----> | C2 | ----> | C3 | ",
31 " |____| <---- |____| <---- |____| <---- |____| ",
32 " k2 k4 k6 ",
33 " ",
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) ",
40 " ",
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:",
44 " ",
45 " ____ K1 ____ k3 ____ ",
46 " | Ca | ----> | C1 | ----> | C2 | ",
47 " |____| <---- |____| <---- |____| ",
48 " k2 k4 ",
49 " | ^ ",
50 " k5 | | k6 ",
51 " v | ",
52 " ____ ",
53 " | C3 | ",
54 " |____| ",
55 " ",
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) ",
62 " ",
63 "Usage: @P [options] parfile [plasmafile bloodfile simfile]",
64 " ",
65 "Options:",
66 " -paral[lel]",
67 " Model with parallel compartments C2 and C3 is applied, overriding",
68 " possible model settings in parameter file.",
69 " -ser[ies]",
70 " Model with compartments C1, C2, and C3 in series is applied, overriding",
71 " possible model settings in parameter file.",
72 " -vvm=<1|2>",
73 " Vascular volume is modelled as (1, default)",
74 " Cpet(T)= Vb*fA*Cab(T) + Vb*(1-fA)*Cvb(T) + (1-Vb)*Ct(T)",
75 " or as (2)",
76 " Cpet(T)= Vb*fA*Cab(T) + Vb*(1-fA)*Cvb(T) + Ct(T).",
77 " -sub | -nosub",
78 " TACs of sub-compartments (C1, C2 and C3) are written (-sub)",
79 " or not written (-nosub, default) into the simfile.",
80 " -stdoptions", // List standard options like --help, -v, etc
81 " ",
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,",
87 "fA=1, and dT=0.",
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.",
93 " ",
94 "See also: simdisp, p2t_di, sim_rtcm, tacadd, simframe, tacformat, dft2img",
95 " ",
96 "Keywords: TAC, simulation, modelling, compartmental model",
97 0};
98/*****************************************************************************/
99
100/*****************************************************************************/
101/* Turn on the globbing of the command line, since it is disabled by default in
102 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
103 In Unix&Linux wildcard command line processing is enabled by default. */
104/*
105#undef _CRT_glob
106#define _CRT_glob -1
107*/
108int _dowildcard = -1;
109/*****************************************************************************/
110
111/*****************************************************************************/
115int main(int argc, char **argv)
116{
117 int ai, help=0, version=0, verbose=1;
118 char plafile[FILENAME_MAX], blofile[FILENAME_MAX],
119 simfile[FILENAME_MAX], parfile[FILENAME_MAX];
120 char *cptr;
121 unsigned int model=0; // unknown
122 unsigned int parNr=0;
123 int save_only_total=1;
124 int parallel=0;
125 int vvm=0; // Vascular volume model
126 PAR par;
127 int ret;
128
129
130 /*
131 * Get arguments
132 */
133 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
134 plafile[0]=blofile[0]=simfile[0]=parfile[0]=(char)0;
135 parInit(&par);
136 //model=modelCodeIndex("SER3TCM");
137 /* Options */
138 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
139 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
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) {
146 parallel=1; model=modelCodeIndex("PAR3TCM"); continue;
147 } else if(strncasecmp(cptr, "SERIES", 3)==0) {
148 parallel=0; model=modelCodeIndex("SER3TCM"); continue;
149 } else if(strncasecmp(cptr, "VVM=", 4)==0) {
150 if(atoiCheck(cptr+4, &vvm)==0 && vvm>=1 && vvm<=2) {vvm--; continue;}
151 }
152 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
153 return(1);
154 } else break; // tac name argument may start with '-'
155
156 TPCSTATUS status; statusInit(&status);
157 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
158 status.verbose=verbose-1;
159
160 /* Print help or version? */
161 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
162 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
163 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
164
165 /* Process other arguments, starting from the first non-option */
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);
170 if(ai<argc) {
171 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
172 return(1);
173 }
174
175 /* Is something missing? */
176 if(!parfile[0]) {
177 fprintf(stderr, "Error: missing parameter file; use option --help\n");
178 return(1);
179 }
180 if(plafile[0] && !simfile[0]) {
181 fprintf(stderr, "Error: missing filename.\n");
182 return(1);
183 }
184 if(strcasecmp(blofile, "NONE")==0) strcpy(blofile, plafile);
185
186
187 /* In verbose mode print arguments and options */
188 if(verbose>1) {
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);
198 }
199
200 /*
201 * Make template parameter file, if no other filenames were given,
202 * and then quit
203 */
204 if(!plafile[0]) {
205 if(model==0) {parallel=0; model=modelCodeIndex("SER3TCM");}
206 parNr=10;
207 ret=parAllocate(&par, parNr, 3);
208 if(ret) {
209 fprintf(stderr, "Error: cannot allocate memory for parameters.\n");
210 parFree(&par); return(1);
211 }
212 par.parNr=parNr; par.tacNr=3;
213 if(parallel) {
214 strcpy(par.n[0].name, "K1"); par.n[0].unit=UNIT_ML_PER_ML_MIN;
215 strcpy(par.n[1].name, "K1/k2"); par.n[1].unit=UNIT_ML_PER_ML;
216 strcpy(par.n[2].name, "k3"); par.n[2].unit=UNIT_PER_MIN;
217 strcpy(par.n[3].name, "k3/k4"); par.n[3].unit=UNIT_UNITLESS;
218 strcpy(par.n[4].name, "k5"); par.n[4].unit=UNIT_PER_MIN;
219 strcpy(par.n[5].name, "k5/k6"); par.n[5].unit=UNIT_UNITLESS;
220 } else {
221 strcpy(par.n[0].name, "K1"); par.n[0].unit=UNIT_ML_PER_ML_MIN;
222 strcpy(par.n[1].name, "k2"); par.n[1].unit=UNIT_PER_MIN;
223 strcpy(par.n[2].name, "k3"); par.n[2].unit=UNIT_PER_MIN;
224 strcpy(par.n[3].name, "k4"); par.n[3].unit=UNIT_PER_MIN;
225 strcpy(par.n[4].name, "k5"); par.n[4].unit=UNIT_PER_MIN;
226 strcpy(par.n[5].name, "k6"); par.n[5].unit=UNIT_PER_MIN;
227 }
228 strcpy(par.n[6].name, "Vb"); par.n[6].unit=UNIT_PERCENTAGE;
229 strcpy(par.n[7].name, "f"); par.n[7].unit=UNIT_ML_PER_ML_MIN;
230 strcpy(par.n[8].name, "fA"); par.n[8].unit=UNIT_PERCENTAGE;
231 strcpy(par.n[9].name, "dT"); par.n[9].unit=UNIT_SEC;
232 for(int i=0; i<par.tacNr; i++) {
233 sprintf(par.r[i].name, "tac%d", 1+i);
234 par.r[i].model=model;
235 //par.r[i].start=0.0;
236 //par.r[i].end=90.0;
237 par.r[i].p[0]=0.3;
238 par.r[i].p[1]=0.8;
239 par.r[i].p[6]=4.0;
240 par.r[i].p[7]=0.8;
241 par.r[i].p[8]=30.;
242 par.r[i].p[9]=0.0;
243 }
244 if(parallel) {
245 int i=0;
246 par.r[i].p[2]=0.0;
247 par.r[i].p[3]=0.0;
248 par.r[i].p[4]=0.5;
249 par.r[i].p[5]=1.0;
250 i=1;
251 par.r[i].p[2]=0.15;
252 par.r[i].p[3]=1.5;
253 par.r[i].p[4]=0.5;
254 par.r[i].p[5]=1.0;
255 i=2;
256 par.r[i].p[2]=0.15;
257 par.r[i].p[3]=3.0;
258 par.r[i].p[4]=0.5;
259 par.r[i].p[5]=1.0;
260 } else {
261 int i=0;
262 par.r[i].p[2]=0.20;
263 par.r[i].p[3]=0.15;
264 par.r[i].p[4]=0.01;
265 par.r[i].p[5]=0.0;
266 i=1;
267 par.r[i].p[2]=0.20;
268 par.r[i].p[3]=0.15;
269 par.r[i].p[4]=0.05;
270 par.r[i].p[5]=0.0;
271 i=2;
272 par.r[i].p[2]=0.20;
273 par.r[i].p[3]=0.15;
274 par.r[i].p[4]=0.10;
275 par.r[i].p[5]=0.01;
276 }
277 if(verbose>1) printf("writing %s\n", parfile);
278 FILE *fp; fp=fopen(parfile, "w");
279 if(fp==NULL) {
280 fprintf(stderr, "Error: cannot open file for writing (%s)\n", parfile);
281 parFree(&par); return(11);
282 }
283 ret=parWrite(&par, fp, PAR_FORMAT_TSV_UK, 1, &status);
284 fclose(fp);
285 parFree(&par); return(0);
286 }
287
288
289 /*
290 * Read parameter file to get parameters for the simulation, and
291 * set model in case it was given with command-line option.
292 */
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);
296 parFree(&par);
297 return(3);
298 }
299 if(verbose>5) parWrite(&par, stdout, PAR_FORMAT_TSV_UK, 1, NULL);
300 if(model!=0) {
301 /* If user gave model, then use it */
302 for(int i=0; i<par.tacNr; i++) par.r[i].model=model;
303 } else {
304 /* otherwise, check the model in parameter file */
305 for(int i=0; i<par.tacNr; i++) {
306 /* If parameter file does not contain model, then use default */
307 if(par.r[i].model==0) {
308 par.r[i].model=modelCodeIndex("SER3TCM");
309 } else {
310 /* If parameter file contains model, then check that it is ok here */
311 if(par.r[i].model==modelCodeIndex("SER3TCM")) continue;
312 if(par.r[i].model==modelCodeIndex("PAR3TCM")) continue;
313 if(par.r[i].model==modelCodeIndex("2TCM")) continue;
314 if(par.r[i].model==modelCodeIndex("1TCM")) continue;
315 fprintf(stderr, "Error: model %s not supported.\n", modelCode(par.r[i].model));
316 parFree(&par); fflush(stderr); return(3);
317 }
318 }
319 }
320 /* Check the validity of model and its parameters */
321 for(int i=0; i<par.tacNr; i++) {
322 if(verbose>3) printf("model %s for tac %s\n", modelCode(par.r[i].model), par.r[i].name);
323 /* check that we got at least as many parameters as the model has, minus
324 the three optional parameters */
325 if(modelParNr(par.r[i].model)>4+(unsigned int)par.parNr) {
326 fprintf(stderr, "Error: invalid parameters for selected model.\n");
327 parFree(&par); return(3);
328 }
329 /* check that we can find the obligatory model parameters */
330 ret=0;
331 if(parFindParameter(&par, "K1")<0) ret++;
332 /*
333 if(parFindParameter(&par, "k2")<0 && parFindParameter(&par, "K1/k2")<0) ret++;
334 if(parFindParameter(&par, "k3")<0) ret++;
335 if(parFindParameter(&par, "k4")<0 && parFindParameter(&par, "k3/k4")<0) ret++;
336 if(parFindParameter(&par, "k5")<0) ret++;
337 if(parFindParameter(&par, "k6")<0 && parFindParameter(&par, "k5/k6")<0) ret++;
338 */
339 if(ret) {
340 fprintf(stderr, "Error: required parameters not available.\n");
341 parFree(&par); return(3);
342 }
343 }
344
345 /*
346 * Read input TACs
347 */
348 if(verbose>1) fprintf(stdout, "reading input TACs\n");
349 TAC input; tacInit(&input);
350 ret=tacReadModelingInput(plafile, blofile, NULL, &input, &status);
351 if(ret!=TPCERROR_OK) {
352 fprintf(stderr, "Error: %s (input files)\n", errorMsg(status.error));
353 tacFree(&input); parFree(&par); return(4);
354 }
355 if(verbose>2) {
356 printf("fileformat := %s\n", tacFormattxt(input.format));
357 printf("tacNr := %d\n", input.tacNr);
358 printf("sampleNr := %d\n", input.sampleNr);
359 printf("xunit := %s\n", unitName(input.tunit));
360 printf("yunit := %s\n", unitName(input.cunit));
361 }
362 if(verbose>10) tacWrite(&input, stdout, TAC_FORMAT_PMOD, 1, NULL);
363 if(input.sampleNr<3) {
364 fprintf(stderr, "Error: too few samples in input TAC.\n");
365 tacFree(&input); parFree(&par); return(4);
366 }
367 if(input.sampleNr<10) {
368 fprintf(stderr, "Warning: too few samples for reliable simulation.\n"); fflush(stderr);
369 }
370
371
372 /*
373 * Check parameter and data units
374 */
375 {
376 if(verbose>1) {fprintf(stdout, "checking parameters and data units\n"); fflush(stdout);}
377 int i, punit;
378 /* Vb */
379 if((i=parFindParameter(&par, "Vb"))>=0) {
380 if(verbose>2) {printf(" Vb\n"); fflush(stdout);}
381 punit=par.n[i].unit;
382 if(punit==UNIT_UNKNOWN) {
383 double pmax=0.0; (void)parValueRange(&par, i, NULL, &pmax);
384 if(pmax>1.0) punit=UNIT_PERCENTAGE; else punit=UNIT_UNITLESS;
385 }
386 if(punit==UNIT_PERCENTAGE) {
387 if(verbose>1) printf("Note: converting Vb from percentage to fractions.\n");
388 par.n[i].unit=UNIT_UNITLESS;
389 for(int j=0; j<par.tacNr; j++) par.r[j].p[i]*=0.01;
390 }
391 }
392 /* fA */
393 if((i=parFindParameter(&par, "fA"))>=0) {
394 if(verbose>2) {printf(" fA\n"); fflush(stdout);}
395 punit=par.n[i].unit;
396 if(punit==UNIT_UNKNOWN) {
397 double pmax=0.0; (void)parValueRange(&par, i, NULL, &pmax);
398 if(pmax>1.0) punit=UNIT_PERCENTAGE; else punit=UNIT_UNITLESS;
399 }
400 if(punit==UNIT_PERCENTAGE) {
401 if(verbose>1) printf("Note: converting fA from percentage to fractions.\n");
402 par.n[i].unit=UNIT_UNITLESS;
403 for(int j=0; j<par.tacNr; j++) par.r[j].p[i]*=0.01;
404 }
405 }
406 /* Perfusion */
407 i=parFindParameter(&par, "f"); if(i<0) i=parFindParameter(&par, "Flow");
408 if(i>=0) {
409 if(verbose>2) {printf(" f\n"); fflush(stdout);}
410 punit=par.n[i].unit;
411 if(punit==UNIT_ML_PER_DL_MIN) {
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;
415 }
416 if(input.tunit==UNIT_MIN && (punit==UNIT_PER_SEC || punit==UNIT_ML_PER_ML_SEC)) {
417 if(verbose>1) printf("Note: converting f from per sec to per min.\n");
418 if(punit==UNIT_PER_SEC) par.n[i].unit=UNIT_PER_MIN;
419 else par.n[i].unit=UNIT_ML_PER_ML_MIN;
420 for(int j=0; j<par.tacNr; j++) par.r[j].p[i]*=60.;
421 } else if(input.tunit==UNIT_SEC && (punit==UNIT_PER_MIN || punit==UNIT_ML_PER_ML_MIN)) {
422 if(verbose>1) printf("Note: converting f from per min to per sec.\n");
423 if(punit==UNIT_PER_MIN) par.n[i].unit=UNIT_PER_SEC;
424 else par.n[i].unit=UNIT_ML_PER_ML_SEC;
425 for(int j=0; j<par.tacNr; j++) par.r[j].p[i]/=60.;
426 }
427 }
428 /* dT */
429 if((i=parFindParameter(&par, "dT"))>=0) {
430 if(verbose>2) {printf(" dT\n"); fflush(stdout);}
431 punit=par.n[i].unit;
432 if(verbose>4) printf(" units: dT=%s x=%s\n", unitName(punit), unitName(input.tunit));
433 if(punit==UNIT_UNKNOWN) punit=UNIT_SEC;
434 if(input.tunit==UNIT_MIN && punit==UNIT_SEC) {
435 if(verbose>1) printf("Note: converting dT from sec to min.\n");
436 par.n[i].unit=UNIT_MIN;
437 for(int j=0; j<par.tacNr; j++) par.r[j].p[i]/=60.;
438 } else if(input.tunit==UNIT_SEC && punit==UNIT_MIN) {
439 if(verbose>1) printf("Note: converting dT from min to sec.\n");
440 par.n[i].unit=UNIT_SEC;
441 for(int j=0; j<par.tacNr; j++) par.r[j].p[i]*=60.;
442 }
443 }
444 /* Rate constants */
445 for(int ri=1; ri<=6; ri++) {
446 char rcname[3]; sprintf(rcname, "k%d", ri);
447 if((i=parFindParameter(&par, rcname))>=0) {
448 if(verbose>2) {printf(" %s\n", rcname); fflush(stdout);}
449 punit=par.n[i].unit;
450 if(verbose>5)
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));
453 if(input.tunit==UNIT_MIN && (punit==UNIT_PER_SEC || punit==UNIT_ML_PER_ML_SEC)) {
454 if(verbose>1) printf("Note: converting %s from per sec to per min.\n", rcname);
455 if(punit==UNIT_PER_SEC) par.n[i].unit=UNIT_PER_MIN;
456 else par.n[i].unit=UNIT_ML_PER_ML_MIN;
457 for(int j=0; j<par.tacNr; j++) par.r[j].p[i]*=60.;
458 } else if(input.tunit==UNIT_SEC && (punit==UNIT_PER_MIN || punit==UNIT_ML_PER_ML_MIN)) {
459 if(verbose>1) printf("Note: converting %s from per min to per sec.\n", rcname);
460 if(punit==UNIT_PER_MIN) par.n[i].unit=UNIT_PER_SEC;
461 else par.n[i].unit=UNIT_ML_PER_ML_SEC;
462 for(int j=0; j<par.tacNr; j++) par.r[j].p[i]/=60.;
463 }
464 }
465 }
466 if(verbose>3) parWrite(&par, stdout, PAR_FORMAT_TSV_UK, 1, NULL);
467 }
468
469
470 /*
471 * Allocate space for simulated data
472 */
473 if(verbose>1) fprintf(stdout, "allocating space for simulated TACs\n");
474 TAC sim; tacInit(&sim);
475 ret=tacAllocateWithPAR(&sim, &par, input.sampleNr, &status);
476 if(ret!=TPCERROR_OK) {
477 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
478 tacFree(&input); tacFree(&sim); parFree(&par); return(4);
479 }
482 sim.cunit=input.cunit;
483 sim.tunit=input.tunit;
484 sim.format=input.format;
485 sim.isframe=0;
486 for(int j=0; j<sim.sampleNr; j++) sim.x[j]=input.x[j];
487
488
489 /*
490 * Simulation
491 */
492 if(verbose>1) printf("simulating\n");
493 double *px=input.x;
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);
498 /* Check whether this tac model is parallel */
499 if(par.r[i].model==modelCodeIndex("PAR3TCM")) parallel=1; else parallel=0;
500 /* Create pointers for simulated data, but set those only after possible reallocation */
501 double *ppet=sim.c[i].y; // set again if reallocated
502 double *pc1=NULL;
503 double *pc2=NULL;
504 double *pc3=NULL;
505 double *pcab=NULL;
506 double *pcvb=NULL;
507 /* Get parameters */
508 double K1, k2, k3, k4, k5, k6, Vb, Flow, fA, dT;
509 K1=k2=k3=k4=k5=k6=Vb=Flow=fA=dT=nan("");
510 K1=parGetParameter(&par, "K1", i);
511 k2=parGetParameter(&par, "k2", i);
512 if(isnan(k2)) {
513 double f=parGetParameter(&par, "K1/k2", i);
514 if(isnormal(f)) k2=K1/f; // not if zero, subnormal, infinite, or NaN
515 }
516 k3=parGetParameter(&par, "k3", i);
517 k4=parGetParameter(&par, "k4", i);
518 if(isnan(k4)) {
519 double f=parGetParameter(&par, "k3/k4", i);
520 if(isnormal(f)) k4=k3/f; // not if zero, subnormal, infinite, or NaN
521 }
522 k5=parGetParameter(&par, "k5", i);
523 k6=parGetParameter(&par, "k6", i);
524 if(isnan(k6)) {
525 double f=parGetParameter(&par, "k5/k6", i);
526 if(isnormal(f)) k6=k5/f; // not if zero, subnormal, infinite, or NaN
527 }
528 Vb=parGetParameter(&par, "Vb", i);
529 Flow=parGetParameter(&par, "f", i);
530 if(isnan(Flow)) Flow=parGetParameter(&par, "Flow", i);
531 fA=parGetParameter(&par, "fA", i);
532 dT=parGetParameter(&par, "dT", i);
533 /* Verify and fix parameters */
534 if(!(K1>=0.0) || k2<0 || k3<0 || k4<0 || k5<0 || k6<0) {
535 fprintf(stderr, "Error: invalid rate constant.\n");
536 tacFree(&sim); tacFree(&input); parFree(&par); return(5);
537 }
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;}
540 if(k5==0.0) 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");
545 tacFree(&sim); tacFree(&input); parFree(&par); return(5);
546 }
547 if(Flow<K1) {
548 fprintf(stderr, "Error: invalid perfusion value (f<K1).\n");
549 tacFree(&sim); tacFree(&input); parFree(&par); return(5);
550 }
551 if(fA<0.0 || fA>1.0) {
552 fprintf(stderr, "Error: invalid fA value.\n");
553 tacFree(&sim); tacFree(&input); parFree(&par); return(5);
554 }
555 if(verbose>3) {
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);
566 }
567 /* Add place for compartment TACs in simulated data, as needed */
568 int currentTacNr=1;
569 if(save_only_total==0) {
570 int n=0;
571 if(Vb>0.0 || k3>0.0 || k5>0.0) n++;
572 if(k3>0.0) n++;
573 if(k5>0.0) n++;
574 if(Vb>0.0) n++;
575 if(Vb>0.0 && fA<1.0 && Flow>0.0) n++;
576 if(n>0 && tacAllocateMore(&sim, n)!=0) {
577 fprintf(stderr, "Error: cannot allocate memory for simulations.\n");
578 tacFree(&input); tacFree(&sim); parFree(&par); return(4);
579 }
580 ppet=sim.c[i].y;
581 if(n>0) {
582 strcpy(sim.c[sim.tacNr].name, sim.c[i].name);
583 strcat(sim.c[sim.tacNr].name, "_C1");
584 pc1=sim.c[sim.tacNr].y;
585 sim.tacNr++; n--; currentTacNr++;
586 }
587 if(n>0 && k3>0.0) {
588 strcpy(sim.c[sim.tacNr].name, sim.c[i].name);
589 strcat(sim.c[sim.tacNr].name, "_C2");
590 pc2=sim.c[sim.tacNr].y;
591 sim.tacNr++; n--; currentTacNr++;
592 }
593 if(n>0 && k5>0.0) {
594 strcpy(sim.c[sim.tacNr].name, sim.c[i].name);
595 strcat(sim.c[sim.tacNr].name, "_C3");
596 pc3=sim.c[sim.tacNr].y;
597 sim.tacNr++; n--; currentTacNr++;
598 }
599 /* Vascular TACs */
600 if(n>0 && Vb>0.0) {
601 strcpy(sim.c[sim.tacNr].name, sim.c[i].name);
602 strcat(sim.c[sim.tacNr].name, "_Cab");
603 pcab=sim.c[sim.tacNr].y;
604 sim.tacNr++; n--; currentTacNr++;
605 }
606 if(n>0 && Vb>0.0 && fA<1.0 && Flow>0.0) {
607 strcpy(sim.c[sim.tacNr].name, sim.c[i].name);
608 strcat(sim.c[sim.tacNr].name, "_Cvb");
609 pcvb=sim.c[sim.tacNr].y;
610 sim.tacNr++; n--; currentTacNr++;
611 }
612 }
613 /* Simulate */
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;
620 if(Vb==1.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];
625 ret=0;
626 } else if(Vb>0.0) {
627 if(isnan(Flow)) Flow=0.0;
628 if(isnan(fA)) fA=1.0;
629 if(parallel==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);
632 else
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);
635 } else {
636 if(parallel==0)
637 ret=simC3s(px, ppy, sim.sampleNr, K1, k2, k3, k4, k5, k6,
638 ppet, pc1, pc2, pc3);
639 else
640 ret=simC3p(px, ppy, sim.sampleNr, K1, k2, k3, k4, k5, k6,
641 ppet, pc1, pc2, pc3);
642 }
643 if(ret) {
644 fprintf(stderr, "Error: invalid data for simulation.\n");
645 if(verbose>1) printf("sim_return_code := %d\n", ret);
646 tacFree(&sim); tacFree(&input); parFree(&par); return(6);
647 }
648 /* Simulate delay time */
649 if(!isnan(dT) && fabs(dT)>1.0E-20) {
650 for(int j=0; j<currentTacNr; j++) {
651 if(verbose>4) {
652 printf(" delay for %s[%d/%d]\n", sim.c[i].name, 1+j, currentTacNr); fflush(stdout);}
653 if((ret=tacDelay(&sim, dT, i+j, &status)) != TPCERROR_OK) break;
654 }
655 if(ret) {
656 fprintf(stderr, "Error: invalid delay time for simulation.\n");
657 if(verbose>2) printf("sim_return_code := %d\n", ret);
658 tacFree(&sim); tacFree(&input); parFree(&par); return(7);
659 }
660 }
661 } // next TAC
662
663 /* simulation done */
664 tacFree(&input); parFree(&par);
665
666
667 /*
668 * Save simulated data
669 */
670 if(verbose>1) printf("writing %s\n", simfile);
671 FILE *fp; fp=fopen(simfile, "w");
672 if(fp==NULL) {
673 fprintf(stderr, "Error: cannot open file for writing (%s)\n", simfile);
674 tacFree(&sim); return(11);
675 }
676 ret=tacWrite(&sim, fp, TAC_FORMAT_PMOD, 1, &status);
677 fclose(fp); tacFree(&sim);
678 if(ret!=TPCERROR_OK) {
679 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
680 return(12);
681 }
682 if(verbose>=0) {printf("%s saved.\n", simfile); fflush(stdout);}
683
684 return(0);
685}
686/*****************************************************************************/
687
688/*****************************************************************************/
int tacDelay(TAC *tac, double dt, int ti, TPCSTATUS *status)
Move TAC y values (concentrations) in time, keeping sample times (x values) intact.
Definition delay.c:29
int atoiCheck(const char *s, int *v)
Definition intutil.c:25
char * modelCode(const unsigned int i)
Definition modell.c:176
unsigned int modelParNr(const unsigned int code)
Definition modell.c:256
unsigned int modelCodeIndex(const char *s)
Definition modell.c:237
void parFree(PAR *par)
Definition par.c:75
int parAllocate(PAR *par, int parNr, int tacNr)
Definition par.c:108
void parInit(PAR *par)
Definition par.c:25
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
Definition pario.c:148
int parRead(PAR *par, const char *fname, TPCSTATUS *status)
Definition pario.c:232
double parGetParameter(PAR *d, const char *par_name, const int ti)
Definition parselect.c:242
void parValueRange(PAR *d, const int i, double *pmin, double *pmax)
Definition parselect.c:287
int parFindParameter(PAR *d, const char *par_name)
Definition parselect.c:219
int tacAllocateWithPAR(TAC *tac, PAR *par, int sampleNr, TPCSTATUS *status)
Allocate TAC based on data in PAR.
Definition partac.c:28
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:169
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:339
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:114
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)
Definition sim3cmp.c:33
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)
Definition sim3cmp.c:140
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)
Definition sim3cms.c:143
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)
Definition sim3cms.c:32
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
char * errorMsg(tpcerror e)
Definition statusmsg.c:68
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
Definition tpcpar.h:100
int parNr
Definition tpcpar.h:108
int tacNr
Definition tpcpar.h:104
PARR * r
Definition tpcpar.h:114
PARN * n
Definition tpcpar.h:112
int unit
Definition tpcpar.h:86
char name[MAX_PARNAME_LEN+1]
Definition tpcpar.h:82
char name[MAX_TACNAME_LEN+1]
Definition tpcpar.h:50
unsigned int model
Definition tpcpar.h:48
double * p
Definition tpcpar.h:64
char name[MAX_TACNAME_LEN+1]
Definition tpctac.h:81
double * y
Definition tpctac.h:75
Definition tpctac.h:87
double * x
Definition tpctac.h:97
unit cunit
Definition tpctac.h:105
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
int isframe
Definition tpctac.h:95
TACC * c
Definition tpctac.h:117
weights weighting
Definition tpctac.h:115
unit tunit
Definition tpctac.h:109
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
void tacFree(TAC *tac)
Definition tac.c:106
void tacInit(TAC *tac)
Definition tac.c:24
int tacAllocateMore(TAC *tac, int tacNr)
Definition tac.c:178
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
int tacReadModelingInput(const char *inputfile1, const char *inputfile2, const char *inputfile3, TAC *inp, TPCSTATUS *status)
Read arterial input data for modelling.
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_MIN
minutes
@ UNIT_ML_PER_ML
mL/mL
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ UNIT_UNKNOWN
Unknown unit.
@ UNIT_PER_SEC
1/s
@ UNIT_ML_PER_DL_MIN
mL/(dL*min)
@ UNIT_UNITLESS
Unitless.
@ UNIT_SEC
seconds
@ UNIT_ML_PER_ML_SEC
mL/(mL*sec)
@ UNIT_PER_MIN
1/min
@ UNIT_PERCENTAGE
Percentage (%).
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.
Header file for libtpcpar.
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Definition tpcpar.h:35
Header file for library libtpctac.
@ TAC_FORMAT_PMOD
PMOD TAC format.
Definition tpctac.h:33
Header file for libtpctacmod.