TPCCLIB
Loading...
Searching...
No Matches
sim_h2o.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 "tpcfileutil.h"
17#include "tpcift.h"
18#include "tpctac.h"
19#include "tpcpar.h"
20#include "tpctacmod.h"
21#include "tpccm.h"
22/*****************************************************************************/
23
24/*****************************************************************************/
25static char *info[] = {
26 "Simulation of PET tissue time-radioactivity concentration curves (TACs)",
27 "from arterial blood (Ca) TACs, based on compartmental model for radiowater.",
28 "Model has two parameters, perfusion (blood flow, f) and partition",
29 "coefficient of water (p).",
30 "Delay (deltat) and dispersion (tau) of arterial input function (AIF),",
31 "perfusable tissue fraction (PTF), and arterial volume fraction (Va) can be",
32 "included in the simulation.",
33 " ",
34 " dAIF(t)/dt = (1/tau)*Ca(T-deltat) - (1/tau)*AIF(T-deltat) ",
35 " dCt(t)/dt = f*AIF(T) - (f/p)*Ct(T) ",
36 " Cpet(T)= PTF*Ct(T) + Va*AIF(T) ",
37 " ",
38 "Usage: @P [options] parfile [bloodfile simfile]",
39 " ",
40 "Options:",
41 " -stdoptions", // List standard options like --help, -v, etc
42 " ",
43 "To create a template parameter file, do not enter names for input and",
44 "simulated TACs.",
45 "If parameter file does not contain units, then per min and per mL units",
46 "are assumed for f, p, PTF and Va, and seconds for deltat and tau.",
47 "For accurate results, blood TAC should have very short sampling intervals.",
48 " ",
49 "See also: b2t_h2o, sim_3tcm, fit_h2o, fit_wrlv, tacadd, simframe",
50 " ",
51 "Keywords: TAC, simulation, compartmental model, perfusion, radiowater",
52 0};
53/*****************************************************************************/
54
55/*****************************************************************************/
56/* Turn on the globbing of the command line, since it is disabled by default in
57 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
58 In Unix&Linux wildcard command line processing is enabled by default. */
59/*
60#undef _CRT_glob
61#define _CRT_glob -1
62*/
63int _dowildcard = -1;
64/*****************************************************************************/
65
66/*****************************************************************************/
70int main(int argc, char **argv)
71{
72 int ai, help=0, version=0, verbose=1;
73 char blofile[FILENAME_MAX], simfile[FILENAME_MAX], parfile[FILENAME_MAX];
74 PAR par;
75 int ret;
76
77
78 /*
79 * Get arguments
80 */
81 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
82 blofile[0]=simfile[0]=parfile[0]=(char)0;
83 parInit(&par);
84 /* Options */
85 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
86 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
87 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
88 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
89 return(1);
90 } else break; // tac name argument may start with '-'
91
92 TPCSTATUS status; statusInit(&status);
93 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
94 status.verbose=verbose-1;
95
96 /* Print help or version? */
97 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
98 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
99 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
100
101 /* Process other arguments, starting from the first non-option */
102 if(ai<argc) strlcpy(parfile, argv[ai++], FILENAME_MAX);
103 if(ai<argc) strlcpy(blofile, argv[ai++], FILENAME_MAX);
104 if(ai<argc) strlcpy(simfile, argv[ai++], FILENAME_MAX);
105 if(ai<argc) {
106 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
107 return(1);
108 }
109
110 /* Is something missing? */
111 if(!parfile[0]) {
112 fprintf(stderr, "Error: missing parameter file; use option --help\n");
113 return(1);
114 }
115 if(blofile[0] && !simfile[0]) {
116 fprintf(stderr, "Error: missing file name.\n");
117 return(1);
118 }
119 if(fileExist(parfile) && !simfile[0]) {
120 fprintf(stderr, "Error: missing file names.\n");
121 parFree(&par); return(1);
122 }
123
124
125 /* In verbose mode print arguments and options */
126 if(verbose>1) {
127 printf("parfile := %s\n", parfile);
128 printf("blofile := %s\n", blofile);
129 printf("simfile := %s\n", simfile);
130 fflush(stdout);
131 }
132
133
134 /*
135 * Make template parameter file, if no other file names were given, and then quit
136 */
137 if(!blofile[0]) {
138 /* We have already checked that parameter file does not exist */
139
140 /* Allocate space for 6 parameters, 4 TTACs */
141 ret=parAllocate(&par, 6, 4);
142 if(ret) {
143 fprintf(stderr, "Error: cannot allocate memory for parameters.\n");
144 parFree(&par); return(1);
145 }
146 par.parNr=6; par.tacNr=4;
147 strcpy(par.n[0].name, "f"); par.n[0].unit=UNIT_ML_PER_ML_MIN;
148 strcpy(par.n[1].name, "p"); par.n[1].unit=UNIT_ML_PER_ML;
149 strcpy(par.n[2].name, "PTF"); par.n[2].unit=UNIT_ML_PER_ML;
150 strcpy(par.n[3].name, "Va"); par.n[3].unit=UNIT_ML_PER_ML;
151 strcpy(par.n[4].name, "deltaT"); par.n[4].unit=UNIT_SEC;
152 strcpy(par.n[5].name, "tau"); par.n[5].unit=UNIT_SEC;
153 for(int i=0; i<par.tacNr; i++) {
154 sprintf(par.r[i].name, "tac%d", 1+i);
155 par.r[i].model=modelCodeIndex("radiowater2");
156 }
157 int ri=0; // first TTAC
158 par.r[ri].p[0]=1.0;
159 par.r[ri].p[1]=1.0;
160 par.r[ri].p[2]=0.6;
161 par.r[ri].p[3]=0.2;
162 par.r[ri].p[4]=0.0;
163 par.r[ri].p[5]=0.0;
164 ri++;
165 par.r[ri].p[0]=4.0;
166 par.r[ri].p[1]=1.0;
167 par.r[ri].p[2]=0.6;
168 par.r[ri].p[3]=0.2;
169 par.r[ri].p[4]=0.0;
170 par.r[ri].p[5]=0.0;
171 ri++;
172 par.r[ri].p[0]=0.2;
173 par.r[ri].p[1]=0.8;
174 par.r[ri].p[2]=0.97;
175 par.r[ri].p[3]=0.03;
176 par.r[ri].p[4]=5.0;
177 par.r[ri].p[5]=0.0;
178 ri++;
179 par.r[ri].p[0]=0.2;
180 par.r[ri].p[1]=0.8;
181 par.r[ri].p[2]=0.97;
182 par.r[ri].p[3]=0.03;
183 par.r[ri].p[4]=5.0;
184 par.r[ri].p[5]=5.0;
185
186 if(verbose>1) printf("writing %s\n", parfile);
187 FILE *fp; fp=fopen(parfile, "w");
188 if(fp==NULL) {
189 fprintf(stderr, "Error: cannot open file for writing (%s)\n", parfile);
190 parFree(&par); return(11);
191 }
192 ret=parWrite(&par, fp, PAR_FORMAT_TSV_UK, 1, &status);
193 fclose(fp); parFree(&par);
194 if(ret!=TPCERROR_OK) {
195 fprintf(stderr, "Error: cannot write %s\n", parfile);
196 return(12);
197 }
198 if(verbose>=0) {printf("%s saved.\n", parfile); fflush(stdout);}
199 return(0);
200 }
201
202
203 /*
204 * Read parameter file to get parameters for the simulation
205 */
206 if(verbose>1) fprintf(stdout, "reading %s\n", parfile);
207 if(parRead(&par, parfile, &status)) {
208 fprintf(stderr, "Error: %s (%s)\n", errorMsg(status.error), parfile);
209 parFree(&par);
210 return(3);
211 }
212 if(verbose>5) parWrite(&par, stdout, PAR_FORMAT_TSV_UK, 1, NULL);
213 /* Check the validity of model and its parameters */
214 for(int i=0; i<par.tacNr; i++) {
215 if(verbose>3) printf("model %s for tac %s\n", modelCode(par.r[i].model), par.r[i].name);
216 if(par.r[i].model!=modelCodeIndex("radiowater2")) {
217 fprintf(stderr, "Error: parameter file has invalid model '%s'.\n", modelDesc(par.r[i].model));
218 parFree(&par); return(3);
219 }
220 /* check that we got at least as many parameters as the model has */
221 if(par.parNr<(int)modelParNr(par.r[i].model)) {
222 fprintf(stderr, "Error: invalid parameters for selected model.\n");
223 parFree(&par); return(3);
224 }
225 }
226 /* check that we can find the obligatory model parameters */
227 int i_deltaT=-1, i_tau=-1, i_f=-1, i_p=-1, i_PTF=-1, i_Va=-1;
228 {
229 ret=0;
230 if((i_f=parFindParameter(&par, "f"))<0) ret++;
231 if((i_p=parFindParameter(&par, "p"))<0) ret++;
232 if((i_PTF=parFindParameter(&par, "PTF"))<0) ret++;
233 if((i_Va=parFindParameter(&par, "Va"))<0) ret++;
234 if((i_deltaT=parFindParameter(&par, "deltaT"))<0 &&
235 (i_deltaT=parFindParameter(&par, "delayT"))<0) ret++;
236 if((i_tau=parFindParameter(&par, "tau"))<0) ret++;
237 if(ret) {
238 fprintf(stderr, "Error: required parameters not available.\n");
239 parFree(&par); return(3);
240 }
241 if(verbose>5) {
242 printf("parameter indices:\n");
243 printf(" f=p[%d]\n", i_f);
244 printf(" p=p[%d]\n", i_p);
245 printf(" PTF=p[%d]\n", i_PTF);
246 printf(" Va=p[%d]\n", i_Va);
247 printf(" deltaT=p[%d]\n", i_deltaT);
248 printf(" tau=p[%d]\n", i_tau);
249 }
250 }
251
252
253 /*
254 * Read input TAC
255 */
256 if(verbose>1) fprintf(stdout, "reading input TAC\n");
257 TAC input; tacInit(&input);
258 ret=tacReadModelingInput(blofile, NULL, NULL, &input, &status);
259 if(ret!=TPCERROR_OK) {
260 fprintf(stderr, "Error: %s (input files)\n", errorMsg(status.error));
261 tacFree(&input); parFree(&par); return(4);
262 }
263 if(verbose>2) {
264 printf("fileformat := %s\n", tacFormattxt(input.format));
265 printf("tacNr := %d\n", input.tacNr);
266 printf("sampleNr := %d\n", input.sampleNr);
267 printf("xunit := %s\n", unitName(input.tunit));
268 printf("yunit := %s\n", unitName(input.cunit));
269 }
270 if(verbose>10) tacWrite(&input, stdout, TAC_FORMAT_PMOD, 1, NULL);
271 if(input.sampleNr<3) {
272 fprintf(stderr, "Error: too few samples in input TAC.\n");
273 tacFree(&input); parFree(&par); return(4);
274 }
275 if(input.sampleNr<10) {
276 fprintf(stderr, "Warning: too few samples for reliable simulation.\n"); fflush(stderr);
277 }
278 if(tacXUnitConvert(&input, UNIT_SEC, &status)!=TPCERROR_OK) {
279 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
280 tacFree(&input); parFree(&par); return(4);
281 }
282
283
284 /*
285 * Allocate space for simulated data
286 */
287 if(verbose>1) fprintf(stdout, "allocating space for simulated TACs\n");
288 TAC sim; tacInit(&sim);
289 ret=tacAllocateWithPAR(&sim, &par, input.sampleNr, &status);
290 if(ret!=TPCERROR_OK) {
291 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
292 tacFree(&input); tacFree(&sim); parFree(&par); return(4);
293 }
296 sim.cunit=input.cunit;
297 sim.tunit=input.tunit;
298 sim.format=input.format;
299 sim.isframe=0;
300 for(int j=0; j<sim.sampleNr; j++) sim.x[j]=input.x[j];
301
302
303 /*
304 * Simulation
305 */
306 if(verbose>1) {printf("simulating...\n"); fflush(stdout);}
307 for(int ri=0; ri<sim.tacNr; ri++) {
308 if(verbose>2) {printf(" %s\n", sim.c[ri].name); fflush(stdout);}
309 double cf;
310
311 /* Make delayed and dispersed input TAC */
312 double deltaT=par.r[ri].p[i_deltaT];
313 cf=unitConversionFactor(par.n[i_deltaT].unit, UNIT_SEC); if(isfinite(cf)) deltaT*=cf;
314 if(verbose>4) printf(" deltaT := %g s\n", deltaT);
315
316 double tau=par.r[ri].p[i_tau];
317 cf=unitConversionFactor(par.n[i_tau].unit, UNIT_SEC); if(isfinite(cf)) tau*=cf;
318 if(verbose>4) printf(" tau := %g s\n", tau);
319
320 double buf1[3*sim.sampleNr]; double *buf2=buf1+sim.sampleNr; double *ca=buf2+sim.sampleNr;
321 doubleCopy(buf1, input.c[0].y, sim.sampleNr);
322 if(simDispersion(sim.x, buf1, sim.sampleNr, tau, 0.0, buf2)) {
323 fprintf(stderr, "Error: cannot add dispersion for '%s'.\n", sim.c[ri].name);
324 tacFree(&input); tacFree(&sim); parFree(&par); return(5);
325 }
326 for(int i=0; i<sim.sampleNr; i++) buf2[i]=input.x[i]+deltaT;
327 if(liInterpolate(buf2, buf1, sim.sampleNr, sim.x, ca, NULL, NULL, sim.sampleNr, 3, 1, 0)!=0) {
328 fprintf(stderr, "Error: cannot add delay time for '%s'.\n", sim.c[ri].name);
329 tacFree(&input); tacFree(&sim); parFree(&par); return(5);
330 }
331
332 /* Simulate pure tissue TAC */
333 double f=par.r[ri].p[i_f];
335 if(isfinite(cf)) f*=cf; else f/=60.0;
336 if(verbose>4) printf(" f := %g mL/(s*mL)\n", f);
337 if(!(f>=0.0)) {
338 fprintf(stderr, "Error: invalid f for '%s'.\n", sim.c[ri].name);
339 tacFree(&input); tacFree(&sim); parFree(&par); return(5);
340 }
341
342 double p=par.r[ri].p[i_p];
343 cf=unitConversionFactor(par.n[i_p].unit, UNIT_ML_PER_ML); if(isfinite(cf)) p*=cf;
344 if(verbose>4) printf(" p := %g mL/mL\n", p);
345 double k2=f/p; if(!(k2>=0.0)) {
346 fprintf(stderr, "Error: invalid k2=f/p for '%s'.\n", sim.c[ri].name);
347 tacFree(&input); tacFree(&sim); parFree(&par); return(5);
348 }
349
350 if(simC1(sim.x, ca, sim.sampleNr, f, k2, sim.c[ri].y)) {
351 fprintf(stderr, "Error: cannot simulate '%s'.\n", sim.c[ri].name);
352 tacFree(&input); tacFree(&sim); parFree(&par); return(5);
353 }
354
355 /* Multiply tissue with PTF */
356 double PTF=par.r[ri].p[i_PTF];
357 cf=unitConversionFactor(par.n[i_PTF].unit, UNIT_ML_PER_ML); if(isfinite(cf)) PTF*=cf;
358 if(verbose>4) printf(" PTF := %g mL/mL\n", PTF);
359 if(!(PTF>=0.0)) {
360 fprintf(stderr, "Error: invalid PTF for '%s'.\n", sim.c[ri].name);
361 tacFree(&input); tacFree(&sim); parFree(&par); return(5);
362 }
363 for(int i=0; i<sim.sampleNr; i++) sim.c[ri].y[i]*=PTF;
364
365 /* Add the contribution of arterial blood in tissue vasculature */
366 double Va=par.r[ri].p[i_Va];
367 cf=unitConversionFactor(par.n[i_Va].unit, UNIT_ML_PER_ML); if(isfinite(cf)) Va*=cf;
368 if(verbose>4) printf(" Va := %g mL/mL\n", Va);
369 if(!(Va>=0.0)) {
370 fprintf(stderr, "Error: invalid Va for '%s'.\n", sim.c[ri].name);
371 tacFree(&input); tacFree(&sim); parFree(&par); return(5);
372 }
373 for(int i=0; i<sim.sampleNr; i++) sim.c[ri].y[i]+=Va*ca[i];
374
375 }
376 /* simulation done */
377 tacFree(&input); parFree(&par);
378
379
380 /*
381 * Save simulated data
382 */
383 if(verbose>1) printf("writing %s\n", simfile);
384 FILE *fp; fp=fopen(simfile, "w");
385 if(fp==NULL) {
386 fprintf(stderr, "Error: cannot open file for writing (%s)\n", simfile);
387 tacFree(&sim); return(11);
388 }
389 ret=tacWrite(&sim, fp, TAC_FORMAT_PMOD, 1, &status);
390 fclose(fp); tacFree(&sim);
391 if(ret!=TPCERROR_OK) {
392 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
393 return(12);
394 }
395 if(verbose>=0) {printf("%s saved.\n", simfile); fflush(stdout);}
396
397 return(0);
398}
399/*****************************************************************************/
400
401/*****************************************************************************/
void doubleCopy(double *t, double *s, const unsigned int n)
Definition doubleutil.c:117
int fileExist(const char *filename)
Definition filexist.c:17
int liInterpolate(double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear interpolation and/or integration with trapezoidal method.
char * modelCode(const unsigned int i)
Definition modell.c:176
char * modelDesc(const unsigned int i)
Definition modell.c:222
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
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 simC1(double *t, double *ca, const int nr, const double k1, const double k2, double *ct)
Definition sim1cm.c:93
int simDispersion(double *x, double *y, const int n, const double tau1, const double tau2, double *tmp)
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
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.
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:23
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
mL/mL
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ UNIT_SEC
seconds
@ UNIT_ML_PER_ML_SEC
mL/(mL*sec)
@ TPCERROR_OK
No error.
double unitConversionFactor(const int u1, const int u2)
Definition units.c:487
char * unitName(int unit_code)
Definition units.c:143
Header file for libtpcfileutil.
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.