8#include "tpcclibConfig.h"
22int FIT2DAT_MAXNR=10000;
26double func841(
int parNr,
double *p,
void*);
27double func844(
int parNr,
double *p,
void*);
28double func2801(
int parNr,
double *p,
void*);
30double *x, *ymeas, *yfit, *w;
33double min1, min2, max1, max2;
34double (*func)(
int parNr,
double *p,
void*);
38static char *info[] = {
39 "Non-linear fitting of the Hill function (sigmoid function) to a (xi,yi)",
40 "curve data. Optionally, a background term B is added to the function:",
42 " f(x) = (A * x^n ) / ( x^n + K ) + B , where A>=0, K>0, n>0, B>=0 ",
44 "Function for estimating EC50 from sigmoidal dose-response curve is obtained",
45 "by rearranging and marking n=HillSlope, A=Top-Bottom, B=Bottom, and",
48 " f(x) = Bottom + (Top-Bottom)/(1 + (EC50/x)^HillSlope)",
50 "With HillSlope constrained to 1 (see options below) the function reduces to",
51 "unconstrained one site binding hyperbola, f(x)=Top*x/(EC50+x).",
53 "Usage: @P [Options] tacfile [fitfile]",
57 " EC50 is estimated by fitting sigmoidal dose-response curve function",
58 " when drug concentrations are on a linear scale (not on a log scale);",
59 " By default, parameter Top is fitted and Bottom is constrained to 0,",
60 " which can be changed with options (see below).",
61 " -w1 All weights are set to 1.0 (no weighting); by default, weights in",
62 " data file are used, if available.",
64 " Weight by sampling interval.",
66 " Parameter n or HillSlope is constrained to the given value; set -n=1",
67 " to fit one site binding hyperbola.",
68 " -B Parameter B or Bottom is fitted; by default B=0",
70 " Parameter B or Bottom is constrained to the given value.",
72 " Parameter Top is constrained to the given value; currently this option",
73 " does not affect parameter A in the default function.",
75 " Error is returned if MRL check is not passed.",
77 " Fitted parameters are also written in result file format (3).",
79 " Fitted and measured TACs are plotted in specified SVG file.",
81 " Fitted TACs are written in DFT format.",
84 "TAC file must contain at least 2 columns, sample times (or concentrations)",
85 "and measurement values (or receptor occupancies).",
86 "Weights can be specified as usual if data is in DFT format (1).",
88 "Program writes the fit start and end times, nr of points, WSS,",
89 "and parameters of the fitted function to the fit file (2).",
92 "1. https://www.turkupetcentre.net/analysis/doc/format_dft.html",
93 "2. https://www.turkupetcentre.net/analysis/doc/format_fit.html",
94 "3. https://www.turkupetcentre.net/analysis/doc/format_res.html",
96 "See also: fit_hiad, fit_ppf, fit_exp, fit_ratf, fit_bpr, fit2dat, tacinv",
98 "Keywords: curve fitting, Hill function, sigmoid, EC50, dose-response curve",
117int main(
int argc,
char **argv)
119 int ai, help=0, version=0, verbose=1;
120 int fi, pi, ri, type=841, m, n, ret;
121 int is_n_fixed=0, is_b_fixed=1, is_a_fixed=0;
123 double fixed_n=1.0, fixed_b=0.0, fixed_a=100.0;
125 char datfile[FILENAME_MAX], fitfile[FILENAME_MAX], outfile[FILENAME_MAX],
126 svgfile[FILENAME_MAX], resfile[FILENAME_MAX], *cptr, temp[512];
131 double a, tstart, tstop, miny, maxy;
132 int tgo_nr, iter_nr, neigh_nr;
138 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
139 datfile[0]=fitfile[0]=outfile[0]=svgfile[0]=resfile[0]=(char)0;
143 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
144 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
146 if(strcasecmp(cptr,
"W1")==0) {
148 }
else if(strcasecmp(cptr,
"WF")==0) {
150 }
else if(strncasecmp(cptr,
"N=", 2)==0) {
151 cptr+=2;
if(strlen(cptr)>0) {
152 is_n_fixed=1; fixed_n=
atof_dpi(cptr);
153 if(fixed_n>0.0)
continue;
155 }
else if(strncasecmp(cptr,
"A=", 2)==0) {
156 cptr+=2;
if(strlen(cptr)>0) {
157 is_a_fixed=1; fixed_a=
atof_dpi(cptr);
158 if(fixed_a>0.0)
continue;
160 }
else if(strncasecmp(cptr,
"Top=", 4)==0) {
161 cptr+=4;
if(strlen(cptr)>0) {
162 is_a_fixed=1; fixed_a=
atof_dpi(cptr);
163 if(fixed_a>0.0)
continue;
165 }
else if(strncasecmp(cptr,
"B=", 2)==0) {
166 cptr+=2;
if(strlen(cptr)>0) {
167 is_b_fixed=1; fixed_b=
atof_dpi(cptr);
171 }
else if(strncasecmp(cptr,
"BOTTOM=", 7)==0) {
172 cptr+=7;
if(strlen(cptr)>0) {
173 is_b_fixed=1; fixed_b=
atof_dpi(cptr); parNr=4;
176 }
else if(strcasecmp(cptr,
"B")==0) {
177 is_b_fixed=0; parNr=4;
179 }
else if(strcasecmp(cptr,
"BOTTOM")==0) {
180 is_b_fixed=0; parNr=4;
182 }
else if(strcasecmp(cptr,
"EC50")==0) {
185 }
else if(strcasecmp(cptr,
"MRL")==0) {
186 MRL_check=1;
continue;
187 }
else if(strncasecmp(cptr,
"SVG=", 4)==0 && strlen(cptr)>4) {
188 strcpy(svgfile, cptr+4);
continue;
189 }
else if(strncasecmp(cptr,
"FIT=", 4)==0 && strlen(cptr)>4) {
190 strcpy(outfile, cptr+4);
continue;
191 }
else if(strncasecmp(cptr,
"RES=", 4)==0 && strlen(cptr)>4) {
192 strcpy(resfile, cptr+4);
continue;
194 fprintf(stderr,
"Error: invalid option '%s'\n", argv[ai]);
199 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
204 for(; ai<argc; ai++) {
205 if(!datfile[0]) {strcpy(datfile, argv[ai]);
continue;}
206 else if(!fitfile[0]) {strcpy(fitfile, argv[ai]);
continue;}
207 fprintf(stderr,
"Error: invalid argument '%s'\n", argv[ai]);
210 if(!fitfile[0]) strcpy(fitfile,
"stdout");
211 if(type==841 && parNr==4) type=844;
212 if(type==841) func=func841;
213 else if(type==844) func=func844;
218 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
221 if(is_a_fixed && type!=2801) {
222 fprintf(stderr,
"Error: option -a can not be used without option -EC50.\n");
225 if(is_a_fixed && is_b_fixed && fixed_a<=fixed_b) {
226 fprintf(stderr,
"Error: invalid constraints for Top and Bottom.\n");
232 printf(
"datfile := %s\n", datfile);
233 printf(
"fitfile := %s\n", fitfile);
234 printf(
"resfile := %s\n", resfile);
235 printf(
"outfile := %s\n", outfile);
236 printf(
"svgfile := %s\n", svgfile);
237 if(is_a_fixed) printf(
"fixed_a := %g\n", fixed_a);
238 if(is_b_fixed) printf(
"fixed_b := %g\n", fixed_b);
239 if(is_n_fixed) printf(
"fixed_n := %g\n", fixed_n);
240 printf(
"type := %d\n", type);
241 printf(
"weights := %d\n", weights);
242 printf(
"MRL_check := %d\n", MRL_check);
251 if(verbose>1) printf(
"reading %s\n", datfile);
253 fprintf(stderr,
"Error in reading '%s': %s\n", datfile,
dfterrmsg);
263 ret=
dftMinMax(&dft, &tstart, &tstop, &miny, &maxy);
265 fprintf(stderr,
"Error: invalid contents in %s\n", datfile);
268 if(tstop<=0.0 || maxy<=0.0) {
269 fprintf(stderr,
"Error: invalid contents in %s\n", datfile);
272 if(tstart<0.0) fprintf(stderr,
"Warning: negative x value(s).\n");
273 if(miny<0.0) fprintf(stderr,
"Warning: negative y value(s).\n");
279 }
else if(weights==1) {
281 }
else if(weights==2) {
290 if(verbose>1) printf(
"allocating memory for fits.\n");
293 fprintf(stderr,
"Error: cannot allocate space for fit results (%d).\n", ret);
298 strncpy(fit.
datafile, datfile, FILENAME_MAX);
301 for(ri=0; ri<dft.
voiNr; ri++) {
311 if(verbose>1) {printf(
"fitting\n"); fflush(stdout);}
312 for(ri=0; ri<dft.
voiNr; ri++) {
313 if(verbose>0 && dft.
voiNr>1) printf(
"%s\n", dft.
voi[ri].
name);
316 for(fi=0; fi<dft.
frameNr; fi++)
317 if(isnan(dft.
voi[ri].
y[fi])) dft.
voi[ri].
y3[fi]=0.0;
318 else dft.
voi[ri].
y3[fi]=dft.
w[fi];
323 printf(
"data_weights[%d] := %g", ri+1, dft.
w[0]);
324 for(fi=1; fi<dft.
frameNr; fi++) printf(
", %g", w[fi]);
329 fit.
voi[ri].
wss=3.402823e+38;
333 n=dataNr/3;
if(n<2) n=2;
334 fi=0;
while(isnan(dft.
voi[ri].
y[fi])) fi++;
335 min1=max1=dft.
voi[ri].
y[fi];
336 for(fi=0; fi<n; fi++)
if(!isnan(dft.
voi[ri].
y[fi])) {
337 if(min1>dft.
voi[ri].
y[fi]) min1=dft.
voi[ri].
y[fi];
338 if(max1<dft.
voi[ri].
y[fi]) max1=dft.
voi[ri].
y[fi];
340 fi=dataNr-1;
while(isnan(dft.
voi[ri].
y[fi])) fi--;
341 min2=max2=dft.
voi[ri].
y[fi];
342 for(fi=dataNr-n; fi<dataNr; fi++)
if(!isnan(dft.
voi[ri].
y[fi])) {
343 if(min2>dft.
voi[ri].
y[fi]) min2=dft.
voi[ri].
y[fi];
344 if(max2<dft.
voi[ri].
y[fi]) max2=dft.
voi[ri].
y[fi];
346 if(verbose>3) printf(
"min1 := %g\nmax1 := %g\nmin2 := %g\nmax2 := %g\n",
347 min1, max1, min2, max2);
350 if(type==841 || type==844) {
351 pmin[0]=(min2>1.0E-08)?min2:1.0E-08;
352 pmax[0]=(10.0*max2>pmin[0])?10.0*max2:pmin[0];
354 pmin[1]=1.0E-08; pmax[1]=20.0;
356 pmin[1]=pmax[1]=fixed_n;
358 pmin[2]=1.0E-08; pmax[2]=1.0E20;
359 if(is_n_fixed!=0 && fixed_n==1.0) pmax[2]=4.0*dft.
x[dataNr-1];
362 pmin[3]=0.0; pmax[3]=0.5*(max1+max2);
368 pmin[3]=pmax[3]=fixed_b; pmin[0]-=pmax[3]; pmax[0]-=pmin[3];
370 if(pmin[0]<0.0) pmin[0]=0.0;
373 pmin[2]=log10(pmin[2]);
374 pmax[2]=log10(pmax[2]);
378 pmin[0]=pmax[0]=fixed_a;
381 pmin[0]=(a>1.0E-10)?a:1.0E-10;
386 pmin[1]=pmax[1]=fixed_b;
388 pmin[1]=0.0; pmax[1]=0.5*(max1+max2);
391 pmin[2]=1.0E-08; pmax[2]=4.0*tstop;
394 pmin[3]=pmax[3]=fixed_n;
396 pmin[3]=1.0E-08; pmax[3]=20.0;
400 fflush(stdout); printf(
"Constraints for the fit:\n");
401 for(pi=0; pi<parNr; pi++)
402 printf(
" %g - %g\n", pmin[pi], pmax[pi]);
408 for(pi=m=0; pi<parNr; pi++)
if(pmin[pi]<pmax[pi]) m++;
411 printf(
"Comparison of nr of samples and params to fit: %d / %d\n", n, m);
413 fprintf(stderr,
"Error: too few samples for fitting in %s\n", datfile);
414 if(verbose>0) printf(
"n := %d\nm := %d\n", n, m);
419 if(verbose>2) printf(
"fitting\n");
420 if(type==841) {iter_nr=3; tgo_nr=1000; neigh_nr=15; }
421 else {iter_nr=3; tgo_nr=2000; neigh_nr=20; }
424 ret=
tgo(pmin, pmax, func, NULL, parNr, neigh_nr, &fit.
voi[ri].
wss,
425 fit.
voi[ri].
p, tgo_nr, iter_nr, verbose-5);
427 fprintf(stderr,
"Error %d in TGO.\n", ret);
434 if(ret!=0 && verbose>0) {
435 fprintf(stderr,
"Warning: fit collided with the limits.\n");
443 func(parNr, fit.
voi[ri].
p, NULL);
445 printf(
" Measured Fitted Weight\n");
446 for(fi=0; fi<dataNr; fi++)
447 if(!isnan(ymeas[fi]))
448 printf(
" %2d: %9.2e %9.2e %9.2e %7.1e\n",
449 fi+1, x[fi], ymeas[fi], yfit[fi], w[fi]);
451 printf(
" %2d: %9.2e %-9.9s %9.2e %7.1e\n", fi+1, x[fi],
452 ".", yfit[fi], w[fi]);
453 printf(
" fitted parameters:");
454 for(pi=0; pi<parNr; pi++) printf(
" %g", fit.
voi[ri].
p[pi]);
459 if(verbose>1) {printf(
"Checking the MRL.\n"); fflush(stdout);}
461 if(m>3 && m>dataNr/3) {
463 fprintf(stderr,
"Error: bad fit.\n");
464 fprintf(stderr,
"MRL := %d / %d\n", m, dataNr);
470 if(m>2 && m>dataNr/4) {
471 fprintf(stderr,
"Warning: bad fit.\n");
472 fprintf(stderr,
"MRL := %d / %d\n", m, dataNr);
474 }
else if(verbose>1) {
475 printf(
"MRL test passed.\n"); fflush(stdout);
477 fprintf(stderr,
"MRL := %d / %d\n", m, dataNr); fflush(stderr);}
481 if(type==841 || type==844) {
482 fit.
voi[ri].
p[2]=pow(10., fit.
voi[ri].
p[2]);
490 if(verbose>1) printf(
"saving results in %s\n", fitfile);
491 ret=
fitWrite(&fit, fitfile);
if(ret) {
492 fprintf(stderr,
"Error (%d) in writing '%s': %s\n", ret, fitfile,
fiterrmsg);
495 if(verbose>0) printf(
"Function parameters written in %s\n", fitfile);
499 if(verbose>1) printf(
"allocating memory for results.\n");
503 fprintf(stderr,
"Error in making results: %s\n", temp);
506 n=0; strcpy(res.
parname[n++],
"Function");
507 if(type==841 || type==844) {
516 strcpy(res.
parname[n++],
"Top");
517 strcpy(res.
parname[n++],
"Bottom");
518 strcpy(res.
parname[n++],
"EC50");
519 strcpy(res.
parname[n++],
"HillSlope");
521 strcpy(res.
parname[n++],
"WSS");
523 sprintf(res.
datarange,
"%g - %g", tstart, tstop);
526 if(verbose>1) printf(
"saving results in %s\n", resfile);
527 if(
resWrite(&res, resfile, verbose-3)) {
528 fprintf(stderr,
"Error in writing '%s': %s\n", resfile,
reserrmsg);
532 if(verbose>1) printf(
"Function parameters written in %s\n", resfile);
540 if(verbose>1) printf(
"creating SVG plot\n");
542 char tmp[FILENAME_MAX];
545 printf(
"calculating fitted curve at automatically generated sample times\n");
549 fprintf(stderr,
"Error %d in memory allocation for fitted curves.\n", ret);
554 for(ri=0, ret=0; ri<adft.
voiNr; ri++) {
555 for(fi=0; fi<adft.
frameNr; fi++) {
556 ret=
fitEval(&fit.
voi[ri], adft.
x[fi], &a);
if(ret!=0)
break;
557 adft.
voi[ri].
y[fi]=a;
562 fprintf(stderr,
"Error: cannot calculate fitted TAC for '%s'.\n", svgfile);
568 if(verbose>1) printf(
"writing %s\n", svgfile);
572 svgfile, verbose-10);
574 fprintf(stderr,
"Error (%d) in writing '%s'.\n", ret, svgfile);
578 if(verbose>0) printf(
"Plots written in %s\n", svgfile);
588 if(verbose>1) printf(
"saving fitted curves in %s\n", outfile);
590 for(ri=0, ret=0; ri<dft.
voiNr; ri++) {
591 for(fi=0; fi<dft.
frameNr; fi++) {
592 ret=
fitEval(&fit.
voi[ri], dft.
x[fi], &a);
if(ret!=0)
break;
598 fprintf(stderr,
"Error: cannot calculate fitted TACs for '%s'.\n", outfile);
603 sprintf(dft.
comments,
"# program := %s\n", temp);
606 fprintf(stderr,
"Error in writing '%s': %s\n", outfile,
dfterrmsg);
610 if(verbose>0) printf(
"Fitted TACs written in %s\n", outfile);
625double func841(
int parNr,
double *p,
void *fdata)
628 double a, b, c, q, v, wss;
636 a=pa[0]; b=pa[1]; c=pow(10., pa[2]);
638 for(i=0, wss=0.0; i<dataNr; i++) {
639 if(x[i]>=0.0) q=pow(x[i], b);
else q=1.0;
640 yfit[i]= a*q/(q+c);
if(isnan(ymeas[i]))
continue;
641 v=yfit[i]-ymeas[i]; wss+=w[i]*v*v;
649double func844(
int parNr,
double *p,
void *fdata)
652 double a, b, c, d, q, v, wss;
660 a=pa[0]; b=pa[1]; c=pow(10., pa[2]); d=pa[3];
662 for(i=0, wss=0.0; i<dataNr; i++) {
663 if(ymeas[i]<min1)
continue;
664 if(x[i]>=0.0) q=pow(x[i], b);
else q=1.0;
665 yfit[i]= a*q/(q+c) + d;
if(isnan(ymeas[i]))
continue;
666 v=yfit[i]-ymeas[i]; wss+=w[i]*v*v;
674double func2801(
int parNr,
double *p,
void *fdata)
677 double top, bottom, ec50, hillslope, v, wss;
685 top=pa[0]; bottom=pa[1]; ec50=pa[2]; hillslope=pa[3];
687 for(i=0, wss=0.0; i<dataNr; i++) {
688 if(x[i]<0.0) {yfit[i]=bottom;
continue;}
689 if(x[i]<1.0E-12) yfit[i]=bottom;
690 else yfit[i]=bottom+(top-bottom)/(1.0+pow(ec50/x[i],hillslope));
691 if(isnan(ymeas[i]))
continue;
692 v=yfit[i]-ymeas[i]; wss+=w[i]*v*v;
int modelCheckParameters(int par_nr, double *lower_p, double *upper_p, double *test_p, double *accept_p, double *penalty)
int modelCheckLimits(int par_nr, double *lower_p, double *upper_p, double *test_p)
double atof_dpi(char *str)
int dftSortByFrame(DFT *dft)
int dftMinMax(DFT *dft, double *minx, double *maxx, double *miny, double *maxy)
int dftRead(char *filename, DFT *data)
int dftWrite(DFT *data, char *filename)
int fitToResult(FIT *fit, RES *res, char *status)
int fit_allocate_with_dft(FIT *fit, DFT *dft)
int getActualSamplenr(DFT *dft, int ri)
Header file for libtpccurveio.
int fitEval(FitVOI *r, double x, double *y)
int fitWrite(FIT *fit, char *filename)
int resWrite(RES *res, char *filename, int verbose)
Header file for libtpcmisc.
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)
Header file for libtpcmodel.
int tgo(double *lowlim, double *uplim, double(*objf)(int, double *, void *), void *objfData, int dim, int neighNr, double *fmin, double *gmin, int samNr, int tgoNr, int verbose)
int mrl_between_tacs(double y1[], double y2[], int n)
Header file for libtpcmodext.
int dftWeightByFreq(DFT *dft)
int plot_fitrange_svg(DFT *dft1, DFT *dft2, char *main_title, double x1, double x2, double y1, double y2, char *fname, int verbose)
Header file for libtpcsvg.
char studynr[MAX_STUDYNR_LEN+1]
char comments[_DFT_COMMENT_LEN+1]
char datafile[FILENAME_MAX]
char studynr[MAX_STUDYNR_LEN+1]
char parname[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
char name[MAX_REGIONNAME_LEN+1]