TPCCLIB
Loading...
Searching...
No Matches
sim_pkcp.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 "tpcextensions.h"
18#include "tpcift.h"
19#include "tpctac.h"
20#include "tpcpar.h"
21#include "tpcli.h"
22#include "tpctacmod.h"
23#include "tpccm.h"
24/*****************************************************************************/
25
26/*****************************************************************************/
27static char *info[] = {
28 "Simulation of drug concentration in plasma using pharmacokinetic compartment",
29 "models.",
30 "Available models, and model parameters:",
31 " O1CM; one-compartment model with first-order absorption and elimination;",
32 " ED/V1, ka, ke.",
33 " O2CM; two-compartment model with first-order absorption and elimination;",
34 " ED/V1, ka, kd, kr, ke.",
35 " ",
36 "Usage: @P [options] parfile [simfile]",
37 " ",
38 "Options:",
39 " -model=<O1CM|O2CM>",
40 " Select the model used to simulate the plasma curve; by default the model",
41 " is read from the parameter file.",
42/* " -nr=<nr of samples>",
43 " Number of samples to simulate; by default read from parfile;",
44 " precise simulation requires frequent samples.",
45*/
46 " -stdoptions", // List standard options like --help, -v, etc
47 " ",
48 "To create a template parameter file, do not enter filename for simulated",
49 "data, but give the model with option -model.",
50 "Simulated time range is determined based on the parameter file.",
51 " ",
52 "See also: paucinf, sim_3tcm, tacadd, interpol",
53 " ",
54 "Keywords: plasma, pharmacokinetics",
55 0};
56/*****************************************************************************/
57
58/*****************************************************************************/
59/* Turn on the globbing of the command line, since it is disabled by default in
60 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
61 In Unix&Linux wildcard command line processing is enabled by default. */
62/*
63#undef _CRT_glob
64#define _CRT_glob -1
65*/
66int _dowildcard = -1;
67/*****************************************************************************/
68
69/*****************************************************************************/
73int main(int argc, char **argv)
74{
75 int ai, help=0, version=0, verbose=1;
76 char simfile[FILENAME_MAX], parfile[FILENAME_MAX];
77 char *cptr;
78 unsigned int model=0, parNr=0;
79 double startTime=nan(""), endTime=nan(""); // hours
80 int ret, pi;
81
82
83 /*
84 * Get arguments
85 */
86 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
87 simfile[0]=parfile[0]=(char)0;
88 /* Options */
89 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
90 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
91 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
92 if(strncasecmp(cptr, "MODEL=", 6)==0 && strlen(cptr)>7) {
93 cptr+=6;
94 model=modelCodeIndex(cptr); if(model!=0) continue;
95 fprintf(stderr, "Error: invalid model selection.\n"); return(1);
96 }
97 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
98 return(1);
99 } else break; // tac name argument may start with '-'
100
101 TPCSTATUS status; statusInit(&status);
102 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
103 status.verbose=verbose-1;
104
105 /* Print help or version? */
106 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
107 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
108 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
109
110 /* Process other arguments, starting from the first non-option */
111 if(ai<argc) {strlcpy(parfile, argv[ai++], FILENAME_MAX);}
112 if(ai<argc) {strlcpy(simfile, argv[ai++], FILENAME_MAX);}
113 if(ai<argc) {
114 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
115 return(1);
116 }
117
118 /* Is something missing? */
119 if(!parfile[0]) {
120 fprintf(stderr, "Error: missing parameter file; use option --help\n");
121 return(1);
122 }
123
124 /* In verbose mode print arguments and options */
125 if(verbose>1) {
126 if(model!=0) printf("model := %s\n", modelCode(model));
127 printf("parfile := %s\n", parfile);
128 printf("simfile := %s\n", simfile);
129 }
130
131
132
133 /*
134 * Make template parameter file, if no other filenames were given,
135 * and then quit
136 */
137 if(!simfile[0]) {
138 parNr=modelParNr(model);
139 if(model==0 || parNr==0) {
140 fprintf(stderr, "Error: unknown simulation model; use option -model.\n");
141 return(1);
142 }
143 PAR par; parInit(&par);
144 ret=parAllocate(&par, parNr, 3);
145 if(ret) {
146 fprintf(stderr, "Error: cannot allocate memory for parameters.\n");
147 parFree(&par); return(1);
148 }
149 par.parNr=parNr; par.tacNr=3;
150 for(int i=0; i<par.tacNr; i++) {
151 sprintf(par.r[i].name, "Cp%d", 1+i);
152 par.r[i].model=model;
153 par.r[i].start=0.0;
154 par.r[i].end=720.0; // 12h
155 par.r[i].dataNr=12;
156 }
157 if(!strcmp(modelCode(model), "O1CM")) {
158 strcpy(par.n[0].name, "ED/V1"); par.n[0].unit=UNIT_UMOL_PER_L;
159 strcpy(par.n[1].name, "ka"); par.n[1].unit=UNIT_PER_HOUR;
160 strcpy(par.n[2].name, "ke"); par.n[2].unit=UNIT_PER_HOUR;
161 par.r[0].p[0]=1.0;
162 par.r[0].p[1]=0.6;
163 par.r[0].p[2]=0.03;
164 for(int i=1; i<par.tacNr; i++) {
165 par.r[i].p[0]=1.0*par.r[i-1].p[0];
166 par.r[i].p[1]=1.0*par.r[i-1].p[1];
167 par.r[i].p[2]=2.0*par.r[i-1].p[2];
168 }
169 } else if(!strcmp(modelCode(model), "O2CM")) {
170 strcpy(par.n[0].name, "ED/V1"); par.n[0].unit=UNIT_UMOL_PER_L;
171 strcpy(par.n[1].name, "ka"); par.n[1].unit=UNIT_PER_HOUR;
172 strcpy(par.n[2].name, "kd"); par.n[2].unit=UNIT_PER_HOUR;
173 strcpy(par.n[3].name, "kr"); par.n[3].unit=UNIT_PER_HOUR;
174 strcpy(par.n[4].name, "ke"); par.n[4].unit=UNIT_PER_HOUR;
175 par.r[0].p[0]=1.0;
176 par.r[0].p[1]=0.6;
177 par.r[0].p[2]=0.02;
178 par.r[0].p[3]=0.02;
179 par.r[0].p[4]=0.04;
180 for(int i=1; i<par.tacNr; i++) {
181 par.r[i].p[0]=1.0*par.r[i-1].p[0];
182 par.r[i].p[1]=1.0*par.r[i-1].p[1];
183 par.r[i].p[2]=2.0*par.r[i-1].p[2];
184 par.r[i].p[3]=2.0*par.r[i-1].p[3];
185 par.r[i].p[4]=1.0*par.r[i-1].p[4];
186 }
187 } else {
188 fprintf(stderr, "Error: incompatible simulation model.\n");
189 return(1);
190 }
191 if(verbose>1) printf("writing %s\n", parfile);
192 FILE *fp; fp=fopen(parfile, "w");
193 if(fp==NULL) {
194 fprintf(stderr, "Error: cannot open file for writing (%s)\n", parfile);
195 parFree(&par); return(11);
196 }
197 ret=parWrite(&par, fp, PAR_FORMAT_CSV_UK, 1, &status);
198 fclose(fp);
199 parFree(&par); return(0);
200 }
201
202
203 /*
204 * Read parameter file to get parameters for the simulation, and
205 * set model in case it was given with command-line option.
206 */
207 if(verbose>1) fprintf(stdout, "reading %s\n", parfile);
208 PAR par; parInit(&par);
209 if(parRead(&par, parfile, &status)) {
210 fprintf(stderr, "Error: %s (%s)\n", errorMsg(status.error), parfile);
211 parFree(&par);
212 return(3);
213 }
214 if(verbose>5) parWrite(&par, stdout, PAR_FORMAT_TSV_UK, 1, NULL);
215
216 if(model!=0) for(int i=0; i<par.tacNr; i++) par.r[i].model=model;
217 /* Check the validity of model and its parameters */
218 for(int i=0; i<par.tacNr; i++) {
219 if(verbose>3)
220 printf("model %s for tac %s\n", modelCode(par.r[i].model), par.r[i].name);
221 /* check that we got at least as many parameters as the model has */
222 if(modelParNr(par.r[i].model)>(unsigned int)par.parNr) {
223 fprintf(stderr, "Error: invalid parameters for selected model.\n");
224 parFree(&par); return(3);
225 }
226 /* check that we can find the obligatory model parameters */
227 ret=0;
228 if(parFindParameter(&par, "ED/V1")<0) ret++;
229 if(parFindParameter(&par, "ka")<0) ret++;
230 if(!strcmp(modelCode(par.r[i].model), "O1CM")) {
231 if(parFindParameter(&par, "ke")<0) ret++;
232 } else if(!strcmp(modelCode(par.r[i].model), "O2CM")) {
233 if(parFindParameter(&par, "kd")<0) ret++;
234 if(parFindParameter(&par, "kr")<0) ret++;
235 if(parFindParameter(&par, "ke")<0) ret++;
236 } else {
237 fprintf(stderr, "Error: invalid model for this simulation.\n");
238 if(verbose>1) printf("model := %s\n", modelCode(par.r[i].model));
239 parFree(&par); return(3);
240 }
241 if(ret) {
242 fprintf(stderr, "Error: required parameters not available.\n");
243 parFree(&par); return(3);
244 }
245 }
246
247#if(0)
248 /* If user did not give sampleNr, then try to get that from parameter file */
249 if(sampleNr<1) {
250 for(int i=0; i<par.tacNr; i++)
251 if(par.r[i].dataNr>sampleNr) sampleNr=par.r[i].dataNr;
252 /* If not there either, then use 100 as the default */
253 if(sampleNr<1) {
254 sampleNr=100;
255 if(verbose>0) fprintf(stderr, "Warning: unknown sample nr; set to %d.\n", sampleNr);
256 }
257 }
258#endif
259 /* Try to get time range from parameter file */
260 for(int i=0; i<par.tacNr; i++) {
261 if(isnan(startTime) || par.r[i].start<startTime) startTime=par.r[i].start;
262 if(isnan(endTime) || par.r[i].end>endTime) endTime=par.r[i].end;
263 }
264 startTime/=60.0; endTime/=60.0;
265 if(isnan(startTime)) startTime=0.0;
266 if(isnan(endTime) || endTime<=startTime) endTime=12.0+fabs(startTime);
267 if(verbose>1) {
268// printf("sampleNr := %d\n", sampleNr);
269 printf("startTime[h] := %g\n", startTime);
270 printf("endTime[h] := %g\n", endTime);
271 }
272
273
274
275 /*
276 * Allocate space for the simulated data;
277 * must start from 0 time, and have frequent sampling.
278 */
279 /* Try to find the smallest ka */
280 double ka=0.0;
281 pi=parFindParameter(&par, "ka");
282 if(pi>=0) {
283 ka=par.r[0].p[pi];
284 for(int i=0; i<par.tacNr; i++)
285 if(par.r[i].p[pi]<ka) ka=par.r[i].p[pi];
286 }
287 if(ka<=0.0) ka=1.0;
288 /* Set sample nr */
289 int isampleNr;
290 isampleNr=(int)simSamples(0.0001/ka, 0.01*endTime, endTime, 2, NULL);
291 if(verbose>2) {
292 printf("isampleNr := %u\n", isampleNr);
293 }
294 /* Allocate TAC struct for the simulated plasma curve(s) */
295 if(verbose>1)
296 printf("allocating memory for %d samples and %d curves\n",
297 isampleNr, par.tacNr);
298 TAC sim; tacInit(&sim);
299 if(tacAllocateWithPAR(&sim, &par, isampleNr, &status)!=TPCERROR_OK) {
300 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
301 parFree(&par);
302 return(4);
303 }
304/*
305 ret=tacAllocate(&sim, isampleNr, par.tacNr);
306 if(ret!=TPCERROR_OK) {
307 fprintf(stderr, "Error: %s\n", errorMsg(ret));
308 parFree(&par); tacFree(&sim); return(4);
309 }
310*/
311 sim.sampleNr=isampleNr;
312 sim.tacNr=par.tacNr;
314 pi=parFindParameter(&par, "ED/V1"); if(pi>=0) sim.cunit=par.n[pi].unit;
315 pi=parFindParameter(&par, "ka");
316 if(pi>=0 && par.n[pi].unit==UNIT_PER_HOUR) {
317 sim.tunit=UNIT_HOUR;
318 }
320 sim.isframe=0;
321 /* Set sample times */
322 simSamples(0.0001/ka, 0.01*endTime, endTime, 2, sim.x);
323
324
325
326 /*
327 * Simulate data for each parameter set
328 */
329 double gi[isampleNr], bufi[isampleNr];
330 for(int i=0; i<par.tacNr; i++) {
331 if(verbose>2 && par.tacNr>1) printf("\nSimulation %d\n", 1+i);
332 /* Set curve name */
333 strcpy(sim.c[i].name, par.r[i].name);
334
335 /* Get the parameter values */
336 double k1, ka, kd, kr, ke;
337
338 k1=parGetParameter(&par, "ED/V1", i);
339 ka=parGetParameter(&par, "ka", i);
340 ke=parGetParameter(&par, "ke", i);
341 kd=parGetParameter(&par, "kd", i); if(isnan(kd)) kd=0.0;
342 kr=parGetParameter(&par, "kr", i); if(isnan(kr)) kr=0.0;
343 if(isnan(k1) || isnan(ka) || isnan(ke)) {
344 fprintf(stderr, "Error: required parameters not available.\n");
345 parFree(&par); tacFree(&sim); return(3);
346 }
347 if(verbose>3) {
348 printf(" ED/V1 := %g\n", k1);
349 printf(" ka := %g\n", ka);
350 printf(" ke := %g\n", ke);
351 printf(" kd := %g\n", kd);
352 printf(" kr := %g\n", kr);
353 }
354 /* Integral of input from GI; (1-e^-ka*t)/ka */
355 for(int j=0; j<isampleNr; j++)
356 gi[j]=(1.0-exp(-ka*sim.x[j]))/ka;
357 /* Simulation of drug concentration in plasma; this equals the concentration
358 in the central (1st) compartment. */
359 double *cp=sim.c[i].y;
360 ret=simC2_i(sim.x, gi, isampleNr, k1, ke, kd, kr, bufi, cp, NULL);
361 if(ret!=0) {
362 fprintf(stderr, "Error: cannot simulate.\n");
363 parFree(&par); tacFree(&sim); return(5);
364 }
365 if(verbose>8)
366 for(int j=0; j<isampleNr; j++)
367 printf("\t%g\t%g\n", sim.x[j], cp[j]);
368 }
369
370
371 /*
372 * Save simulated data
373 */
374 if(verbose>1) printf("writing %s\n", simfile);
375 FILE *fp; fp=fopen(simfile, "w");
376 if(fp==NULL) {
377 fprintf(stderr, "Error: cannot open file for writing (%s)\n", simfile);
378 parFree(&par); tacFree(&sim); return(11);
379 }
380 ret=tacWrite(&sim, fp, TAC_FORMAT_UNKNOWN, 1, &status);
381 fclose(fp);
382 parFree(&par); tacFree(&sim);
383 if(ret!=TPCERROR_OK) {
384 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
385 return(12);
386 }
387 if(verbose>=0) printf("%s saved.\n", simfile);
388
389 return(0);
390}
391/*****************************************************************************/
392
393/*****************************************************************************/
unsigned int simSamples(double initStep, double maxStep, double endTime, int mode, double *x)
Definition interpolate.c:50
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
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 simC2_i(double *t, double *cai, const int nr, const double k1, const double k2, const double k3, const double k4, double *ct, double *cta, double *ctb)
Definition sim2cm.c:124
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
int dataNr
Definition tpcpar.h:62
unsigned int model
Definition tpcpar.h:48
double * p
Definition tpcpar.h:64
double start
Definition tpcpar.h:52
double end
Definition tpcpar.h:54
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 tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
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_UMOL_PER_L
umol/L
@ UNIT_PER_HOUR
1/h
@ UNIT_HOUR
hours
@ TPCERROR_OK
No error.
Header file for library libtpcift.
Header file for libtpcli.
Header file for libtpcpar.
@ PAR_FORMAT_CSV_UK
UK CSV.
Definition tpcpar.h:33
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Definition tpcpar.h:35
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28
@ TAC_FORMAT_PMOD
PMOD TAC format.
Definition tpctac.h:33
Header file for libtpctacmod.