8#include "tpcclibConfig.h"
31double func_pbr_src(
int parNr,
double *p,
void*);
32double func_pbr_fm2(
int parNr,
double *p,
void*);
33double func_pbr_rf(
int parNr,
double *p,
void*);
34double func_pbr_hill(
int parNr,
double *p,
void*);
36typedef struct FITDATA {
55static char *info[] = {
56 "Non-linear fitting of a function to sampled plasma-to-blood ratio (PBR) data.",
58 "Plasma-to-blood ratio is calculated from RBC-to-plasma ratio (RPC) as",
59 " PBR(t)=1/((1-HCT)+HCT*RPC(t))",
60 "and RBC-to-plasma ratio is modelled with function 1 (SRC)",
61 " RPC(t)=p1*t*exp(-p2*t) + p3*p1*(1-exp(-p2*t)*(1+p2*t))/(p2*p2)",
63 " RPC(t)=(p1*t-p3-p5)*exp(-p2*t) + p3*exp(-p4*t) + p5*exp(-p6*t)",
65 " RPC(t)=(p1*t + p3*t^2 + p5*t^3) / (1 + p2*t + p4*t^2 + p6*t^3)",
66 "or function 4 (HILL)",
67 " RPC(t)=(p1*t^p2)/(t^p2 + p3)",
69 "Usage: @P [Options] datafile [parfile]",
72 " -HCT=<Haematocrit>",
73 " Constrain haematocrit to specified value; fitted by default.",
74 " -model=<SRC|FM2|RF|HILL>",
75 " Use function 1 (SCR, default), function 2 (FM2), function 3 (RF), or",
76 " function 4 (HILL).",
78 " Sum-of-squares (OLS) is minimized by default, but optionally",
79 " sum of absolute deviations (LAD) can be selected.",
81 " All weights are set to 1.0 (no weighting); by default, weights in",
82 " data file are used, if available.",
84 " Weight by sampling interval.",
86 " Parameter k is constrained to given value.",
88 " Specify the constraints for function parameters;",
89 " This file with default values can be created by giving this option",
90 " as the only command-line argument to this program.",
91 " Without file name the default values are printed on screen.",
93 " Fitted and measured TACs are plotted in specified SVG file.",
96 "Datafile must contain at least 2 columns, sample times and ratios,",
97 "possibly also weights as last column.",
100 " @P -svg=ia765pbrat.svg ia765pb.rat ia765pbrat.fit",
102 "See also: fit_bpr, tacinv, tacblend, b2rbc, bpr2cpr, fit_sigm, fit_hiad",
104 "Keywords: curve fitting, input, blood, plasma, modelling, simulation",
128int main(
int argc,
char **argv)
130 int ai, help=0, version=0, verbose=1;
131 char pbrfile[FILENAME_MAX], parfile[FILENAME_MAX];
132 char limfile[FILENAME_MAX], svgfile[FILENAME_MAX];
134 double fixed_hct=nan(
"");
135 double fixed_k=nan(
"");
145 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
146 pbrfile[0]=parfile[0]=svgfile[0]=limfile[0]=(char)0;
148 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
150 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
151 if(strcasecmp(cptr,
"W1")==0) {
153 }
else if(strcasecmp(cptr,
"WF")==0) {
155 }
else if(strncasecmp(cptr,
"MIN=", 4)==0 && strlen(cptr)>4) {
157 }
else if(strncasecmp(cptr,
"LIM=", 4)==0 && strlen(cptr)>4) {
158 strlcpy(limfile, cptr+4, FILENAME_MAX);
continue;
159 }
else if(strncasecmp(cptr,
"SVG=", 4)==0 && strlen(cptr)>4) {
160 strlcpy(svgfile, cptr+4, FILENAME_MAX);
continue;
161 }
else if(strncasecmp(cptr,
"K=", 2)==0 && strlen(cptr)>2) {
162 if(!
atofCheck(cptr+2, &fixed_k) && fixed_k>=0.0)
continue;
163 }
else if(strncasecmp(cptr,
"MODEL=", 6)==0 && strlen(cptr)>6) {
165 if(strcasecmp(cptr,
"SRC")==0) {model=
modelCodeIndex(
"p2bsrc");
continue;}
166 if(strcasecmp(cptr,
"FM2")==0) {model=
modelCodeIndex(
"p2bfm2");
continue;}
167 if(strcasecmp(cptr,
"RF")==0) {model=
modelCodeIndex(
"p2brf");
continue;}
168 if(strcasecmp(cptr,
"HILL")==0) {model=
modelCodeIndex(
"p2bhill");
continue;}
169 if(strcasecmp(cptr,
"1")==0) {model=
modelCodeIndex(
"p2bsrc");
continue;}
170 if(strcasecmp(cptr,
"2")==0) {model=
modelCodeIndex(
"p2bfm2");
continue;}
171 if(strcasecmp(cptr,
"3")==0) {model=
modelCodeIndex(
"p2brf");
continue;}
172 if(strcasecmp(cptr,
"4")==0) {model=
modelCodeIndex(
"p2bhill");
continue;}
173 }
else if(strncasecmp(cptr,
"HCT=", 4)==0 && strlen(cptr)>4) {
174 if(!
atofCheck(cptr+4, &fixed_hct) && fixed_hct>0.0 && fixed_hct<1.0)
continue;
176 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
185 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
190 if(ai<argc)
strlcpy(pbrfile, argv[ai++], FILENAME_MAX);
191 if(ai<argc)
strlcpy(parfile, argv[ai++], FILENAME_MAX);
192 if(ai<argc) {fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
return(1);}
196 printf(
"pbrfile := %s\n", pbrfile);
197 if(parfile[0]) printf(
"parfile := %s\n", parfile);
198 if(limfile[0]) printf(
"limfile := %s\n", limfile);
199 if(svgfile[0]) printf(
"svgfile := %s\n", svgfile);
200 printf(
"weights := %d\n",
weights);
201 if(!isnan(fixed_k)) printf(
"fixed_k := %g\n", fixed_k);
202 if(!isnan(fixed_hct)) printf(
"fixed_hct := %g\n", fixed_hct);
204 printf(
"model := %s\n",
modelDesc(model));
210 fprintf(stderr,
"Error: cannot initiate parameter list.\n");
return(1);}
212 strcpy(plim.
n[0].
name,
"HCT"); plim.
n[0].
lim1=0.36; plim.
n[0].
lim2=0.50;
214 strcpy(plim.
n[1].
name,
"A"); plim.
n[1].
lim1=1.0E-06; plim.
n[1].
lim2=1.0E+02;
215 strcpy(plim.
n[2].
name,
"L"); plim.
n[2].
lim1=1.0E-06; plim.
n[2].
lim2=5.0;
230 strcpy(plim.
n[6].
name,
"L3"); plim.
n[6].
lim1=-0.1; plim.
n[6].
lim2=0.01;
234 strcpy(plim.
n[3].
name,
"p3"); plim.
n[3].
lim1=0.001; plim.
n[3].
lim2=5000.0;
237 if(limfile[0] && !pbrfile[0]) {
239 if(strcasecmp(limfile,
"stdout")!=0 &&
fileExist(limfile)) {
240 fprintf(stderr,
"Error: parameter constraint file %s exists.\n", limfile);
245 if(verbose>1 && strcasecmp(limfile,
"stdout")!=0)
246 printf(
"writing parameter constraints file\n");
248 fprintf(stderr,
"Error: cannot write constraints file.\n");
251 if(strcasecmp(limfile,
"stdout")!=0)
252 fprintf(stdout,
"Parameter constraints written in %s\n", limfile);
258 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
262 fprintf(stderr,
"Error: optimality criterion not supported.\n");
265 if(strcasecmp(limfile,
"stdout")==0) limfile[0]=(char)0;
273 fprintf(stderr,
"Error: cannot read constraints file.\n");
279 if(!isnan(fixed_hct)) plim.
n[0].
lim1=plim.
n[0].
lim2=fixed_hct;
288 if(verbose>1) printf(
"reading %s\n", pbrfile);
296 printf(
"tacNr := %d\n", tac.
tacNr);
297 printf(
"sampleNr := %d\n", tac.
sampleNr);
300 printf(
"isframe := %d\n", tac.
isframe);
303 fprintf(stderr,
"Error: file contains no data.\n");
305 }
else if(tac.
tacNr>1) {
306 if(verbose>0) fprintf(stderr,
"Warning: file contains more than one curve.\n");
310 fprintf(stderr,
"Error: too few samples.\n");
315 fprintf(stderr,
"Error: data contains missing values.\n");
323 fprintf(stderr,
"Error: invalid data sample times.\n");
327 printf(
"xmin := %g\n", xmin);
328 printf(
"xmax := %g\n", xmax);
335 for(
int i=0; i<tac.
sampleNr; i++) tac.
w[i]=1.0;
339 for(
int i=0; i<tac.
sampleNr; i++) tac.
w[i]=1.0;
351 if(verbose>1) printf(
"preparing space for parameters\n");
362 iftPut(&par.
h,
"program", buf, 0, NULL);
368 for(
int i=0; i<par.
tacNr; i++) {
377 iftPut(&par.
h,
"datafile", pbrfile, 0, NULL);
391 if(verbose>1) printf(
"preparing for fitting\n");
401 fitdata.ymeas=tac.
c[0].
y;
404 fitdata.optcrit=optcrit;
405 if(verbose>10) fitdata.verbose=verbose-10;
else fitdata.verbose=0;
409 fprintf(stderr,
"Error: cannot allocate memory.\n");
418 for(
int i=0; i<par.
parNr; i++) {
422 for(
int i=0; i<par.
parNr; i++) {
436 fprintf(stderr,
"Error: %s\n",
errorMsg(status.
error)); fflush(stderr);
443 printf(
"measured and fitted TAC:\n");
445 printf(
"\t%g\t%g\t%g\n", tac.
x[i], tac.
c[0].
y[i], yfit[i]);
450 for(
int i=0; i<par.
parNr; i++) par.
r[0].
p[i]=nlo.
xfull[i];
462 if(verbose>1) printf(
" saving %s\n", parfile);
463 FILE *fp=fopen(parfile,
"w");
465 fprintf(stderr,
"Error: cannot open file for writing.\n"); fflush(stderr);
471 fprintf(stderr,
"Error: %s\n",
errorMsg(status.
error)); fflush(stderr);
474 if(verbose>0) printf(
"parameters saved in %s\n", parfile);
483 if(verbose>1) printf(
"plotting measured and fitted data\n");
491 fprintf(stderr,
"Error: %s\n",
errorMsg(status.
error)); fflush(stderr);
496 for(
int ci=0; ci<tac.
tacNr && ret==0; ci++)
499 fprintf(stderr,
"Error: %s\n",
errorMsg(status.
error)); fflush(stderr);
507 for(
int ci=0; ci<tac.
tacNr && ret==0; ci++) {
512 fprintf(stderr,
"Error: cannot calculate function values.\n"); fflush(stderr);
518 ret=
tacPlotFitSVG(&tac, &ftac,
"", nan(
""), nan(
""), nan(
""), nan(
""), svgfile, &status);
520 fprintf(stderr,
"Error: %s\n",
errorMsg(status.
error)); fflush(stderr);
525 if(verbose>0) printf(
"Measured and fitted data plotted in %s\n", svgfile);
540double func_pbr_src(
int parNr,
double *p,
void *fdata)
542 FITDATA *d=(FITDATA*)fdata;
544 if(d->verbose>0) {printf(
"%s()\n", __func__); fflush(stdout);}
545 if(parNr!=4)
return(nan(
""));
546 if(d->verbose>20) printf(
"p[]: %g %g %g %g\n", p[0], p[1], p[2], p[3]);
550 for(
unsigned int i=0; i<d->n; i++) {
552 if(isnan(d->ymeas[i]) || isnan(d->x[i]) || d->x[i]<0.0)
continue;
553 double et=exp(-p[2]*d->x[i]);
554 double rc=(1.0-p[3]/p[2])*d->x[i]*et + (p[3]/(p[2]*p[2]))*(1.0-et);
556 d->ysim[i]=1.0/((1.0-p[0])+p[0]*rc);
557 double v=d->ysim[i]-d->ymeas[i];
559 wss+=d->w[i]*fabs(v);
567double func_pbr_fm2(
int parNr,
double *p,
void *fdata)
569 FITDATA *d=(FITDATA*)fdata;
571 if(d->verbose>0) {printf(
"%s()\n", __func__); fflush(stdout);}
572 if(parNr!=7)
return(nan(
""));
573 if(d->verbose>20) printf(
"p[]: %g %g %g %g %g %g %g\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
576 double d0=p[1] - p[3]*p[4] - p[5]*p[6] + p[2]*(p[3]+p[5]);
577 if(d0<=0.0)
return(nan(
""));
581 for(
unsigned int i=0; i<d->n; i++) {
583 if(!isfinite(d->ymeas[i]) || !isfinite(d->x[i]) || d->x[i]<0.0)
continue;
584 double rc=(p[1]*d->x[i]-p[3]-p[5])*exp(-p[2]*d->x[i])
585 + p[3]*exp(-p[4]*d->x[i]) + p[5]*exp(-p[6]*d->x[i]);
586 d->ysim[i]=1.0/((1.0-p[0])+p[0]*rc);
587 double v=d->ysim[i]-d->ymeas[i];
589 wss+=d->w[i]*fabs(v);
597double func_pbr_rf(
int parNr,
double *p,
void *fdata)
599 FITDATA *d=(FITDATA*)fdata;
601 if(d->verbose>0) {printf(
"%s()\n", __func__); fflush(stdout);}
602 if(parNr!=7)
return(nan(
""));
603 if(d->verbose>20) printf(
"p[]: %g %g %g %g %g %g %g\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
607 for(
unsigned int i=0; i<d->n; i++) {
609 if(isnan(d->ymeas[i]) || isnan(d->x[i]) || d->x[i]<0.0)
continue;
610 double a = p[1]*d->x[i] + p[3]*d->x[i]*d->x[i] + p[5]*d->x[i]*d->x[i]*d->x[i];
611 double b = 1.0 + p[2]*d->x[i] + p[4]*d->x[i]*d->x[i] + p[6]*d->x[i]*d->x[i]*d->x[i];
612 d->ysim[i]=1.0/((1.0-p[0])+p[0]*(a/b));
613 double v=d->ysim[i]-d->ymeas[i];
if(!isfinite(v))
return(nan(
""));
615 wss+=d->w[i]*fabs(v);
623double func_pbr_hill(
int parNr,
double *p,
void *fdata)
625 FITDATA *d=(FITDATA*)fdata;
627 if(d->verbose>0) {printf(
"%s()\n", __func__); fflush(stdout);}
628 if(parNr!=4)
return(nan(
""));
629 if(d->verbose>20) printf(
"p[]: %g %g %g %g\n", p[0], p[1], p[2], p[3]);
633 for(
unsigned int i=0; i<d->n; i++) {
635 if(isnan(d->ymeas[i]) || isnan(d->x[i]) || d->x[i]<0.0)
continue;
636 double rc=p[1]*pow(d->x[i], p[2])/(p[3]+pow(d->x[i], p[2]));
637 d->ysim[i]=1.0/((1.0-p[0])+p[0]*rc);
638 double v=d->ysim[i]-d->ymeas[i];
if(!isfinite(v))
return(nan(
""));
640 wss+=d->w[i]*fabs(v);
char * ctime_r_int(const time_t *t, char *buf)
Convert calendar time t into a null-terminated string of the form YYYY-MM-DD hh:mm:ss,...
int atofCheck(const char *s, double *v)
int fileExist(const char *filename)
int mfEvalY(const char *fid, const int parNr, const double *p, const int sampleNr, const double *x, double *y, const int verbose)
unsigned int drandSeed(short int seed)
Make and optionally set the seed for rand(), drand, drandRange, and drandGaussian().
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
int iftFindKey(IFT *ift, const char *key, int start_index)
unsigned int simSamples(double initStep, double maxStep, double endTime, int mode, double *x)
char * modelCode(const unsigned int i)
char * modelDesc(const unsigned int i)
unsigned int modelParNr(const unsigned int code)
unsigned int modelCodeIndex(const char *s)
void nloptInit(NLOPT *nlo)
int nloptAllocate(NLOPT *nlo, unsigned int parNr)
void nloptFree(NLOPT *nlo)
void nloptWrite(NLOPT *d, FILE *fp)
char * optcritCode(optimality_criterion id)
optimality_criterion optcritId(const char *s)
int parAllocate(PAR *par, int parNr, int tacNr)
char * parFormattxt(parformat c)
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
int parReadLimits(PAR *par, const char *fname, const int verbose)
void parListLimits(PAR *par, FILE *fp)
int parFormatFromExtension(const char *s)
int parWriteLimits(PAR *par, const char *fname, const int verbose)
int parAllocateWithTAC(PAR *par, TAC *tac, int parNr, TPCSTATUS *status)
Allocate PAR based on data in TAC.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
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)
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)
double(* _fun)(int, double *, void *)
IFT h
Optional (but often useful) header information.
char name[MAX_PARNAME_LEN+1]
IFT h
Optional (but often useful) header information.
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
int tacCopyTacchdr(TACC *d1, TACC *d2)
int tacCopyHdr(TAC *tac1, TAC *tac2)
Copy TAC header data from tac1 to tac2.
int tacPlotFitSVG(TAC *tac1, TAC *tac2, const char *main_title, const double x1, const double x2, const double y1, const double y2, const char *fname, TPCSTATUS *status)
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
char * tacFormattxt(tacformat c)
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
int tacSortByTime(TAC *d, TPCSTATUS *status)
int tacIsWeighted(TAC *tac)
unsigned int tacWSampleNr(TAC *tac)
int tacWByFreq(TAC *tac, isotope isot, TPCSTATUS *status)
int tacGetSampleInterval(TAC *d, double ilimit, double *minfdur, double *maxfdur)
Get the shortest and longest sampling intervals or frame lengths in TAC structure.
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
int nloptIATGO(NLOPT *nlo, const int doLocal, unsigned int maxIterNr, double neighFract, TPCSTATUS *status)
int nloptITGO1(NLOPT *nlo, const int doLocal, unsigned int tgoNr, unsigned int sampleNr, unsigned int neighNr, TPCSTATUS *status)
Header file for libtpccm.
Header file for library libtpcextensions.
weights
Is data weighted, or are weight factors available with data?
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
char * unitName(int unit_code)
Header file for libtpcfileutil.
Header file for library libtpcift.
@ ISOTOPE_UNKNOWN
Unknown.
Header file for libtpcli.
Header file for libtpclinopt.
Header file for libtpcmodels.
optimality_criterion
Optimality Criterion for statistical optimizations.
@ OPTCRIT_OLS
Ordinary Least Squares (sum-of-squares, SS).
@ OPTCRIT_LAD
Least Absolute Deviations (sum of absolute deviations, LAE, LAV, LAR).
@ OPTCRIT_UNKNOWN
Unknown optimality criterion.
Header file for library libtpcnlopt.
Header file for libtpcpar.
@ PAR_FORMAT_UNKNOWN
Unknown format.
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Header file for libtpcrand.
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Header file for libtpctacmod.