TPCCLIB
Loading...
Searching...
No Matches
fit_ppf.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "tpcclibConfig.h"
10/*****************************************************************************/
11#include <stdio.h>
12#include <stdlib.h>
13#include <math.h>
14#include <string.h>
15#include <time.h>
16/*****************************************************************************/
17#include "libtpcmisc.h"
18#include "libtpcmodel.h"
19#include "libtpccurveio.h"
20#include "libtpcsvg.h"
21#include "libtpcmodext.h"
22/*****************************************************************************/
23
24/*****************************************************************************/
25#define MAX_FUNC_NR 7
26#define MAX_METAB_NR 3
27enum {MODEL_UNKNOWN, MODEL_PF, MODEL_HILL, MODEL_GCDF, MODEL_EP, MODEL_MPF, MODEL_MHILL};
28int model=MODEL_UNKNOWN;
29int func_par_nr[MAX_FUNC_NR]={0,5,5,5,6,5,5};
30int func_type[MAX_FUNC_NR]={0,MF_EMAYER_PAR,MF_EHILL_PAR,MF_PPFIGAM,MF_PF_MU,MF_PF3M_PAR,MF_HILL3M_PAR};
31double func_pf(int parNr, double *p, void*);
32double func_hill(int parNr, double *p, void*);
33double func_gcdf(int parNr, double *p, void*);
34double func_ep(int parNr, double *p, void*);
35double func_mpf(int parNr, double *p, void*);
36double func_mhill(int parNr, double *p, void*);
37double (*func_list[MAX_FUNC_NR])(int parNr, double *p, void*)=
38 {NULL,func_pf,func_hill,func_gcdf,func_ep,func_mpf,func_mhill};
39/*****************************************************************************/
40#define MAX_MINMEAS_NR 4
41enum {MINMEAS_UNKNOWN, MINMEAS_OLS, MINMEAS_LAD, MINMEAS_ODR};
42int min_meas=MINMEAS_UNKNOWN;
43/*****************************************************************************/
44double *x, *ymeas[1+MAX_METAB_NR], *yfit[1+MAX_METAB_NR], *w; /* Local */
45int origdataNr=0, fitdataNr=0, parNr=5, metabNr=0;
46double frwgt[1+MAX_METAB_NR];
47double pmin[MAX_PARAMETERS], pmax[MAX_PARAMETERS];
48double lastWSS=0.0;
49/*****************************************************************************/
50
51/*****************************************************************************/
52static char *info[] = {
53 "Fits an empirical function to plasma parent (unchanged) tracer",
54 "fraction curve (1), where the fractions are between 0 and 1.",
55 " ",
56 "Usage: @P [Options] fractionfile [fitfile]",
57 " ",
58 "Options:",
59 " -model=<PF | HILL | GCDF | EP | MPF | MHILL>",
60 " Select the function (see descriptions below); default is HILL.",
61 " Use MPF or MHILL to fit functions to 2-3 metabolite fraction curves",
62 " instead of parent fraction curve.",
63/* Currently in testing, therefore hidden.
64 " HILL2 can be used to save parameters for the 2nd Hill function",
65 " representation.",
66*/
67 " -min=<OLS|LAD|ODR>",
68 " Sum-of-squares (ordinal least squares, OLS) is minimized by default,",
69 " but optionally, sum of absolute deviations (LAD), or",
70 " sum-of-squares of Akaho distances (orthogonal distances, ODR) ",
71 " can be selected. ODR can be used only with PF and HILL.",
72 " -delaymin=<value>",
73 " Set the lower limit for delay parameter.",
74 " -mdelay=<separated | joint>",
75 " Delay parameter for each metabolite is fitted separately, or",
76 " all metabolites are assumed to share common delay time (default).",
77 " -fix0",
78 " Parent fraction at time zero is fixed to zero sample, if available.",
79 " -a=<value>, -b=<value>, -c=<value>, ...",
80 " Specified parameter is fixed to given (population mean) value.",
81 " Option -fix0 overrides other options when possible.",
82 " -WC",
83 " The last data column contains sample weights.",
84 " -W1",
85 " All weights are set to 1.0 (no weighting)",
86 " -WF",
87 " Less frequent samples are given more weight.",
88 " -WP=<weight>, -WM1=<weight>, -WM2=<weight>, -WM3=<weight>",
89 " Put additional or less weight to parent and/or metabolite fractions.",
90 " -ND",
91 " Some fractions are known to exceed 1, not divided by 100.",
92 " -MRL",
93 " Error is returned if MRL check is not passed.",
94 " -svg=<Filename>",
95 " Fitted and measured TACs are plotted in specified SVG file.",
96 " -stdoptions", // List standard options like --help, -v, etc
97 " ",
98 "Fraction datafile must contain at least two columns: sample times (min) and",
99 "fractions of parent tracer. Fractions of 1-3 metabolites can be given in",
100 "additional columns. Weights column can be given as specified in",
101 "DFT format (2) or with option -wc.",
102 "Program writes the fit start and end times, nr of points, WSS,",
103 "and parameters of the fitted function to the FIT file (3).",
104 " ",
105 "Available functions:",
106 "PF - extended power function (1,4,5)",
107 " f(x) = {D^(-1/C) + (A*(x-E))^B }^-C , when x>E,",
108 " f(x) = D , when x<=E ,",
109 " where 0<A<=1, B>1.5, C>0, 0<D<=1, 0<=E.",
110 " With option -d=1 this is essentially the same function as proposed in (4)",
111 " or with options -b=2 -d=1 -e=0 the same as suggested in (5).",
112 "HILL - Extended Hill type function (1,6)",
113 " f(x) = D - {(D-A)(x-E)^B}/{C+(x-E)^B} , when x>E,",
114 " f(x) = D , when x<=E ,",
115 " where 0<=A<=D, 1<=B, 0<C, 0<D<=1, 0<=E.",
116 " With options -d=1 -e=0 this is the traditional Hill type function (6)",
117 " f(x) = 1 - {(1-A)x^B}/(C+x^B)",
118 " where C>0<=A<=D, 1<=B, 0<C, 0<D<=1, 0<=E.",
119 "GCDF - Inverted Gamma CDF (7)",
120 " f(x) = A{1-B*gcdf(C(x-E),D)}, where 0<A<=1,0<=B<=1,C>0,D>0.",
121 "EP - Exponential/Power function based on Mu et al (8)",
122 " f(x) = B*(C*exp(-D*(x-A)^3/(E+(x-A)^2)) + (1-C)*exp(-F*(x-A))), when x>A,",
123 " f(x) = B , when x<=A ,",
124 "MPF - Extended power function is fitted to 1-3 metabolite fractions.",
125 "MHILL - Extended Hill type function is fitted to 1-3 metabolite fractions.",
126 " ",
127 "References:",
128 "1. Fitting the fractions of parent tracer in plasma.",
129 " https://www.turkupetcentre.net/petanalysis/input_parent_fitting.html",
130 "2. https://www.turkupetcentre.net/petanalysis/format_tpc_dft.html",
131 "3. https://www.turkupetcentre.net/petanalysis/format_tpc_fit.html",
132 "4. Meyer PT, et al. J Cereb Blood Flow Metab. 2004;24(3):323-333.",
133 " https://doi.org/10.1097/01.wcb.0000110531.48786.9d",
134 "5. Watabe H, et al. J Cereb Blood Flow Metab 2000;20:899-909.",
135 " https://doi.org/10.1097/00004647-200006000-00002",
136 "6. Wu S, et al. J Nucl Med 2007;48:926-931.",
137 " https://doi.org/10.2967/jnumed.106.038075",
138 "7. Naganawa M, et al. J Cereb Blood Flow Metab. 2014;34:1818-1825.",
139 " https://doi.org/10.1038/jcbfm.2014.150",
140 "8. Mu L et al. EJNMMI Res. 2020;10:114.",
141 " https://doi.org/10.1186/s13550-020-00700-7",
142 " ",
143 "See also: fit2dat, metabcor, avgfract, fitedit, fit_fexp, fith2met, tac2svg",
144 " ",
145 "Keywords: input, plasma, modelling, simulation, metabolite correction",
146 0};
147/*****************************************************************************/
148
149/*****************************************************************************/
150/* Turn on the globbing of the command line, since it is disabled by default in
151 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
152 In Unix&Linux wildcard command line processing is enabled by default. */
153/*
154#undef _CRT_glob
155#define _CRT_glob -1
156*/
157int _dowildcard = -1;
158/*****************************************************************************/
159
160/*****************************************************************************/
164int main(int argc, char **argv)
165{
166 int ai, help=0, version=0, verbose=1;
167 int fi, pi, ri, type=0, ret, m, n;
168 int noDivide=0, last_col_is_weight=0;
169 int MRL_check=0; // 0=off, 1=on
170 double fixed_p[MAX_PARAMETERS]; // values <0 mean not fixed
171 double min_delay=-1.0; // <0 not set
172 int fixed0=0; // fix fraction at time zero to measured value at time zero, if available
173 int delay_par_index=0; // Which parameter represents delay time
174 int iscale_par_index=0; // Which parameter represents scale
175 int ffile_type=1; // Parameters are saved in 1=usual or 2=Hill#2
176 // format; fitting is still the same.
177 int mdelay_joint=1; // 0=separated, 1=joint
178 char *cptr, dfile[FILENAME_MAX], ffile[FILENAME_MAX],
179 svgfile[FILENAME_MAX];
180 DFT dft;
181 FIT fit;
182 double a, b, tstart, tstop, maxfract, aic;
183 // Weights: 0=left as it is in datafile, 1=set to 1, 2=sampling frequency
184 int weighting=0;
185
186#ifdef MINGW
187 // Use Unix/Linux default of two-digit exponents in MinGW on Windows
188 _set_output_format(_TWO_DIGIT_EXPONENT);
189#endif
190
191
192 /* Initially, assume that none of parameters is fixed */
193 for(pi=0; pi<MAX_PARAMETERS; pi++) fixed_p[pi]=-1;
194 /* By default, no additional weight for any of fractions */
195 for(m=0; m<=MAX_METAB_NR; m++) frwgt[m]=1.0;
196
197
198 /*
199 * Get arguments
200 */
201 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
202 dftInit(&dft); fitInit(&fit);
203 dfile[0]=ffile[0]=svgfile[0]=(char)0;
204 /* Options */
205 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
206 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
207 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
208 if(strncasecmp(cptr, "MODEL=", 6)==0) {
209 cptr+=6;
210 if(strncasecmp(cptr, "PF", 1)==0) {model=MODEL_PF; continue;}
211 if(strcasecmp(cptr, "HILL2")==0) {model=MODEL_HILL; ffile_type=2; continue;}
212 if(strncasecmp(cptr, "HILL", 1)==0) {model=MODEL_HILL; continue;}
213 if(strncasecmp(cptr, "GCDF", 1)==0) {model=MODEL_GCDF; continue;}
214 if(strcasecmp(cptr, "EP")==0) {model=MODEL_EP; continue;}
215 if(strncasecmp(cptr, "MPF", 3)==0) {model=MODEL_MPF; continue;}
216 if(strncasecmp(cptr, "MHILL", 3)==0) {model=MODEL_MHILL; continue;}
217 fprintf(stderr, "Error: invalid model selection.\n"); return(1);
218 } else if(strcasecmp(cptr, "ND")==0) {
219 noDivide=1; continue;
220 } else if(strcasecmp(cptr, "W1")==0) {
221 weighting=1; continue;
222 } else if(strcasecmp(cptr, "WF")==0) {
223 weighting=2; continue;
224 } else if(strcasecmp(cptr, "WC")==0) {
225 last_col_is_weight=1; continue;
226 } else if(strncasecmp(cptr, "WP=", 3)==0) {
227 frwgt[0]=atof_dpi(cptr+3); if(frwgt[0]>=0.0) continue;
228 } else if(strncasecmp(cptr, "WM1=", 4)==0) {
229 frwgt[1]=atof_dpi(cptr+4); if(frwgt[1]>=0.0) continue;
230 } else if(strncasecmp(cptr, "WM2=", 4)==0) {
231 frwgt[2]=atof_dpi(cptr+4); if(frwgt[2]>=0.0) continue;
232 } else if(strncasecmp(cptr, "WM3=", 4)==0) {
233 frwgt[3]=atof_dpi(cptr+4); if(frwgt[3]>=0.0) continue;
234 } else if(strncasecmp(cptr, "A=", 2)==0) {
235 fixed_p[0]=atof_dpi(cptr+2); if(fixed_p[0]>=0.0) continue;
236 } else if(strncasecmp(cptr, "B=", 2)==0) {
237 fixed_p[1]=atof_dpi(cptr+2); if(fixed_p[1]>=0.0) continue;
238 } else if(strncasecmp(cptr, "C=", 2)==0) {
239 fixed_p[2]=atof_dpi(cptr+2); if(fixed_p[2]>=0.0) continue;
240 } else if(strncasecmp(cptr, "D=", 2)==0) {
241 fixed_p[3]=atof_dpi(cptr+2); if(fixed_p[3]>=0.0) continue;
242 } else if(strncasecmp(cptr, "E=", 2)==0) {
243 fixed_p[4]=atof_dpi(cptr+2); if(fixed_p[4]>=0.0) continue;
244 } else if(strncasecmp(cptr, "F=", 2)==0) {
245 fixed_p[5]=atof_dpi(cptr+2); if(fixed_p[5]>=0.0) continue;
246 } else if(strncasecmp(cptr, "DELAYMIN=", 9)==0) {
247 min_delay=atof_dpi(cptr+9); if(min_delay>=0.0) continue;
248 } else if(strcasecmp(cptr, "FIX0")==0 || strcasecmp(cptr, "FIXED0")==0) {
249 fixed0=1; continue;
250 } else if(strcasecmp(cptr, "MRL")==0) {
251 MRL_check=1; continue;
252 } else if(strncasecmp(cptr, "MDELAY=", 7)==0) {
253 cptr+=7;
254 if(strncasecmp(cptr, "JOINT", 1)==0) {mdelay_joint=1; continue;}
255 if(strncasecmp(cptr, "SEPARATED", 1)==0) {mdelay_joint=0; continue;}
256 fprintf(stderr, "Error: invalid mdelay selection.\n"); return(1);
257 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
258 strlcpy(svgfile, cptr+4, FILENAME_MAX); continue;
259 } else if(strncasecmp(cptr, "MIN=", 4)==0) {
260 cptr+=4;
261 if(strcasecmp(cptr, "OLS")==0 || strcasecmp(cptr, "SS")==0 || strcasecmp(cptr, "WSS")==0) {
262 min_meas=MINMEAS_OLS; continue;}
263 if(strcasecmp(cptr, "LAD")==0 || strcasecmp(cptr, "ABS")==0 || strcasecmp(cptr, "WABS")==0) {
264 min_meas=MINMEAS_LAD; continue;}
265 if(strcasecmp(cptr, "ODR")==0) {
266 min_meas=MINMEAS_ODR; continue;}
267 fprintf(stderr, "Error: invalid minimization measure.\n"); return(1);
268 }
269 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
270 return(1);
271 } else break;
272
273 /* Print help or version? */
274 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
275 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
276 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
277
278 /* Process other arguments, starting from the first non-option */
279 if(ai<argc) strlcpy(dfile, argv[ai++], FILENAME_MAX);
280 if(ai<argc) strlcpy(ffile, argv[ai++], FILENAME_MAX);
281 if(ai<argc) {fprintf(stderr, "Error: too many arguments: '%s'.\n", argv[ai]); return(1);}
282
283 /* Is something missing? */
284 if(!dfile[0]) {
285 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
286 return(1);
287 }
288 /* Apply default model, if not selected by user */
289 if(model==MODEL_UNKNOWN) model=MODEL_HILL;
290 if(min_meas==MINMEAS_UNKNOWN) min_meas=MINMEAS_OLS;
291 /* Check compatibility of options */
292 if(min_meas==MINMEAS_ODR) {
293 if(model!=MODEL_HILL && model!=MODEL_PF) {
294 fprintf(stderr, "Warning: ODR is not available with selected model.\n");
295 fprintf(stderr, "Note: using OLS instead of ODR.\n");
296 min_meas=MINMEAS_OLS;
297 }
298 }
299 /* Set function specific parameters */
300 type=func_type[model];
301 if(model==MODEL_HILL && ffile_type==2) type=MF_EHILL2_PAR;
302 parNr=func_par_nr[model];
303 delay_par_index=parNr-1;
304 if(model!=MODEL_GCDF) iscale_par_index=parNr-2;
305 if(model==MODEL_EP) {delay_par_index=0; iscale_par_index=1;}
306 for(pi=0, n=0; pi<parNr; pi++) if(fixed_p[pi]>=0.0) n++;
307 if((parNr-n)<1) {
308 fprintf(stderr, "Error: too many parameters were fixed.\n");
309 return(1);
310 }
311 if(fixed_p[delay_par_index]>=0.0 && mdelay_joint==0)
312 fprintf(stderr, "Warning: option -mdelay is not effective with option -e\n");
313 if(!ffile[0]) strcpy(ffile, "stdout");
314
315
316 /* In verbose mode print arguments and options */
317 if(verbose>1) {
318 printf("dfile := %s\n", dfile);
319 printf("ffile := %s\n", ffile);
320 printf("svgfile := %s\n", svgfile);
321 printf("noDivide := %d\n", noDivide);
322 printf("weighting := %d\n", weighting);
323 printf("mdelay_joint := %d\n", mdelay_joint);
324 printf("last_col_is_weight := %d\n", last_col_is_weight);
325 printf("model := %d\n", model);
326 printf("type := %d\n", type);
327 printf("parNr := %d\n", parNr);
328 printf("min_meas := %d\n", min_meas);
329 for(pi=0; pi<parNr; pi++) if(fixed_p[pi]>=0.0) printf("fixed_p[%d] := %g\n", pi, fixed_p[pi]);
330 if(min_delay>=0.0) printf("min_delay := %g\n", min_delay);
331 printf("fixed0 := %d\n", fixed0);
332 printf("MRL_check := %d\n", MRL_check);
333 for(m=0; m<=MAX_METAB_NR; m++) printf("frwgt[%d] := %g\n", m, frwgt[m]);
334 fflush(stdout);
335 }
336 if(verbose>2) CSV_TEST=verbose-2; else CSV_TEST=0;
337
338 /*
339 * Read data
340 */
341 if(verbose>1) printf("reading %s\n", dfile);
342 if(dftRead(dfile, &dft)) {
343 fprintf(stderr, "Error in reading '%s': %s\n", dfile, dfterrmsg);
344 return(2);
345 }
346 origdataNr=dft.frameNr;
347
348 /* If required, set the last column as weights */
349 if(last_col_is_weight!=0) {
350 if(verbose>1) printf("reading weights from the last column.\n");
351 if(dft.voiNr<2) {
352 fprintf(stderr, "Error: no column for weights in %s\n", dfile);
353 dftEmpty(&dft); return(2);
354 }
355 for(fi=0; fi<dft.frameNr; fi++) {
356 dft.w[fi]=dft.voi[dft.voiNr-1].y[fi];
357 if(isnan(dft.w[fi])) dft.w[fi]=0.0;
358 }
359 dft.isweight=1; dft.voiNr--;
360 }
361
362 if(verbose>1) {
363 if(strlen(dft.studynr)>0 && strcmp(dft.studynr, ".")!=0)
364 printf("study_number := %s\n", dft.studynr);
365 printf("tacNr := %d\n", dft.voiNr);
366 }
367
368 /* Sort the samples by time in case data is catenated from several curves */
369 (void)dftSortByFrame(&dft);
370
371 /* Make sure that times are in minutes */
372 if(dft.timeunit==TUNIT_SEC) {
373 if(verbose>1) printf("Sample times are converted to min\n");
374 dftSec2min(&dft);
375 }
376 if(dft.timeunit==TUNIT_UNKNOWN) {
377 dft.timeunit=TUNIT_MIN;
378 }
379
380 /* Ignore extra columns, if parent fraction is fitted */
381 if(model==MODEL_PF || model==MODEL_HILL || model==MODEL_GCDF || model==MODEL_EP) {
382 if(dft.voiNr>1) {
383 fprintf(stderr, "Warning: extra columns in %s are ignored.\n", dfile);
384 dft.voiNr=1;
385 }
386 } else { /* Metabolite fraction(s) will be fitted */
387 if(dft.voiNr==1) {
388 if(verbose>1) printf("calculating metabolite fractions\n");
389 /* If no metabolite fractions were found, then add one */
390 ret=dftAddmem(&dft, 1); if(ret!=0) {
391 fprintf(stderr, "Error: cannot allocate memory for metabolite.\n");
392 dftEmpty(&dft); return(2);
393 }
394 dft.voiNr++;
395 for(fi=0; fi<dft.frameNr; fi++) dft.voi[1].y[fi]=1.0-dft.voi[0].y[fi];
396 } else if(dft.voiNr>(1+MAX_METAB_NR)) {
397 /* If too many metabolite fractions, then combine the last ones */
398 for(fi=0; fi<dft.frameNr; fi++) for(ri=1+MAX_METAB_NR; ri<dft.voiNr; ri++)
399 {
400 if(isnan(dft.voi[ri].y[fi])) continue;
401 if(isnan(dft.voi[MAX_METAB_NR].y[fi])) {
402 dft.voi[MAX_METAB_NR].y[fi]=dft.voi[ri].y[fi]; continue;}
403 dft.voi[MAX_METAB_NR].y[fi]+=dft.voi[ri].y[fi];
404 }
405 fprintf(stderr, "Warning: extra metabolite(s) are summed in Metab3.\n");
406 dft.voiNr=1+MAX_METAB_NR;
407 }
408 /* Set the number of metabolite fraction curves to be fitted */
409 metabNr=dft.voiNr-1; if(metabNr>MAX_METAB_NR) metabNr=MAX_METAB_NR;
410 if(verbose>1) printf("metabNr := %d\n", metabNr);
411 /* Set only later the fitted parameter nr based on the nr of metabolites */
412 }
413 /* Set the names for curves */
414 if(strlen(dft.voi[0].name)==0) {
415 strcpy(dft.voi[0].name, "Parent");
416 strcpy(dft.voi[0].voiname, dft.voi[0].name);
417 }
418 for(ri=1; ri<dft.voiNr; ri++) if(strlen(dft.voi[ri].name)==0) {
419 strcpy(dft.voi[ri].name, "Metab1");
420 strcpy(dft.voi[ri].voiname, dft.voi[ri].name);
421 }
422 if(verbose>11) dftPrint(&dft);
423 /* Set the number of fitted samples here; sort the data first if necessary */
424 // not implemented, all data fitted
425 fitdataNr=origdataNr;
426 if(fitdataNr<2) { // More precise testing later
427 fprintf(stderr, "Error: too few samples for fitting in %s\n", dfile);
428 dftEmpty(&dft); return(2);
429 }
430 dft.frameNr=fitdataNr;
431
432 /* Get start and end times */
433 ret=dftMinMax(&dft, &tstart, &tstop, NULL, &maxfract);
434 if(ret!=0) {
435 fprintf(stderr, "Error: invalid contents in %s\n", dfile);
436 dftEmpty(&dft); return(2);
437 }
438 if(verbose>2) printf("max := %g\n", maxfract);
439 /* Check that x values are >=0 and that there is range in x values */
440 if(tstart<0.0 || !(tstop>tstart)) {
441 fprintf(stderr, "Error: invalid sample times.\n");
442 dftEmpty(&dft); return(2);
443 }
444 /* Check that y values are <=1 */
445 if(maxfract>100.0 || maxfract<0.001) {
446 fprintf(stderr, "Error: invalid fraction values.\n");
447 dftEmpty(&dft); return(2);
448 }
449 if(noDivide==0 && maxfract>1.0) {
450 fprintf(stderr, "Warning: converting percentages to fractions.\n");
451 for(fi=0; fi<origdataNr; fi++) for(ri=0; ri<dft.voiNr; ri++)
452 if(!isnan(dft.voi[ri].y[fi])) dft.voi[ri].y[fi]/=100.0;
453 /* make sure that units are not percentages any more */
454 dftUnitToDFT(&dft, CUNIT_UNITLESS);
455 }
456 if(verbose>9) dftPrint(&dft);
457
458 /* Check and set weights */
459 if(dft.isweight==0 || weighting==1) {
460 dft.isweight=1;
461 for(fi=0; fi<dft.frameNr; fi++) dft.w[fi]=1.0;
462 }
463 if(weighting==2) { // weighting by sample frequency
464 dftWeightByFreq(&dft); // must be sorted by time before this
465 }
466 /* Set sample weights to zero, if parent fraction is NaN */
467 for(fi=0; fi<dft.frameNr; fi++) if(isnan(dft.voi[0].y[fi])) dft.w[fi]=0;
468 if(verbose>1) {
469 printf("data_weights := %g", dft.w[0]);
470 for(fi=1; fi<dft.frameNr; fi++) printf(", %g", dft.w[fi]);
471 printf("\n");
472 }
473
474
475 /*
476 * Allocate memory for fits
477 */
478 if(verbose>1) printf("allocating memory for fits.\n");
479 ret=fit_allocate_with_dft(&fit, &dft);
480 if(ret) {
481 fprintf(stderr, "Error: cannot allocate space for fit results (%d).\n", ret);
482 dftEmpty(&dft); fitEmpty(&fit); return(4);
483 }
484 /* Set necessary information in fit data structure */
485 fit.voiNr=dft.voiNr;
486 strncpy(fit.datafile, dfile, FILENAME_MAX);
487 tpcProgramName(argv[0], 1, 1, fit.program, 256);
488 fit.time=time(NULL);
489 for(fi=n=0; fi<fitdataNr; fi++) if(dft.x[fi]>=0.0 && !isnan(dft.voi[0].y[fi])) n++;
490 for(ri=0; ri<fit.voiNr; ri++) {
491 fit.voi[ri].type=type;
492 fit.voi[ri].parNr=parNr;
493 if(model==MODEL_MPF || model==MODEL_MHILL) fit.voi[ri].parNr*=metabNr;
494 fit.voi[ri].start=tstart; fit.voi[ri].end=tstop;
495 fit.voi[ri].dataNr=n;
496 }
497 if(model==MODEL_MHILL) {
498 fit.voi[0].type=MF_HILL3M_PAR;
499 fit.voi[1].type=MF_HILL3M_M1;
500 if(metabNr>1) fit.voi[2].type=MF_HILL3M_M2;
501 if(metabNr>2) fit.voi[3].type=MF_HILL3M_M3;
502 } else if(model==MODEL_MPF) {
503 fit.voi[0].type=MF_PF3M_PAR;
504 fit.voi[1].type=MF_PF3M_M1;
505 if(metabNr>1) fit.voi[2].type=MF_PF3M_M2;
506 if(metabNr>2) fit.voi[3].type=MF_PF3M_M3;
507 }
508
509 /*
510 * Set parameter constraints
511 */
512 switch(model) {
513 case MODEL_PF:
514 case MODEL_MPF:
515 pmin[0]=1.0e-20; pmax[0]=1.0e+00;
516 pmin[1]=1.5; pmax[1]=5.0e+01;
517 pmin[2]=1.0e-20; pmax[2]=1.0e+00;
518 pmin[3]=1.0e-20; pmax[3]=1.0e+00;
519 break;
520 case MODEL_HILL:
521 case MODEL_MHILL:
522 pmin[0]=0.0; pmax[0]=1.0e+00;
523 pmin[1]=1.0; pmax[1]=1.5e+01;
524 pmin[2]=1.0e-06; pmax[2]=1.0e+05;
525 pmin[3]=1.0e-06; pmax[3]=1.0e+00;
526 break;
527 case MODEL_GCDF:
528 pmin[0]=0.0; pmax[0]=1.0e+00;
529 pmin[1]=0.1; pmax[1]=1.0e+00;
530 pmin[2]=1.0e-06; pmax[2]=1.0e+01;
531 pmin[3]=1.0e-06; pmax[3]=1.0e+02;
532 break;
533 case MODEL_EP:
534 pmin[0]=0.0; pmax[0]=1.0; // delay
535 pmin[1]=0.1; pmax[1]=1.0; // max
536 pmin[2]=0.001; pmax[2]=1.0;
537 pmin[3]=0.001; pmax[3]=1.0;
538 pmin[4]=1.0; pmax[4]=1.0e+03;
539 pmin[5]=1.0e-06; pmax[5]=0.2;
540 break;
541 }
542 /* Delay parameter limits; first the min */
543 if(min_delay>=0) {
544 if(min_delay>0.9*dft.x[fitdataNr-1]) min_delay=0.9*dft.x[fitdataNr-1];
545 pmin[delay_par_index]=min_delay;
546 } else {
547 if(fixed_p[iscale_par_index]==1.0) { // fraction starts from 1.0
548 a=0.0; // search last sample that is 1.0
549 for(fi=0; fi<fitdataNr; fi++) if(dft.voi[0].y[fi]>=1.0 && dft.x[fi]>a) a=dft.x[fi];
550 pmin[delay_par_index]=a;
551 } else { // here initial fraction can be <1
552 pmin[delay_par_index]=0.0;
553 }
554 }
555 /* then the max delay */
556 if(model==MODEL_PF || model==MODEL_HILL || model==MODEL_GCDF || model==MODEL_EP || mdelay_joint==1) {
557 /* parent fraction is fitted, or if metabolite fraction(s) are fitted, then
558 common delay time for all metabolites is assumed */
559 if(fixed_p[iscale_par_index]==1.0) {
560 // fractions start from 1.0/0.0
561 a=1000.0; // search first sample time which is lower than 1.0
562 for(fi=0; fi<fitdataNr; fi++) if(dft.voi[0].y[fi]<1.0 && dft.x[fi]<a) a=dft.x[fi];
563 pmax[delay_par_index]=a;
564 } else { // here initial fraction can be <1
565 // max delay is set to the first sample time after max value
566 for(fi=0, n=fitdataNr-1, a=0.0; fi<fitdataNr; fi++)
567 if(dft.voi[0].y[fi]>=a) {a=dft.voi[0].y[fi]; n=fi;}
568 if(n<fitdataNr-1) n++;
569 pmax[delay_par_index]=dft.x[n];
570 }
571 } else {
572 /* Metabolite fractions are fitted with separated delay times */
573 /* Find highest and lowest parent fraction sample times,
574 and set max delay time to the time where fraction has fallen to half
575 of the difference */
576 m=0; n=fitdataNr-1; a=dft.voi[0].y[m]; b=dft.voi[0].y[n];
577 for(fi=0; fi<fitdataNr; fi++) {
578 if(dft.voi[0].y[fi]>=a) {m=fi; a=dft.voi[0].y[m];}
579 if(dft.voi[0].y[fi]<b) {n=fi; b=dft.voi[0].y[n];}
580 }
581 if(verbose>2) {
582 printf("max parent fraction %g at %g\n", a, dft.x[m]);
583 printf("min parent fraction %g at %g\n", b, dft.x[n]);
584 }
585 a=0.5*(a-b);
586 for(fi=m; fi<=n; fi++) if(dft.voi[0].y[fi]<=a) break;
587 if(verbose>2) printf("parent fraction dropped to %g at %g\n", a, dft.x[fi]);
588 pmax[delay_par_index]=dft.x[fi];
589 }
590 if(min_delay>=0 && pmin[delay_par_index]==pmax[delay_par_index]) {
591 pmax[delay_par_index]=1.5*pmin[delay_par_index];
592 if(pmax[delay_par_index]>dft.x[fitdataNr-1]) pmax[delay_par_index]=dft.x[fitdataNr-1];
593 }
594 if(pmax[delay_par_index]<pmin[delay_par_index]) pmax[delay_par_index]=pmin[delay_par_index];
595 /* Fix to user-defined values, if available */
596 for(pi=0; pi<parNr; pi++) {if(fixed_p[pi]>=0.0) pmin[pi]=pmax[pi]=fixed_p[pi];}
597 if(fixed0 && fabs(tstart)<1.0E-08) {
598 /* There might be more than one zero samples, thus get the mean */
599 double y0=0.0; int n=0;
600 for(int i=0; i<fitdataNr; i++) if(fabs(dft.x[i])<1.0E-08) {y0+=dft.voi[0].y[i]; n++;}
601 if(n>1) y0/=(double)n;
602 if(!(y0>0.0)) {
603 fprintf(stderr, "Warning: initial fraction is not fixed to sample zero.\n");
604 fflush(stderr);
605 } else {
606 if(verbose>1) {printf("Note: initial fraction fixed to %g\n", y0); fflush(stdout);}
607 pmin[iscale_par_index]=pmax[iscale_par_index]=y0;
608 if(fixed_p[iscale_par_index]>0.0) {
609 fprintf(stderr, "Warning: non-effective option -d for initial fraction.\n");
610 fflush(stderr);
611 }
612 }
613 }
614 /* If metabolites are fitted, then fix the parameter limits and number */
615 if(model==MODEL_MPF || model==MODEL_MHILL) {
616 /* Copy the same limits to the rest of parameters */
617 for(m=1; m<metabNr; m++) {
618 for(pi=0; pi<parNr-1; pi++) { // other parameters except delay
619 pmin[m*parNr+pi]=pmin[pi]; pmax[m*parNr+pi]=pmax[pi];}
620 // delay difference compared to the first
621 if(mdelay_joint==0) {
622 a=pmax[pi]-pmin[pi];
623 pmin[m*parNr+pi]=-0.5*a; pmax[m*parNr+pi]=+0.5*a;
624 } else {
625 pmin[m*parNr+pi]=0.0; pmax[m*parNr+pi]=0.0;
626 }
627 }
628 /* Nr of fitted parameters can be set only now */
629 parNr*=metabNr;
630 if(verbose>2) printf("final_parNr := %d\n", parNr);
631 }
632 if(verbose>1) {
633 printf("Constraints for the fit:\n");
634 for(pi=0; pi<parNr; pi++) printf(" limit[%d]: %g - %g\n", pi+1, pmin[pi], pmax[pi]);
635 fflush(stdout);
636 }
637
638
639 /*
640 * Check that sample number (not including NaNs) is at least one more
641 * than the number of actually fitted parameters.
642 */
643 for(fi=n=0; fi<fitdataNr; fi++) {
644 if(dft.x[fi]<0.0) continue;
645 if(!isnan(dft.voi[0].y[fi])) n++;
646 }
647 for(pi=m=0; pi<parNr; pi++) if(pmin[pi]<pmax[pi]) m++;
648 if(verbose>1) printf("Comparison of nr of samples and params to fit: %d / %d\n", n, m);
649 if((n-1)<m) {
650 fprintf(stderr, "Error: too few samples for fitting in %s\n", dfile);
651 if(verbose>0) printf("n := %d\nm := %d\n", n, m);
652 dftEmpty(&dft); fitEmpty(&fit); return(2);
653 }
654
655
656 /*
657 * Fit (one fit only)
658 */
659 if(verbose>1) {printf("preparing to fit.\n"); fflush(stdout);}
660 ri=0;
661 /* Set data pointers */
662 x=dft.x; w=dft.w; ymeas[0]=dft.voi[ri].y; yfit[0]=dft.voi[ri].y2;
663 for(m=0; m<metabNr; m++) {
664 ymeas[m+1]=dft.voi[m+1].y; yfit[m+1]=dft.voi[m+1].y2;
665 }
666 /* Set the initial value for WSS */
667 fit.voi[ri].wss=3.402823e+38;
668 /* fit */
669 if(verbose>1) printf("fitting\n");
671 TGO_LOCAL_OPT=0; // 0=Powell-Brent, 1=Bobyqa
672 TGO_SQUARED_TRANSF=1; //if(model==MODEL_GCDF) TGO_SQUARED_TRANSF=0;
673 int neighNr=6, iterNr=1, sampleNr=800;
674 if(model==MODEL_MPF || model==MODEL_PF) {
678 neighNr=5; iterNr=1; sampleNr=800;
679 }
680 ret=tgo(pmin, pmax, func_list[model], NULL, parNr, neighNr, &fit.voi[ri].wss,
681 fit.voi[ri].p, sampleNr, iterNr, verbose-8);
682 if(ret) {
683 fprintf(stderr, "Error %d in TGO.\n", ret);
684 dftEmpty(&dft); fitEmpty(&fit);
685 return(4);
686 }
687 if(verbose>4) {
688 printf("Results from tgo():\n");
689 for(pi=0; pi<parNr; pi++) printf(" parameter[%d] := %g\n", pi, fit.voi[ri].p[pi]);
690 printf("WSS := %g\n", fit.voi[ri].wss);
691 fflush(stdout);
692 }
693 fit.voi[ri].wss=lastWSS; // remove penalty from reported WSS (do not use a)
694 if(verbose>5) {printf("lastWSS := %g\n", lastWSS); fflush(stdout);}
695 /* Correct fitted parameters to match constraints like inside the function */
696 ri=0;
697 (void)modelCheckParameters(parNr, pmin, pmax, fit.voi[ri].p, fit.voi[ri].p, &a);
698 if(model==MODEL_HILL) { // Must be A<=D
699 if(fit.voi[ri].p[0]>fit.voi[ri].p[3]) fit.voi[ri].p[0]=fit.voi[ri].p[3];
700 } else if(model==MODEL_MHILL) {
701 n=parNr/metabNr;
702 for(m=0; m<metabNr; m++)
703 if(fit.voi[ri].p[m*n]>fit.voi[ri].p[m*n+3])
704 fit.voi[ri].p[m*n]=fit.voi[ri].p[m*n+3];
705 }
706 if(model==MODEL_MPF || model==MODEL_MHILL) { // delay can not be negative
707 n=parNr/metabNr;
708 for(m=1; m<metabNr; m++)
709 if( (fit.voi[ri].p[n-1]+fit.voi[ri].p[(m+1)*n-1]) < 0.0)
710 fit.voi[ri].p[(m+1)*n-1] = -fit.voi[ri].p[n-1];
711 }
712 /* Warn user about parameters that collide with limits */
713 if(verbose>5) {
714 printf("Corrected parameters:\n");
715 for(pi=0; pi<parNr; pi++) printf(" parameter[%d] := %g\n", pi, fit.voi[ri].p[pi]);
716 }
717 if(verbose>1) {
718 ret=modelCheckLimits(parNr, pmin, pmax, fit.voi[ri].p);
719 if(ret==0) {if(verbose>2) fprintf(stdout, "ok\n");}
720 else fprintf(stderr, "warning, fit collided with the limits.\n");
721 }
722 if(verbose>1) {fprintf(stdout, "WSS := %g\n", fit.voi[ri].wss); fflush(stdout);}
723 /* Print measured and fitted curve */
724 if(verbose>3) {
725 printf(" Measured Fitted Weight\n");
726 for(fi=0; fi<fitdataNr; fi++)
727 if(!isnan(ymeas[0][fi]))
728 printf(" %2d: %9.4e %9.4e %9.4e %7.1e\n", fi+1, x[fi], ymeas[0][fi], yfit[0][fi], w[fi]);
729 else
730 printf(" %2d: %9.4e %-9.9s %9.4e %7.1e\n", fi+1, x[fi], ".", yfit[0][fi], w[fi]);
731 printf(" fitted parameters:");
732 for(pi=0; pi<parNr; pi++) printf(" %g", fit.voi[ri].p[pi]);
733 printf("\n");
734 }
735 /* Check the MRL */
736 if(verbose>1) printf("Checking the MRL.\n");
737 fi=mrl_between_tacs(yfit[0], ymeas[0], fitdataNr);
738 if(fi>3 && fi>fitdataNr/3) {
739 if(MRL_check!=0) {
740 fprintf(stderr, "Error: bad fit.\n");
741 fprintf(stderr, "MRL := %d / %d\n", fi, fitdataNr);
742 dftEmpty(&dft); fitEmpty(&fit);
743 return(7);
744 }
745 }
746 if(fi>2 && fi>fitdataNr/4) {
747 fprintf(stderr, "Warning: bad fit.\n");
748 fprintf(stderr, "MRL := %d / %d\n", fi, fitdataNr);
749 } else if(verbose>1) {
750 printf("MRL test passed.\n");
751 if(verbose>2) fprintf(stderr, "MRL := %d / %d\n", fi, fitdataNr);
752 }
753 /* Calculate WSS for separate curves */
754 if(verbose>1) {
755 double wss[1+metabNr], f=0.0;
756 for(ai=0; ai<=metabNr; ai++) {
757 wss[ai]=0.0;
758 for(fi=0; fi<fitdataNr; fi++) {
759 a=dft.voi[ai].y[fi]-dft.voi[ai].y2[fi];
760 wss[ai]+=w[fi]*a*a;
761 }
762 f+=wss[ai]; printf("WSS[%d] := %g\n", ai+1, wss[ai]);
763 }
764 printf("WSS[total] := %g\n", f);
765 }
766 /* Calculate AIC */
767 if(verbose>1) {
768 ri=0;
769 for(ai=0, m=0; ai<=metabNr; ai++) if(frwgt[ai]>0.0)
770 for(fi=0; fi<fitdataNr; fi++) if(w[fi]>0.0) m++;
771 printf("nr_of_fitted_samples := %d\n", m);
772 for(pi=0, n=0; pi<parNr; pi++) if(pmax[pi]>pmin[pi]) n++;
773 printf("nr_of_fitted_parameters := %d\n", n);
774 aic=aicSS(fit.voi[ri].wss, m, n);
775 printf("AIC := %g\n", aic);
776 }
777 if(verbose>2) {
778 printf("Fitted parameters:\n");
779 ri=0;
780 for(pi=0; pi<parNr; pi++) printf(" par[%d]: %g\n", pi+1, fit.voi[ri].p[pi]);
781 if(verbose>4) for(pi=0; pi<parNr; pi++)
782 printf(" par[%d]: %g [%g, %g]\n", pi+1, fit.voi[ri].p[pi], pmin[pi], pmax[pi]);
783 }
784 /* In case of metabolite fitting, convert fitted delay parameter differences to actual delays */
785 if(model==MODEL_MPF || model==MODEL_MHILL) {
786 n=parNr/metabNr;
787 ri=0;
788 for(m=1; m<metabNr; m++) {
789 fit.voi[ri].p[(m+1)*n-1]+=fit.voi[ri].p[n-1];
790 }
791 }
792 /* Copy the parameters for metabolites, when necessary */
793 for(ri=1; ri<fit.voiNr; ri++) {
794 for(pi=0; pi<fit.voi[0].parNr; pi++) fit.voi[ri].p[pi]=fit.voi[0].p[pi];
795 fit.voi[ri].wss=fit.voi[0].wss;
796 }
797 /* In case of Hill function when function format #2 is required divide a with d */
798 if(model==MODEL_HILL && ffile_type==2) {
799 fit.voi[0].p[0]/=fit.voi[0].p[3];
800 }
801
802
803 /*
804 * Save fit results
805 */
806 if((verbose>1) && strcmp(ffile, "stdout")!=0) printf("saving results in %s\n", ffile);
807 ret=fitWrite(&fit, ffile); if(ret) {
808 fprintf(stderr, "Error (%d) in writing '%s': %s\n", ret, ffile, fiterrmsg);
809 dftEmpty(&dft); fitEmpty(&fit); return(11);
810 }
811 if(strcmp(ffile, "stdout")!=0 && verbose>0)
812 printf("Function parameters written in %s\n", ffile);
813
814
815 /*
816 * Plot fitted curves
817 */
818 if(svgfile[0]) {
819 if(verbose>1) printf("creating SVG plot\n");
820 DFT adft;
821 char tmp[FILENAME_MAX];
822
823 if(verbose>1) printf("calculating fitted curve at automatically generated sample times\n");
824 dftInit(&adft);
825 ret=dftAutointerpolate(&dft, &adft, 1.10*dft.x[dft.frameNr-1], verbose-7);
826 if(ret) {
827 fprintf(stderr, "Error %d in memory allocation for fitted curves.\n", ret);
828 dftEmpty(&dft); fitEmpty(&fit); dftEmpty(&adft);
829 return(13);
830 }
831 for(fi=0; fi<adft.frameNr; fi++) adft.w[fi]=1.0;
832 x=adft.x; w=adft.w;
833 for(ri=0; ri<adft.voiNr; ri++) {
834 yfit[ri]=adft.voi[ri].y;
835 ymeas[ri]=adft.voi[ri].y2;
836 }
837 // use library function
838 for(ri=0, ret=0; ri<adft.voiNr; ri++) {
839 for(fi=0; fi<adft.frameNr; fi++) {
840 ret=fitEval(&fit.voi[ri], adft.x[fi], &a); if(ret!=0) break;
841 adft.voi[ri].y[fi]=a;
842 }
843 if(ret!=0) break;
844 }
845 if(ret!=0) {
846 fprintf(stderr, "Error: cannot calculate fitted curve for '%s'.\n", svgfile);
847 dftEmpty(&dft); dftEmpty(&adft); fitEmpty(&fit);
848 return(14);
849 }
850
851 /* Save SVG plot of fitted and original data */
852 if(verbose>1) printf("writing %s\n", svgfile);
853 tpcProgramName(argv[0], 0, 0, tmp, 64); strcat(tmp, " ");
854 if(strlen(adft.studynr)>1) strcat(tmp, adft.studynr);
855 ret=plot_fitrange_svg(&dft, &adft, tmp, 0.0, nan(""), 0.0, 1.0, svgfile, verbose-8);
856 if(ret) {
857 fprintf(stderr, "Error (%d) in writing '%s'.\n", ret, svgfile);
858 dftEmpty(&adft); dftEmpty(&dft); fitEmpty(&fit);
859 return(30+ret);
860 }
861 if(verbose>0) printf("Plots written in %s\n", svgfile);
862
863 dftEmpty(&adft);
864 }
865
866 /* Free memory */
867 dftEmpty(&dft); fitEmpty(&fit);
868
869 return(0);
870}
871/*****************************************************************************/
872
873/******************************************************************************
874 *
875 * Functions to be minimized
876 *
877 *****************************************************************************/
878double func_pf(int parNr, double *p, void *fdata)
879{
880 int i;
881 double a, b, c, d, dt, v, f, wss;
882 double pa[MAX_PARAMETERS], penalty=1.0;
883
884 /* Check parameters against the constraints */
885 if(0) {
886 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
887 printf("\n");
888 }
889 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
890 if(fdata) {}
891 a=pa[0]; b=pa[1]; c=pa[2]; d=pa[3]; dt=pa[4];
892
893 /* Calculate the curve values and weighted SS */
894 f=pow(d, -1.0/c);
895 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
896 if(x[i]<=dt) yfit[0][i]=d;
897 else yfit[0][i]=pow(f+pow(a*(x[i]-dt), b), -c);
898 v=yfit[0][i]-ymeas[0][i];
899 if(min_meas==MINMEAS_LAD) v=fabs(v);
900 else if(min_meas==MINMEAS_OLS) v*=v;
901 else if(min_meas==MINMEAS_ODR) {
902 /* Calculate function derivative at x */
903 double df=0.0;
904 if(x[i]>dt) df=-(b*c*pow(a*(x[i]-dt),b)/(x[i]-dt)) * pow(pow(d,-1.0/c)+pow(a*(x[i]-dt),b),-c-1.0);
905 if(!isfinite(df)) df=0.0;
906 /* Calculate Akaho distance */
907 v*=v; v/=(1.0 + df*df);
908 }
909 wss+=w[i]*v;
910 }
911 lastWSS=wss; wss*=penalty;
912 if(0) printf("%g %g %g %g %g -> %g\n", a, b, c, d, dt, wss);
913 return(wss);
914}
915
916double func_hill(int parNr, double *p, void *fdata)
917{
918 int i;
919 double a, b, c, d, dt, v, wss;
920 double pa[MAX_PARAMETERS], penalty=1.0;
921
922 /* Check parameters against the constraints */
923 if(0) {
924 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
925 printf("\n");
926 }
927 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
928 if(fdata) {}
929 a=pa[0]; b=pa[1]; c=pa[2]; d=pa[3]; dt=pa[4];
930 /* additional check: a<=d */
931 if(a>d) {
932 penalty+=100.0*(a/d);
933 a=d;
934 }
935
936 /* Calculate the curve values and weighted SS */
937 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
938 if(x[i]<=dt)
939 yfit[0][i]= d;
940 else {
941 double f=pow(x[i]-dt, b);
942 yfit[0][i]= d + (a-d)*f/(c+f);
943 }
944 v=yfit[0][i]-ymeas[0][i];
945 if(min_meas==MINMEAS_LAD) v=fabs(v);
946 else if(min_meas==MINMEAS_OLS) v*=v;
947 else if(min_meas==MINMEAS_ODR) {
948 /* Calculate function derivative at x */
949 double df=0.0; if(x[i]>dt) df=-b*c*(d-a)*pow(x[i]-dt,b-1.0)/pow(c+pow(x[i]-dt,b),2);
950 if(!isfinite(df)) df=0.0;
951 /* Calculate Akaho distance */
952 v*=v; v/=(1.0 + df*df);
953 }
954 wss+=w[i]*v;
955 }
956 lastWSS=wss; wss*=penalty; // needed because additional penalty is possible
957 //printf(" objfunc(): lastWSS=%g WSS=%g\n", lastWSS, wss);
958 if(0) printf("%g %g %g %g %g -> %g\n", a, b, c, d, dt, wss);
959 return(wss);
960}
961
962double func_gcdf(int parNr, double *p, void *fdata)
963{
964 int i;
965 double a, b, c, d, dt, v, wss;
966 double pa[MAX_PARAMETERS], penalty=1.0;
967
968 /* Check parameters against the constraints */
969 if(0) {
970 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
971 printf("\n");
972 }
973 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
974 if(fdata) {}
975 a=pa[0]; b=pa[1]; c=pa[2]; d=pa[3]; dt=pa[4];
976 /* Calculate the curve values and weighted SS */
977 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
978 if(x[i]<=dt)
979 yfit[0][i]=a;
980 else {
981 yfit[0][i]= a*(1.0-b*igam(d, c*(x[i]-dt)));
982 }
983 v=yfit[0][i]-ymeas[0][i];
984 if(min_meas==MINMEAS_LAD) v=fabs(v);
985 else v*=v;
986 wss+=w[i]*v;
987 //printf(" x=%g ymeas=%g yfit=%g v=%g wss=%g\n", x[i], ymeas[0][i], yfit[0][i], v, wss);
988 }
989 lastWSS=wss; wss*=penalty;
990 //printf(" objfunc(): lastWSS=%g WSS=%g\n", lastWSS, wss);
991 if(0) printf("%g %g %g %g %g -> %g\n", a, b, c, d, dt, wss);
992 return(wss);
993}
994
995double func_ep(int parNr, double *p, void *fdata) // Based on Mu et al 2020
996{
997 int i;
998 double a, b, c, d, dt, s, v, wss;
999 double pa[MAX_PARAMETERS], penalty=1.0;
1000
1001 /* Check parameters against the constraints */
1002 if(0) {
1003 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
1004 printf("\n");
1005 }
1006 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
1007 if(fdata) {}
1008 dt=pa[0]; s=pa[1]; a=pa[2]; b=pa[3]; c=pa[4]; d=pa[5];
1009 /* Calculate the curve values and weighted SS */
1010 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
1011 double xt=x[i]-dt;
1012 if(xt<=0.0)
1013 yfit[0][i]=s;
1014 else {
1015 yfit[0][i]= a*exp(-b*xt*xt*xt/(xt*xt+c)) + (1.0-a)*exp(-d*xt);
1016 yfit[0][i]*=s;
1017 }
1018 v=yfit[0][i]-ymeas[0][i];
1019 if(min_meas==MINMEAS_LAD) v=fabs(v);
1020 else v*=v;
1021 wss+=w[i]*v;
1022 }
1023 lastWSS=wss; wss*=penalty;
1024 return(wss);
1025}
1026
1027double func_mpf(int parNr, double *p, void *fdata)
1028{
1029 int i, m, pn;
1030 double a[1+MAX_METAB_NR], b[1+MAX_METAB_NR], c[1+MAX_METAB_NR],
1031 d[1+MAX_METAB_NR], dt[1+MAX_METAB_NR];
1032 double pa[1+MAX_PARAMETERS], penalty=1.0;
1033 double mf[1+MAX_METAB_NR], g[1+MAX_METAB_NR], v, f, wss;
1034
1035 /* Check parameters against the constraints */
1036 if(0) {
1037 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
1038 printf("\n");
1039 }
1040 if(fdata) {}
1041 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
1042 pn=parNr/metabNr;
1043 for(m=0; m<metabNr; m++) {
1044 a[m]=pa[m*pn+0]; b[m]=pa[m*pn+1]; c[m]=pa[m*pn+2];
1045 d[m]=pa[m*pn+3]; dt[m]=pa[m*pn+4]; if(m>0) dt[m]+=dt[0];
1046 }
1047 for(; m<MAX_METAB_NR; m++) a[m]=b[m]=c[m]=d[m]=dt[m]=0.0;
1048 /* additional check: delay time should be positive */
1049 for(m=1; m<metabNr; m++) if(dt[m]<0.0) {
1050 penalty+=100.0*(-dt[m]); dt[m]=0.0;}
1051
1052 /* Calculate the curve values and weighted SS */
1053 for(m=0; m<metabNr; m++) g[m]=pow(d[m], -1.0/c[m]);
1054 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
1055 for(m=0; m<metabNr && m<=MAX_METAB_NR; m++) {
1056 if(x[i]<=dt[m]) mf[m]=1.0 - d[m];
1057 else mf[m]=1.0 - pow(g[m]+pow(a[m]*(x[i]-dt[m]), b[m]), -c[m]);
1058 }
1059 for(; m<MAX_METAB_NR; m++) mf[m]=0.0;
1060 yfit[0][i]=1.0;
1061 f=1.0-mf[0]*mf[1]-mf[0]*mf[2]-mf[1]*mf[2]+2.0*mf[0]*mf[1]*mf[2];
1062 yfit[1][i]=mf[0]*(1.0-mf[1]-mf[2]+mf[1]*mf[2])/f; yfit[0][i]-=yfit[1][i];
1063 if(metabNr>1) {
1064 yfit[2][i]=mf[1]*(1.0-mf[0]-mf[2]+mf[0]*mf[2])/f; yfit[0][i]-=yfit[2][i];
1065 }
1066 if(metabNr>2) {
1067 yfit[3][i]=mf[2]*(1.0-mf[0]-mf[1]+mf[0]*mf[1])/f; yfit[0][i]-=yfit[3][i];
1068 }
1069 for(m=0; m<=metabNr && m<=MAX_METAB_NR; m++) {
1070 v=yfit[m][i]-ymeas[m][i];
1071 if(min_meas==MINMEAS_OLS) v*=v; else v=fabs(v);
1072 wss+=w[i]*frwgt[m]*v;
1073 }
1074 }
1075 lastWSS=wss; wss*=penalty; // needed because additional penalty is possible
1076 //if(!isfinite(wss)) wss=nan("");
1077 return(wss);
1078}
1079
1080double func_mhill(int parNr, double *p, void *fdata)
1081{
1082 int i, m, pn;
1083 double a[1+MAX_METAB_NR], b[1+MAX_METAB_NR], c[1+MAX_METAB_NR],
1084 d[1+MAX_METAB_NR], dt[1+MAX_METAB_NR];
1085 double pa[1+MAX_PARAMETERS], penalty=1.0;
1086 double mf[1+MAX_METAB_NR], v, f, wss;
1087
1088 /* Check parameters against the constraints */
1089 if(0) {
1090 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
1091 printf("\n");
1092 }
1093 if(fdata) {}
1094 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
1095 pn=parNr/metabNr;
1096 for(m=0; m<metabNr; m++) {
1097 a[m]=pa[m*pn+0]; b[m]=pa[m*pn+1]; c[m]=pa[m*pn+2];
1098 d[m]=pa[m*pn+3]; dt[m]=pa[m*pn+4]; if(m>0) dt[m]+=dt[0];
1099 /* additional check: a<=d */
1100 if(a[m]>d[m]) {
1101 penalty+=100.0*(a[m]/d[m]);
1102 a[m]=d[m];
1103 }
1104 }
1105 for(; m<MAX_METAB_NR; m++) a[m]=b[m]=c[m]=d[m]=dt[m]=0.0;
1106 /* additional check: delay time should be positive */
1107 for(m=1; m<metabNr; m++) if(dt[m]<0.0) {
1108 penalty+=100.0*(-dt[m]); dt[m]=0.0;}
1109
1110 /* Calculate the curve values and weighted SS */
1111 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
1112 for(m=0; m<metabNr && m<=MAX_METAB_NR; m++) {
1113 if(x[i]<=dt[m])
1114 mf[m]=1.0 - d[m];
1115 else {
1116 f=pow(x[i]-dt[m], b[m]);
1117 mf[m]=1.0 - (d[m] + (a[m]-d[m])*f/(c[m]+f));
1118 }
1119 }
1120 for(; m<MAX_METAB_NR; m++) mf[m]=0.0;
1121 yfit[0][i]=1.0;
1122 f=1.0-mf[0]*mf[1]-mf[0]*mf[2]-mf[1]*mf[2]+2.0*mf[0]*mf[1]*mf[2];
1123 yfit[1][i]=mf[0]*(1.0-mf[1]-mf[2]+mf[1]*mf[2])/f; yfit[0][i]-=yfit[1][i];
1124 if(metabNr>1) {
1125 yfit[2][i]=mf[1]*(1.0-mf[0]-mf[2]+mf[0]*mf[2])/f; yfit[0][i]-=yfit[2][i];
1126 }
1127 if(metabNr>2) {
1128 yfit[3][i]=mf[2]*(1.0-mf[0]-mf[1]+mf[0]*mf[1])/f; yfit[0][i]-=yfit[3][i];
1129 }
1130 for(m=0; m<=metabNr && m<=MAX_METAB_NR; m++) {
1131 v=yfit[m][i]-ymeas[m][i];
1132 if(min_meas==MINMEAS_OLS) v*=v; else v=fabs(v);
1133 wss+=w[i]*frwgt[m]*v;
1134 }
1135 }
1136 lastWSS=wss; wss*=penalty; // needed because additional penalty is possible
1137 return(wss);
1138}
1139/*****************************************************************************/
1140
1141/*****************************************************************************/
double aicSS(double ss, const int n, const int k)
Definition aic.c:20
int modelCheckParameters(int par_nr, double *lower_p, double *upper_p, double *test_p, double *accept_p, double *penalty)
Definition constraints.c:15
int modelCheckLimits(int par_nr, double *lower_p, double *upper_p, double *test_p)
Definition constraints.c:59
int CSV_TEST
Definition csv.c:6
double atof_dpi(char *str)
Definition decpoint.c:59
void dftInit(DFT *data)
Definition dft.c:38
char dfterrmsg[64]
Definition dft.c:6
int dftAddmem(DFT *dft, int voiNr)
Definition dft.c:107
int dftSortByFrame(DFT *dft)
Definition dft.c:1169
int dftMinMax(DFT *dft, double *minx, double *maxx, double *miny, double *maxy)
Definition dft.c:974
void dftEmpty(DFT *data)
Definition dft.c:20
int dftRead(char *filename, DFT *data)
Definition dftio.c:22
void dftPrint(DFT *data)
Definition dftio.c:538
void dftUnitToDFT(DFT *dft, int dunit)
Definition dftunit.c:11
void dftSec2min(DFT *dft)
Definition dftunit.c:160
int dftAutointerpolate(DFT *dft, DFT *dft2, double endtime, int verbose)
int fit_allocate_with_dft(FIT *fit, DFT *dft)
Definition fitres.c:14
Header file for libtpccurveio.
double igam(double a, double x)
Definition mathfunc.c:1715
int fitEval(FitVOI *r, double x, double *y)
Definition mathfunc.c:645
void fitEmpty(FIT *fit)
Definition mathfunc.c:18
int fitWrite(FIT *fit, char *filename)
Definition mathfunc.c:54
char fiterrmsg[64]
Definition mathfunc.c:6
void fitInit(FIT *fit)
Definition mathfunc.c:38
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
Definition proginfo.c:101
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
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)
Definition tgo.c:39
int TGO_LOCAL_INSIDE
Definition tgo.c:29
int mrl_between_tacs(double y1[], double y2[], int n)
Definition runs_test.c:103
#define MAX_PARAMETERS
Definition libtpcmodel.h:31
int TGO_LOCAL_OPT
Definition tgo.c:31
int TGO_SQUARED_TRANSF
Definition tgo.c:27
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)
Definition plotfit.c:16
Header file for libtpcsvg.
Voi * voi
int timeunit
char studynr[MAX_STUDYNR_LEN+1]
double * w
int voiNr
int frameNr
int isweight
double * x
int voiNr
char datafile[FILENAME_MAX]
char program[1024]
FitVOI * voi
time_t time
double wss
double end
double start
double p[MAX_FITPARAMS]
double * y2
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
char name[MAX_REGIONNAME_LEN+1]