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
187 /* Initially, assume that none of parameters is fixed */
188 for(pi=0; pi<MAX_PARAMETERS; pi++) fixed_p[pi]=-1;
189 /* By default, no additional weight for any of fractions */
190 for(m=0; m<=MAX_METAB_NR; m++) frwgt[m]=1.0;
191
192
193 /*
194 * Get arguments
195 */
196 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
197 dftInit(&dft); fitInit(&fit);
198 dfile[0]=ffile[0]=svgfile[0]=(char)0;
199 /* Options */
200 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
201 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
202 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
203 if(strncasecmp(cptr, "MODEL=", 6)==0) {
204 cptr+=6;
205 if(strncasecmp(cptr, "PF", 1)==0) {model=MODEL_PF; continue;}
206 if(strcasecmp(cptr, "HILL2")==0) {model=MODEL_HILL; ffile_type=2; continue;}
207 if(strncasecmp(cptr, "HILL", 1)==0) {model=MODEL_HILL; continue;}
208 if(strncasecmp(cptr, "GCDF", 1)==0) {model=MODEL_GCDF; continue;}
209 if(strcasecmp(cptr, "EP")==0) {model=MODEL_EP; continue;}
210 if(strncasecmp(cptr, "MPF", 3)==0) {model=MODEL_MPF; continue;}
211 if(strncasecmp(cptr, "MHILL", 3)==0) {model=MODEL_MHILL; continue;}
212 fprintf(stderr, "Error: invalid model selection.\n"); return(1);
213 } else if(strcasecmp(cptr, "ND")==0) {
214 noDivide=1; continue;
215 } else if(strcasecmp(cptr, "W1")==0) {
216 weighting=1; continue;
217 } else if(strcasecmp(cptr, "WF")==0) {
218 weighting=2; continue;
219 } else if(strcasecmp(cptr, "WC")==0) {
220 last_col_is_weight=1; continue;
221 } else if(strncasecmp(cptr, "WP=", 3)==0) {
222 frwgt[0]=atof_dpi(cptr+3); if(frwgt[0]>=0.0) continue;
223 } else if(strncasecmp(cptr, "WM1=", 4)==0) {
224 frwgt[1]=atof_dpi(cptr+4); if(frwgt[1]>=0.0) continue;
225 } else if(strncasecmp(cptr, "WM2=", 4)==0) {
226 frwgt[2]=atof_dpi(cptr+4); if(frwgt[2]>=0.0) continue;
227 } else if(strncasecmp(cptr, "WM3=", 4)==0) {
228 frwgt[3]=atof_dpi(cptr+4); if(frwgt[3]>=0.0) continue;
229 } else if(strncasecmp(cptr, "A=", 2)==0) {
230 fixed_p[0]=atof_dpi(cptr+2); if(fixed_p[0]>=0.0) continue;
231 } else if(strncasecmp(cptr, "B=", 2)==0) {
232 fixed_p[1]=atof_dpi(cptr+2); if(fixed_p[1]>=0.0) continue;
233 } else if(strncasecmp(cptr, "C=", 2)==0) {
234 fixed_p[2]=atof_dpi(cptr+2); if(fixed_p[2]>=0.0) continue;
235 } else if(strncasecmp(cptr, "D=", 2)==0) {
236 fixed_p[3]=atof_dpi(cptr+2); if(fixed_p[3]>=0.0) continue;
237 } else if(strncasecmp(cptr, "E=", 2)==0) {
238 fixed_p[4]=atof_dpi(cptr+2); if(fixed_p[4]>=0.0) continue;
239 } else if(strncasecmp(cptr, "F=", 2)==0) {
240 fixed_p[5]=atof_dpi(cptr+2); if(fixed_p[5]>=0.0) continue;
241 } else if(strncasecmp(cptr, "DELAYMIN=", 9)==0) {
242 min_delay=atof_dpi(cptr+9); if(min_delay>=0.0) continue;
243 } else if(strcasecmp(cptr, "FIX0")==0 || strcasecmp(cptr, "FIXED0")==0) {
244 fixed0=1; continue;
245 } else if(strcasecmp(cptr, "MRL")==0) {
246 MRL_check=1; continue;
247 } else if(strncasecmp(cptr, "MDELAY=", 7)==0) {
248 cptr+=7;
249 if(strncasecmp(cptr, "JOINT", 1)==0) {mdelay_joint=1; continue;}
250 if(strncasecmp(cptr, "SEPARATED", 1)==0) {mdelay_joint=0; continue;}
251 fprintf(stderr, "Error: invalid mdelay selection.\n"); return(1);
252 } else if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
253 strlcpy(svgfile, cptr+4, FILENAME_MAX); continue;
254 } else if(strncasecmp(cptr, "MIN=", 4)==0) {
255 cptr+=4;
256 if(strcasecmp(cptr, "OLS")==0 || strcasecmp(cptr, "SS")==0 || strcasecmp(cptr, "WSS")==0) {
257 min_meas=MINMEAS_OLS; continue;}
258 if(strcasecmp(cptr, "LAD")==0 || strcasecmp(cptr, "ABS")==0 || strcasecmp(cptr, "WABS")==0) {
259 min_meas=MINMEAS_LAD; continue;}
260 if(strcasecmp(cptr, "ODR")==0) {
261 min_meas=MINMEAS_ODR; continue;}
262 fprintf(stderr, "Error: invalid minimization measure.\n"); return(1);
263 }
264 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
265 return(1);
266 } else break;
267
268 /* Print help or version? */
269 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
270 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
271 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
272
273 /* Process other arguments, starting from the first non-option */
274 if(ai<argc) strlcpy(dfile, argv[ai++], FILENAME_MAX);
275 if(ai<argc) strlcpy(ffile, argv[ai++], FILENAME_MAX);
276 if(ai<argc) {fprintf(stderr, "Error: too many arguments: '%s'.\n", argv[ai]); return(1);}
277
278 /* Is something missing? */
279 if(!dfile[0]) {
280 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
281 return(1);
282 }
283 /* Apply default model, if not selected by user */
284 if(model==MODEL_UNKNOWN) model=MODEL_HILL;
285 if(min_meas==MINMEAS_UNKNOWN) min_meas=MINMEAS_OLS;
286 /* Check compatibility of options */
287 if(min_meas==MINMEAS_ODR) {
288 if(model!=MODEL_HILL && model!=MODEL_PF) {
289 fprintf(stderr, "Warning: ODR is not available with selected model.\n");
290 fprintf(stderr, "Note: using OLS instead of ODR.\n");
291 min_meas=MINMEAS_OLS;
292 }
293 }
294 /* Set function specific parameters */
295 type=func_type[model];
296 if(model==MODEL_HILL && ffile_type==2) type=MF_EHILL2_PAR;
297 parNr=func_par_nr[model];
298 delay_par_index=parNr-1;
299 if(model!=MODEL_GCDF) iscale_par_index=parNr-2;
300 if(model==MODEL_EP) {delay_par_index=0; iscale_par_index=1;}
301 for(pi=0, n=0; pi<parNr; pi++) if(fixed_p[pi]>=0.0) n++;
302 if((parNr-n)<1) {
303 fprintf(stderr, "Error: too many parameters were fixed.\n");
304 return(1);
305 }
306 if(fixed_p[delay_par_index]>=0.0 && mdelay_joint==0)
307 fprintf(stderr, "Warning: option -mdelay is not effective with option -e\n");
308 if(!ffile[0]) strcpy(ffile, "stdout");
309
310
311 /* In verbose mode print arguments and options */
312 if(verbose>1) {
313 printf("dfile := %s\n", dfile);
314 printf("ffile := %s\n", ffile);
315 printf("svgfile := %s\n", svgfile);
316 printf("noDivide := %d\n", noDivide);
317 printf("weighting := %d\n", weighting);
318 printf("mdelay_joint := %d\n", mdelay_joint);
319 printf("last_col_is_weight := %d\n", last_col_is_weight);
320 printf("model := %d\n", model);
321 printf("type := %d\n", type);
322 printf("parNr := %d\n", parNr);
323 printf("min_meas := %d\n", min_meas);
324 for(pi=0; pi<parNr; pi++) if(fixed_p[pi]>=0.0) printf("fixed_p[%d] := %g\n", pi, fixed_p[pi]);
325 if(min_delay>=0.0) printf("min_delay := %g\n", min_delay);
326 printf("fixed0 := %d\n", fixed0);
327 printf("MRL_check := %d\n", MRL_check);
328 for(m=0; m<=MAX_METAB_NR; m++) printf("frwgt[%d] := %g\n", m, frwgt[m]);
329 fflush(stdout);
330 }
331 if(verbose>2) CSV_TEST=verbose-2; else CSV_TEST=0;
332
333 /*
334 * Read data
335 */
336 if(verbose>1) printf("reading %s\n", dfile);
337 if(dftRead(dfile, &dft)) {
338 fprintf(stderr, "Error in reading '%s': %s\n", dfile, dfterrmsg);
339 return(2);
340 }
341 origdataNr=dft.frameNr;
342
343 /* If required, set the last column as weights */
344 if(last_col_is_weight!=0) {
345 if(verbose>1) printf("reading weights from the last column.\n");
346 if(dft.voiNr<2) {
347 fprintf(stderr, "Error: no column for weights in %s\n", dfile);
348 dftEmpty(&dft); return(2);
349 }
350 for(fi=0; fi<dft.frameNr; fi++) {
351 dft.w[fi]=dft.voi[dft.voiNr-1].y[fi];
352 if(isnan(dft.w[fi])) dft.w[fi]=0.0;
353 }
354 dft.isweight=1; dft.voiNr--;
355 }
356
357 if(verbose>1) {
358 if(strlen(dft.studynr)>0 && strcmp(dft.studynr, ".")!=0)
359 printf("study_number := %s\n", dft.studynr);
360 printf("tacNr := %d\n", dft.voiNr);
361 }
362
363 /* Sort the samples by time in case data is catenated from several curves */
364 (void)dftSortByFrame(&dft);
365
366 /* Make sure that times are in minutes */
367 if(dft.timeunit==TUNIT_SEC) {
368 if(verbose>1) printf("Sample times are converted to min\n");
369 dftSec2min(&dft);
370 }
371 if(dft.timeunit==TUNIT_UNKNOWN) {
372 dft.timeunit=TUNIT_MIN;
373 }
374
375 /* Ignore extra columns, if parent fraction is fitted */
376 if(model==MODEL_PF || model==MODEL_HILL || model==MODEL_GCDF || model==MODEL_EP) {
377 if(dft.voiNr>1) {
378 fprintf(stderr, "Warning: extra columns in %s are ignored.\n", dfile);
379 dft.voiNr=1;
380 }
381 } else { /* Metabolite fraction(s) will be fitted */
382 if(dft.voiNr==1) {
383 if(verbose>1) printf("calculating metabolite fractions\n");
384 /* If no metabolite fractions were found, then add one */
385 ret=dftAddmem(&dft, 1); if(ret!=0) {
386 fprintf(stderr, "Error: cannot allocate memory for metabolite.\n");
387 dftEmpty(&dft); return(2);
388 }
389 dft.voiNr++;
390 for(fi=0; fi<dft.frameNr; fi++) dft.voi[1].y[fi]=1.0-dft.voi[0].y[fi];
391 } else if(dft.voiNr>(1+MAX_METAB_NR)) {
392 /* If too many metabolite fractions, then combine the last ones */
393 for(fi=0; fi<dft.frameNr; fi++) for(ri=1+MAX_METAB_NR; ri<dft.voiNr; ri++)
394 {
395 if(isnan(dft.voi[ri].y[fi])) continue;
396 if(isnan(dft.voi[MAX_METAB_NR].y[fi])) {
397 dft.voi[MAX_METAB_NR].y[fi]=dft.voi[ri].y[fi]; continue;}
398 dft.voi[MAX_METAB_NR].y[fi]+=dft.voi[ri].y[fi];
399 }
400 fprintf(stderr, "Warning: extra metabolite(s) are summed in Metab3.\n");
401 dft.voiNr=1+MAX_METAB_NR;
402 }
403 /* Set the number of metabolite fraction curves to be fitted */
404 metabNr=dft.voiNr-1; if(metabNr>MAX_METAB_NR) metabNr=MAX_METAB_NR;
405 if(verbose>1) printf("metabNr := %d\n", metabNr);
406 /* Set only later the fitted parameter nr based on the nr of metabolites */
407 }
408 /* Set the names for curves */
409 if(strlen(dft.voi[0].name)==0) {
410 strcpy(dft.voi[0].name, "Parent");
411 strcpy(dft.voi[0].voiname, dft.voi[0].name);
412 }
413 for(ri=1; ri<dft.voiNr; ri++) if(strlen(dft.voi[ri].name)==0) {
414 strcpy(dft.voi[ri].name, "Metab1");
415 strcpy(dft.voi[ri].voiname, dft.voi[ri].name);
416 }
417 if(verbose>11) dftPrint(&dft);
418 /* Set the number of fitted samples here; sort the data first if necessary */
419 // not implemented, all data fitted
420 fitdataNr=origdataNr;
421 if(fitdataNr<2) { // More precise testing later
422 fprintf(stderr, "Error: too few samples for fitting in %s\n", dfile);
423 dftEmpty(&dft); return(2);
424 }
425 dft.frameNr=fitdataNr;
426
427 /* Get start and end times */
428 ret=dftMinMax(&dft, &tstart, &tstop, NULL, &maxfract);
429 if(ret!=0) {
430 fprintf(stderr, "Error: invalid contents in %s\n", dfile);
431 dftEmpty(&dft); return(2);
432 }
433 if(verbose>2) printf("max := %g\n", maxfract);
434 /* Check that x values are >=0 and that there is range in x values */
435 if(tstart<0.0 || !(tstop>tstart)) {
436 fprintf(stderr, "Error: invalid sample times.\n");
437 dftEmpty(&dft); return(2);
438 }
439 /* Check that y values are <=1 */
440 if(maxfract>100.0 || maxfract<0.001) {
441 fprintf(stderr, "Error: invalid fraction values.\n");
442 dftEmpty(&dft); return(2);
443 }
444 if(noDivide==0 && maxfract>1.0) {
445 fprintf(stderr, "Warning: converting percentages to fractions.\n");
446 for(fi=0; fi<origdataNr; fi++) for(ri=0; ri<dft.voiNr; ri++)
447 if(!isnan(dft.voi[ri].y[fi])) dft.voi[ri].y[fi]/=100.0;
448 /* make sure that units are not percentages any more */
449 dftUnitToDFT(&dft, CUNIT_UNITLESS);
450 }
451 if(verbose>9) dftPrint(&dft);
452
453 /* Check and set weights */
454 if(dft.isweight==0 || weighting==1) {
455 dft.isweight=1;
456 for(fi=0; fi<dft.frameNr; fi++) dft.w[fi]=1.0;
457 }
458 if(weighting==2) { // weighting by sample frequency
459 dftWeightByFreq(&dft); // must be sorted by time before this
460 }
461 /* Set sample weights to zero, if parent fraction is NaN */
462 for(fi=0; fi<dft.frameNr; fi++) if(isnan(dft.voi[0].y[fi])) dft.w[fi]=0;
463 if(verbose>1) {
464 printf("data_weights := %g", dft.w[0]);
465 for(fi=1; fi<dft.frameNr; fi++) printf(", %g", dft.w[fi]);
466 printf("\n");
467 }
468
469
470 /*
471 * Allocate memory for fits
472 */
473 if(verbose>1) printf("allocating memory for fits.\n");
474 ret=fit_allocate_with_dft(&fit, &dft);
475 if(ret) {
476 fprintf(stderr, "Error: cannot allocate space for fit results (%d).\n", ret);
477 dftEmpty(&dft); fitEmpty(&fit); return(4);
478 }
479 /* Set necessary information in fit data structure */
480 fit.voiNr=dft.voiNr;
481 strncpy(fit.datafile, dfile, FILENAME_MAX);
482 tpcProgramName(argv[0], 1, 1, fit.program, 256);
483 fit.time=time(NULL);
484 for(fi=n=0; fi<fitdataNr; fi++) if(dft.x[fi]>=0.0 && !isnan(dft.voi[0].y[fi])) n++;
485 for(ri=0; ri<fit.voiNr; ri++) {
486 fit.voi[ri].type=type;
487 fit.voi[ri].parNr=parNr;
488 if(model==MODEL_MPF || model==MODEL_MHILL) fit.voi[ri].parNr*=metabNr;
489 fit.voi[ri].start=tstart; fit.voi[ri].end=tstop;
490 fit.voi[ri].dataNr=n;
491 }
492 if(model==MODEL_MHILL) {
493 fit.voi[0].type=MF_HILL3M_PAR;
494 fit.voi[1].type=MF_HILL3M_M1;
495 if(metabNr>1) fit.voi[2].type=MF_HILL3M_M2;
496 if(metabNr>2) fit.voi[3].type=MF_HILL3M_M3;
497 } else if(model==MODEL_MPF) {
498 fit.voi[0].type=MF_PF3M_PAR;
499 fit.voi[1].type=MF_PF3M_M1;
500 if(metabNr>1) fit.voi[2].type=MF_PF3M_M2;
501 if(metabNr>2) fit.voi[3].type=MF_PF3M_M3;
502 }
503
504 /*
505 * Set parameter constraints
506 */
507 switch(model) {
508 case MODEL_PF:
509 case MODEL_MPF:
510 pmin[0]=1.0e-20; pmax[0]=1.0e+00;
511 pmin[1]=1.5; pmax[1]=5.0e+01;
512 pmin[2]=1.0e-20; pmax[2]=1.0e+00;
513 pmin[3]=1.0e-20; pmax[3]=1.0e+00;
514 break;
515 case MODEL_HILL:
516 case MODEL_MHILL:
517 pmin[0]=0.0; pmax[0]=1.0e+00;
518 pmin[1]=1.0; pmax[1]=1.5e+01;
519 pmin[2]=1.0e-06; pmax[2]=1.0e+05;
520 pmin[3]=1.0e-06; pmax[3]=1.0e+00;
521 break;
522 case MODEL_GCDF:
523 pmin[0]=0.0; pmax[0]=1.0e+00;
524 pmin[1]=0.1; pmax[1]=1.0e+00;
525 pmin[2]=1.0e-06; pmax[2]=1.0e+01;
526 pmin[3]=1.0e-06; pmax[3]=1.0e+02;
527 break;
528 case MODEL_EP:
529 pmin[0]=0.0; pmax[0]=1.0; // delay
530 pmin[1]=0.1; pmax[1]=1.0; // max
531 pmin[2]=0.001; pmax[2]=1.0;
532 pmin[3]=0.001; pmax[3]=1.0;
533 pmin[4]=1.0; pmax[4]=1.0e+03;
534 pmin[5]=1.0e-06; pmax[5]=0.2;
535 break;
536 }
537 /* Delay parameter limits; first the min */
538 if(min_delay>=0) {
539 if(min_delay>0.9*dft.x[fitdataNr-1]) min_delay=0.9*dft.x[fitdataNr-1];
540 pmin[delay_par_index]=min_delay;
541 } else {
542 if(fixed_p[iscale_par_index]==1.0) { // fraction starts from 1.0
543 a=0.0; // search last sample that is 1.0
544 for(fi=0; fi<fitdataNr; fi++) if(dft.voi[0].y[fi]>=1.0 && dft.x[fi]>a) a=dft.x[fi];
545 pmin[delay_par_index]=a;
546 } else { // here initial fraction can be <1
547 pmin[delay_par_index]=0.0;
548 }
549 }
550 /* then the max delay */
551 if(model==MODEL_PF || model==MODEL_HILL || model==MODEL_GCDF || model==MODEL_EP || mdelay_joint==1) {
552 /* parent fraction is fitted, or if metabolite fraction(s) are fitted, then
553 common delay time for all metabolites is assumed */
554 if(fixed_p[iscale_par_index]==1.0) {
555 // fractions start from 1.0/0.0
556 a=1000.0; // search first sample time which is lower than 1.0
557 for(fi=0; fi<fitdataNr; fi++) if(dft.voi[0].y[fi]<1.0 && dft.x[fi]<a) a=dft.x[fi];
558 pmax[delay_par_index]=a;
559 } else { // here initial fraction can be <1
560 // max delay is set to the first sample time after max value
561 for(fi=0, n=fitdataNr-1, a=0.0; fi<fitdataNr; fi++)
562 if(dft.voi[0].y[fi]>=a) {a=dft.voi[0].y[fi]; n=fi;}
563 if(n<fitdataNr-1) n++;
564 pmax[delay_par_index]=dft.x[n];
565 }
566 } else {
567 /* Metabolite fractions are fitted with separated delay times */
568 /* Find highest and lowest parent fraction sample times,
569 and set max delay time to the time where fraction has fallen to half
570 of the difference */
571 m=0; n=fitdataNr-1; a=dft.voi[0].y[m]; b=dft.voi[0].y[n];
572 for(fi=0; fi<fitdataNr; fi++) {
573 if(dft.voi[0].y[fi]>=a) {m=fi; a=dft.voi[0].y[m];}
574 if(dft.voi[0].y[fi]<b) {n=fi; b=dft.voi[0].y[n];}
575 }
576 if(verbose>2) {
577 printf("max parent fraction %g at %g\n", a, dft.x[m]);
578 printf("min parent fraction %g at %g\n", b, dft.x[n]);
579 }
580 a=0.5*(a-b);
581 for(fi=m; fi<=n; fi++) if(dft.voi[0].y[fi]<=a) break;
582 if(verbose>2) printf("parent fraction dropped to %g at %g\n", a, dft.x[fi]);
583 pmax[delay_par_index]=dft.x[fi];
584 }
585 if(min_delay>=0 && pmin[delay_par_index]==pmax[delay_par_index]) {
586 pmax[delay_par_index]=1.5*pmin[delay_par_index];
587 if(pmax[delay_par_index]>dft.x[fitdataNr-1]) pmax[delay_par_index]=dft.x[fitdataNr-1];
588 }
589 if(pmax[delay_par_index]<pmin[delay_par_index]) pmax[delay_par_index]=pmin[delay_par_index];
590 /* Fix to user-defined values, if available */
591 for(pi=0; pi<parNr; pi++) {if(fixed_p[pi]>=0.0) pmin[pi]=pmax[pi]=fixed_p[pi];}
592 if(fixed0 && fabs(tstart)<1.0E-08) {
593 /* There might be more than one zero samples, thus get the mean */
594 double y0=0.0; int n=0;
595 for(int i=0; i<fitdataNr; i++) if(fabs(dft.x[i])<1.0E-08) {y0+=dft.voi[0].y[i]; n++;}
596 if(n>1) y0/=(double)n;
597 if(!(y0>0.0)) {
598 fprintf(stderr, "Warning: initial fraction is not fixed to sample zero.\n");
599 fflush(stderr);
600 } else {
601 if(verbose>1) {printf("Note: initial fraction fixed to %g\n", y0); fflush(stdout);}
602 pmin[iscale_par_index]=pmax[iscale_par_index]=y0;
603 if(fixed_p[iscale_par_index]>0.0) {
604 fprintf(stderr, "Warning: non-effective option -d for initial fraction.\n");
605 fflush(stderr);
606 }
607 }
608 }
609 /* If metabolites are fitted, then fix the parameter limits and number */
610 if(model==MODEL_MPF || model==MODEL_MHILL) {
611 /* Copy the same limits to the rest of parameters */
612 for(m=1; m<metabNr; m++) {
613 for(pi=0; pi<parNr-1; pi++) { // other parameters except delay
614 pmin[m*parNr+pi]=pmin[pi]; pmax[m*parNr+pi]=pmax[pi];}
615 // delay difference compared to the first
616 if(mdelay_joint==0) {
617 a=pmax[pi]-pmin[pi];
618 pmin[m*parNr+pi]=-0.5*a; pmax[m*parNr+pi]=+0.5*a;
619 } else {
620 pmin[m*parNr+pi]=0.0; pmax[m*parNr+pi]=0.0;
621 }
622 }
623 /* Nr of fitted parameters can be set only now */
624 parNr*=metabNr;
625 if(verbose>2) printf("final_parNr := %d\n", parNr);
626 }
627 if(verbose>1) {
628 printf("Constraints for the fit:\n");
629 for(pi=0; pi<parNr; pi++) printf(" limit[%d]: %g - %g\n", pi+1, pmin[pi], pmax[pi]);
630 fflush(stdout);
631 }
632
633
634 /*
635 * Check that sample number (not including NaNs) is at least one more
636 * than the number of actually fitted parameters.
637 */
638 for(fi=n=0; fi<fitdataNr; fi++) {
639 if(dft.x[fi]<0.0) continue;
640 if(!isnan(dft.voi[0].y[fi])) n++;
641 }
642 for(pi=m=0; pi<parNr; pi++) if(pmin[pi]<pmax[pi]) m++;
643 if(verbose>1) printf("Comparison of nr of samples and params to fit: %d / %d\n", n, m);
644 if((n-1)<m) {
645 fprintf(stderr, "Error: too few samples for fitting in %s\n", dfile);
646 if(verbose>0) printf("n := %d\nm := %d\n", n, m);
647 dftEmpty(&dft); fitEmpty(&fit); return(2);
648 }
649
650
651 /*
652 * Fit (one fit only)
653 */
654 if(verbose>1) {printf("preparing to fit.\n"); fflush(stdout);}
655 ri=0;
656 /* Set data pointers */
657 x=dft.x; w=dft.w; ymeas[0]=dft.voi[ri].y; yfit[0]=dft.voi[ri].y2;
658 for(m=0; m<metabNr; m++) {
659 ymeas[m+1]=dft.voi[m+1].y; yfit[m+1]=dft.voi[m+1].y2;
660 }
661 /* Set the initial value for WSS */
662 fit.voi[ri].wss=3.402823e+38;
663 /* fit */
664 if(verbose>1) printf("fitting\n");
666 TGO_LOCAL_OPT=0; // 0=Powell-Brent, 1=Bobyqa
667 TGO_SQUARED_TRANSF=1; //if(model==MODEL_GCDF) TGO_SQUARED_TRANSF=0;
668 int neighNr=6, iterNr=1, sampleNr=800;
669 if(model==MODEL_MPF || model==MODEL_PF) {
673 neighNr=5; iterNr=1; sampleNr=800;
674 }
675 ret=tgo(pmin, pmax, func_list[model], NULL, parNr, neighNr, &fit.voi[ri].wss,
676 fit.voi[ri].p, sampleNr, iterNr, verbose-8);
677 if(ret) {
678 fprintf(stderr, "Error %d in TGO.\n", ret);
679 dftEmpty(&dft); fitEmpty(&fit);
680 return(4);
681 }
682 if(verbose>4) {
683 printf("Results from tgo():\n");
684 for(pi=0; pi<parNr; pi++) printf(" parameter[%d] := %g\n", pi, fit.voi[ri].p[pi]);
685 printf("WSS := %g\n", fit.voi[ri].wss);
686 fflush(stdout);
687 }
688 fit.voi[ri].wss=lastWSS; // remove penalty from reported WSS (do not use a)
689 if(verbose>5) {printf("lastWSS := %g\n", lastWSS); fflush(stdout);}
690 /* Correct fitted parameters to match constraints like inside the function */
691 ri=0;
692 (void)modelCheckParameters(parNr, pmin, pmax, fit.voi[ri].p, fit.voi[ri].p, &a);
693 if(model==MODEL_HILL) { // Must be A<=D
694 if(fit.voi[ri].p[0]>fit.voi[ri].p[3]) fit.voi[ri].p[0]=fit.voi[ri].p[3];
695 } else if(model==MODEL_MHILL) {
696 n=parNr/metabNr;
697 for(m=0; m<metabNr; m++)
698 if(fit.voi[ri].p[m*n]>fit.voi[ri].p[m*n+3])
699 fit.voi[ri].p[m*n]=fit.voi[ri].p[m*n+3];
700 }
701 if(model==MODEL_MPF || model==MODEL_MHILL) { // delay can not be negative
702 n=parNr/metabNr;
703 for(m=1; m<metabNr; m++)
704 if( (fit.voi[ri].p[n-1]+fit.voi[ri].p[(m+1)*n-1]) < 0.0)
705 fit.voi[ri].p[(m+1)*n-1] = -fit.voi[ri].p[n-1];
706 }
707 /* Warn user about parameters that collide with limits */
708 if(verbose>5) {
709 printf("Corrected parameters:\n");
710 for(pi=0; pi<parNr; pi++) printf(" parameter[%d] := %g\n", pi, fit.voi[ri].p[pi]);
711 }
712 if(verbose>1) {
713 ret=modelCheckLimits(parNr, pmin, pmax, fit.voi[ri].p);
714 if(ret==0) {if(verbose>2) fprintf(stdout, "ok\n");}
715 else fprintf(stderr, "warning, fit collided with the limits.\n");
716 }
717 if(verbose>1) {fprintf(stdout, "WSS := %g\n", fit.voi[ri].wss); fflush(stdout);}
718 /* Print measured and fitted curve */
719 if(verbose>3) {
720 printf(" Measured Fitted Weight\n");
721 for(fi=0; fi<fitdataNr; fi++)
722 if(!isnan(ymeas[0][fi]))
723 printf(" %2d: %9.4e %9.4e %9.4e %7.1e\n", fi+1, x[fi], ymeas[0][fi], yfit[0][fi], w[fi]);
724 else
725 printf(" %2d: %9.4e %-9.9s %9.4e %7.1e\n", fi+1, x[fi], ".", yfit[0][fi], w[fi]);
726 printf(" fitted parameters:");
727 for(pi=0; pi<parNr; pi++) printf(" %g", fit.voi[ri].p[pi]);
728 printf("\n");
729 }
730 /* Check the MRL */
731 if(verbose>1) printf("Checking the MRL.\n");
732 fi=mrl_between_tacs(yfit[0], ymeas[0], fitdataNr);
733 if(fi>3 && fi>fitdataNr/3) {
734 if(MRL_check!=0) {
735 fprintf(stderr, "Error: bad fit.\n");
736 fprintf(stderr, "MRL := %d / %d\n", fi, fitdataNr);
737 dftEmpty(&dft); fitEmpty(&fit);
738 return(7);
739 }
740 }
741 if(fi>2 && fi>fitdataNr/4) {
742 fprintf(stderr, "Warning: bad fit.\n");
743 fprintf(stderr, "MRL := %d / %d\n", fi, fitdataNr);
744 } else if(verbose>1) {
745 printf("MRL test passed.\n");
746 if(verbose>2) fprintf(stderr, "MRL := %d / %d\n", fi, fitdataNr);
747 }
748 /* Calculate WSS for separate curves */
749 if(verbose>1) {
750 double wss[1+metabNr], f=0.0;
751 for(ai=0; ai<=metabNr; ai++) {
752 wss[ai]=0.0;
753 for(fi=0; fi<fitdataNr; fi++) {
754 a=dft.voi[ai].y[fi]-dft.voi[ai].y2[fi];
755 wss[ai]+=w[fi]*a*a;
756 }
757 f+=wss[ai]; printf("WSS[%d] := %g\n", ai+1, wss[ai]);
758 }
759 printf("WSS[total] := %g\n", f);
760 }
761 /* Calculate AIC */
762 if(verbose>1) {
763 ri=0;
764 for(ai=0, m=0; ai<=metabNr; ai++) if(frwgt[ai]>0.0)
765 for(fi=0; fi<fitdataNr; fi++) if(w[fi]>0.0) m++;
766 printf("nr_of_fitted_samples := %d\n", m);
767 for(pi=0, n=0; pi<parNr; pi++) if(pmax[pi]>pmin[pi]) n++;
768 printf("nr_of_fitted_parameters := %d\n", n);
769 aic=aicSS(fit.voi[ri].wss, m, n);
770 printf("AIC := %g\n", aic);
771 }
772 if(verbose>2) {
773 printf("Fitted parameters:\n");
774 ri=0;
775 for(pi=0; pi<parNr; pi++) printf(" par[%d]: %g\n", pi+1, fit.voi[ri].p[pi]);
776 if(verbose>4) for(pi=0; pi<parNr; pi++)
777 printf(" par[%d]: %g [%g, %g]\n", pi+1, fit.voi[ri].p[pi], pmin[pi], pmax[pi]);
778 }
779 /* In case of metabolite fitting, convert fitted delay parameter differences to actual delays */
780 if(model==MODEL_MPF || model==MODEL_MHILL) {
781 n=parNr/metabNr;
782 ri=0;
783 for(m=1; m<metabNr; m++) {
784 fit.voi[ri].p[(m+1)*n-1]+=fit.voi[ri].p[n-1];
785 }
786 }
787 /* Copy the parameters for metabolites, when necessary */
788 for(ri=1; ri<fit.voiNr; ri++) {
789 for(pi=0; pi<fit.voi[0].parNr; pi++) fit.voi[ri].p[pi]=fit.voi[0].p[pi];
790 fit.voi[ri].wss=fit.voi[0].wss;
791 }
792 /* In case of Hill function when function format #2 is required divide a with d */
793 if(model==MODEL_HILL && ffile_type==2) {
794 fit.voi[0].p[0]/=fit.voi[0].p[3];
795 }
796
797
798 /*
799 * Save fit results
800 */
801 if((verbose>1) && strcmp(ffile, "stdout")!=0) printf("saving results in %s\n", ffile);
802 ret=fitWrite(&fit, ffile); if(ret) {
803 fprintf(stderr, "Error (%d) in writing '%s': %s\n", ret, ffile, fiterrmsg);
804 dftEmpty(&dft); fitEmpty(&fit); return(11);
805 }
806 if(strcmp(ffile, "stdout")!=0 && verbose>0)
807 printf("Function parameters written in %s\n", ffile);
808
809
810 /*
811 * Plot fitted curves
812 */
813 if(svgfile[0]) {
814 if(verbose>1) printf("creating SVG plot\n");
815 DFT adft;
816 char tmp[FILENAME_MAX];
817
818 if(verbose>1) printf("calculating fitted curve at automatically generated sample times\n");
819 dftInit(&adft);
820 ret=dftAutointerpolate(&dft, &adft, 1.10*dft.x[dft.frameNr-1], verbose-7);
821 if(ret) {
822 fprintf(stderr, "Error %d in memory allocation for fitted curves.\n", ret);
823 dftEmpty(&dft); fitEmpty(&fit); dftEmpty(&adft);
824 return(13);
825 }
826 for(fi=0; fi<adft.frameNr; fi++) adft.w[fi]=1.0;
827 x=adft.x; w=adft.w;
828 for(ri=0; ri<adft.voiNr; ri++) {
829 yfit[ri]=adft.voi[ri].y;
830 ymeas[ri]=adft.voi[ri].y2;
831 }
832 // use library function
833 for(ri=0, ret=0; ri<adft.voiNr; ri++) {
834 for(fi=0; fi<adft.frameNr; fi++) {
835 ret=fitEval(&fit.voi[ri], adft.x[fi], &a); if(ret!=0) break;
836 adft.voi[ri].y[fi]=a;
837 }
838 if(ret!=0) break;
839 }
840 if(ret!=0) {
841 fprintf(stderr, "Error: cannot calculate fitted curve for '%s'.\n", svgfile);
842 dftEmpty(&dft); dftEmpty(&adft); fitEmpty(&fit);
843 return(14);
844 }
845
846 /* Save SVG plot of fitted and original data */
847 if(verbose>1) printf("writing %s\n", svgfile);
848 tpcProgramName(argv[0], 0, 0, tmp, 64); strcat(tmp, " ");
849 if(strlen(adft.studynr)>1) strcat(tmp, adft.studynr);
850 ret=plot_fitrange_svg(&dft, &adft, tmp, 0.0, nan(""), 0.0, 1.0, svgfile, verbose-8);
851 if(ret) {
852 fprintf(stderr, "Error (%d) in writing '%s'.\n", ret, svgfile);
853 dftEmpty(&adft); dftEmpty(&dft); fitEmpty(&fit);
854 return(30+ret);
855 }
856 if(verbose>0) printf("Plots written in %s\n", svgfile);
857
858 dftEmpty(&adft);
859 }
860
861 /* Free memory */
862 dftEmpty(&dft); fitEmpty(&fit);
863
864 return(0);
865}
866/*****************************************************************************/
867
868/******************************************************************************
869 *
870 * Functions to be minimized
871 *
872 *****************************************************************************/
873double func_pf(int parNr, double *p, void *fdata)
874{
875 int i;
876 double a, b, c, d, dt, v, f, wss;
877 double pa[MAX_PARAMETERS], penalty=1.0;
878
879 /* Check parameters against the constraints */
880 if(0) {
881 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
882 printf("\n");
883 }
884 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
885 if(fdata) {}
886 a=pa[0]; b=pa[1]; c=pa[2]; d=pa[3]; dt=pa[4];
887
888 /* Calculate the curve values and weighted SS */
889 f=pow(d, -1.0/c);
890 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
891 if(x[i]<=dt) yfit[0][i]=d;
892 else yfit[0][i]=pow(f+pow(a*(x[i]-dt), b), -c);
893 v=yfit[0][i]-ymeas[0][i];
894 if(min_meas==MINMEAS_LAD) v=fabs(v);
895 else if(min_meas==MINMEAS_OLS) v*=v;
896 else if(min_meas==MINMEAS_ODR) {
897 /* Calculate function derivative at x */
898 double df=0.0;
899 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);
900 if(!isfinite(df)) df=0.0;
901 /* Calculate Akaho distance */
902 v*=v; v/=(1.0 + df*df);
903 }
904 wss+=w[i]*v;
905 }
906 lastWSS=wss; wss*=penalty;
907 if(0) printf("%g %g %g %g %g -> %g\n", a, b, c, d, dt, wss);
908 return(wss);
909}
910
911double func_hill(int parNr, double *p, void *fdata)
912{
913 int i;
914 double a, b, c, d, dt, v, wss;
915 double pa[MAX_PARAMETERS], penalty=1.0;
916
917 /* Check parameters against the constraints */
918 if(0) {
919 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
920 printf("\n");
921 }
922 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
923 if(fdata) {}
924 a=pa[0]; b=pa[1]; c=pa[2]; d=pa[3]; dt=pa[4];
925 /* additional check: a<=d */
926 if(a>d) {
927 penalty+=100.0*(a/d);
928 a=d;
929 }
930
931 /* Calculate the curve values and weighted SS */
932 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
933 if(x[i]<=dt)
934 yfit[0][i]= d;
935 else {
936 double f=pow(x[i]-dt, b);
937 yfit[0][i]= d + (a-d)*f/(c+f);
938 }
939 v=yfit[0][i]-ymeas[0][i];
940 if(min_meas==MINMEAS_LAD) v=fabs(v);
941 else if(min_meas==MINMEAS_OLS) v*=v;
942 else if(min_meas==MINMEAS_ODR) {
943 /* Calculate function derivative at x */
944 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);
945 if(!isfinite(df)) df=0.0;
946 /* Calculate Akaho distance */
947 v*=v; v/=(1.0 + df*df);
948 }
949 wss+=w[i]*v;
950 }
951 lastWSS=wss; wss*=penalty; // needed because additional penalty is possible
952 //printf(" objfunc(): lastWSS=%g WSS=%g\n", lastWSS, wss);
953 if(0) printf("%g %g %g %g %g -> %g\n", a, b, c, d, dt, wss);
954 return(wss);
955}
956
957double func_gcdf(int parNr, double *p, void *fdata)
958{
959 int i;
960 double a, b, c, d, dt, v, wss;
961 double pa[MAX_PARAMETERS], penalty=1.0;
962
963 /* Check parameters against the constraints */
964 if(0) {
965 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
966 printf("\n");
967 }
968 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
969 if(fdata) {}
970 a=pa[0]; b=pa[1]; c=pa[2]; d=pa[3]; dt=pa[4];
971 /* Calculate the curve values and weighted SS */
972 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
973 if(x[i]<=dt)
974 yfit[0][i]=a;
975 else {
976 yfit[0][i]= a*(1.0-b*igam(d, c*(x[i]-dt)));
977 }
978 v=yfit[0][i]-ymeas[0][i];
979 if(min_meas==MINMEAS_LAD) v=fabs(v);
980 else v*=v;
981 wss+=w[i]*v;
982 //printf(" x=%g ymeas=%g yfit=%g v=%g wss=%g\n", x[i], ymeas[0][i], yfit[0][i], v, wss);
983 }
984 lastWSS=wss; wss*=penalty;
985 //printf(" objfunc(): lastWSS=%g WSS=%g\n", lastWSS, wss);
986 if(0) printf("%g %g %g %g %g -> %g\n", a, b, c, d, dt, wss);
987 return(wss);
988}
989
990double func_ep(int parNr, double *p, void *fdata) // Based on Mu et al 2020
991{
992 int i;
993 double a, b, c, d, dt, s, v, wss;
994 double pa[MAX_PARAMETERS], penalty=1.0;
995
996 /* Check parameters against the constraints */
997 if(0) {
998 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
999 printf("\n");
1000 }
1001 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
1002 if(fdata) {}
1003 dt=pa[0]; s=pa[1]; a=pa[2]; b=pa[3]; c=pa[4]; d=pa[5];
1004 /* Calculate the curve values and weighted SS */
1005 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
1006 double xt=x[i]-dt;
1007 if(xt<=0.0)
1008 yfit[0][i]=s;
1009 else {
1010 yfit[0][i]= a*exp(-b*xt*xt*xt/(xt*xt+c)) + (1.0-a)*exp(-d*xt);
1011 yfit[0][i]*=s;
1012 }
1013 v=yfit[0][i]-ymeas[0][i];
1014 if(min_meas==MINMEAS_LAD) v=fabs(v);
1015 else v*=v;
1016 wss+=w[i]*v;
1017 }
1018 lastWSS=wss; wss*=penalty;
1019 return(wss);
1020}
1021
1022double func_mpf(int parNr, double *p, void *fdata)
1023{
1024 int i, m, pn;
1025 double a[1+MAX_METAB_NR], b[1+MAX_METAB_NR], c[1+MAX_METAB_NR],
1026 d[1+MAX_METAB_NR], dt[1+MAX_METAB_NR];
1027 double pa[1+MAX_PARAMETERS], penalty=1.0;
1028 double mf[1+MAX_METAB_NR], g[1+MAX_METAB_NR], v, f, wss;
1029
1030 /* Check parameters against the constraints */
1031 if(0) {
1032 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
1033 printf("\n");
1034 }
1035 if(fdata) {}
1036 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
1037 pn=parNr/metabNr;
1038 for(m=0; m<metabNr; m++) {
1039 a[m]=pa[m*pn+0]; b[m]=pa[m*pn+1]; c[m]=pa[m*pn+2];
1040 d[m]=pa[m*pn+3]; dt[m]=pa[m*pn+4]; if(m>0) dt[m]+=dt[0];
1041 }
1042 for(; m<MAX_METAB_NR; m++) a[m]=b[m]=c[m]=d[m]=dt[m]=0.0;
1043 /* additional check: delay time should be positive */
1044 for(m=1; m<metabNr; m++) if(dt[m]<0.0) {
1045 penalty+=100.0*(-dt[m]); dt[m]=0.0;}
1046
1047 /* Calculate the curve values and weighted SS */
1048 for(m=0; m<metabNr; m++) g[m]=pow(d[m], -1.0/c[m]);
1049 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
1050 for(m=0; m<metabNr && m<=MAX_METAB_NR; m++) {
1051 if(x[i]<=dt[m]) mf[m]=1.0 - d[m];
1052 else mf[m]=1.0 - pow(g[m]+pow(a[m]*(x[i]-dt[m]), b[m]), -c[m]);
1053 }
1054 for(; m<MAX_METAB_NR; m++) mf[m]=0.0;
1055 yfit[0][i]=1.0;
1056 f=1.0-mf[0]*mf[1]-mf[0]*mf[2]-mf[1]*mf[2]+2.0*mf[0]*mf[1]*mf[2];
1057 yfit[1][i]=mf[0]*(1.0-mf[1]-mf[2]+mf[1]*mf[2])/f; yfit[0][i]-=yfit[1][i];
1058 if(metabNr>1) {
1059 yfit[2][i]=mf[1]*(1.0-mf[0]-mf[2]+mf[0]*mf[2])/f; yfit[0][i]-=yfit[2][i];
1060 }
1061 if(metabNr>2) {
1062 yfit[3][i]=mf[2]*(1.0-mf[0]-mf[1]+mf[0]*mf[1])/f; yfit[0][i]-=yfit[3][i];
1063 }
1064 for(m=0; m<=metabNr && m<=MAX_METAB_NR; m++) {
1065 v=yfit[m][i]-ymeas[m][i];
1066 if(min_meas==MINMEAS_OLS) v*=v; else v=fabs(v);
1067 wss+=w[i]*frwgt[m]*v;
1068 }
1069 }
1070 lastWSS=wss; wss*=penalty; // needed because additional penalty is possible
1071 //if(!isfinite(wss)) wss=nan("");
1072 return(wss);
1073}
1074
1075double func_mhill(int parNr, double *p, void *fdata)
1076{
1077 int i, m, pn;
1078 double a[1+MAX_METAB_NR], b[1+MAX_METAB_NR], c[1+MAX_METAB_NR],
1079 d[1+MAX_METAB_NR], dt[1+MAX_METAB_NR];
1080 double pa[1+MAX_PARAMETERS], penalty=1.0;
1081 double mf[1+MAX_METAB_NR], v, f, wss;
1082
1083 /* Check parameters against the constraints */
1084 if(0) {
1085 for(i=0; i<parNr; i++) printf(" p[%d]=%g", i, p[i]);
1086 printf("\n");
1087 }
1088 if(fdata) {}
1089 modelCheckParameters(parNr, pmin, pmax, p, pa, &penalty);
1090 pn=parNr/metabNr;
1091 for(m=0; m<metabNr; m++) {
1092 a[m]=pa[m*pn+0]; b[m]=pa[m*pn+1]; c[m]=pa[m*pn+2];
1093 d[m]=pa[m*pn+3]; dt[m]=pa[m*pn+4]; if(m>0) dt[m]+=dt[0];
1094 /* additional check: a<=d */
1095 if(a[m]>d[m]) {
1096 penalty+=100.0*(a[m]/d[m]);
1097 a[m]=d[m];
1098 }
1099 }
1100 for(; m<MAX_METAB_NR; m++) a[m]=b[m]=c[m]=d[m]=dt[m]=0.0;
1101 /* additional check: delay time should be positive */
1102 for(m=1; m<metabNr; m++) if(dt[m]<0.0) {
1103 penalty+=100.0*(-dt[m]); dt[m]=0.0;}
1104
1105 /* Calculate the curve values and weighted SS */
1106 for(i=0, wss=0.0; i<fitdataNr; i++) if(w[i]>0.0) {
1107 for(m=0; m<metabNr && m<=MAX_METAB_NR; m++) {
1108 if(x[i]<=dt[m])
1109 mf[m]=1.0 - d[m];
1110 else {
1111 f=pow(x[i]-dt[m], b[m]);
1112 mf[m]=1.0 - (d[m] + (a[m]-d[m])*f/(c[m]+f));
1113 }
1114 }
1115 for(; m<MAX_METAB_NR; m++) mf[m]=0.0;
1116 yfit[0][i]=1.0;
1117 f=1.0-mf[0]*mf[1]-mf[0]*mf[2]-mf[1]*mf[2]+2.0*mf[0]*mf[1]*mf[2];
1118 yfit[1][i]=mf[0]*(1.0-mf[1]-mf[2]+mf[1]*mf[2])/f; yfit[0][i]-=yfit[1][i];
1119 if(metabNr>1) {
1120 yfit[2][i]=mf[1]*(1.0-mf[0]-mf[2]+mf[0]*mf[2])/f; yfit[0][i]-=yfit[2][i];
1121 }
1122 if(metabNr>2) {
1123 yfit[3][i]=mf[2]*(1.0-mf[0]-mf[1]+mf[0]*mf[1])/f; yfit[0][i]-=yfit[3][i];
1124 }
1125 for(m=0; m<=metabNr && m<=MAX_METAB_NR; m++) {
1126 v=yfit[m][i]-ymeas[m][i];
1127 if(min_meas==MINMEAS_OLS) v*=v; else v=fabs(v);
1128 wss+=w[i]*frwgt[m]*v;
1129 }
1130 }
1131 lastWSS=wss; wss*=penalty; // needed because additional penalty is possible
1132 return(wss);
1133}
1134/*****************************************************************************/
1135
1136/*****************************************************************************/
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:1744
int fitEval(FitVOI *r, double x, double *y)
Definition mathfunc.c:618
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]