10#include "tpcclibConfig.h"
30double func_dmsurge(
int parNr,
double *p,
void*);
32typedef struct FITDATA {
50static char *info[] = {
51 "Fitting of the sum of surge functions and delay time",
52 "to time-activity curves (TACs).",
56 " f(x) = Sum of Ai*(x-dt)*exp(-Ki*(x-dt)) where i=1..N",
58 "Usage: @P [Options] tacfile [parfile]",
62 " Maximum number of surge functions (1<=n<=10); by default 5.",
64 " Maximum K value (kmax>kmin). By default 10.0.",
66 " Minimum K value (>0). By default, kMax*1.0E-10.",
68 " Number of basis functions, used in determination of initial parameter",
69 " estimates and number of exponentials for nonlinear fitting;",
71 " -dt=<min,max,step> | -dt=delay",
72 " The range and step size of precision of time delay estimation, or",
75 " All weights are set to 1.0 (no weighting); by default, weights in",
76 " data file are used, if available.",
78 " Weight by sampling interval.",
80 " Non-linear LSQ fit (default), or only linear LSQ fit; In case of NLLSQ,",
81 " LLSQ is still performed first to obtain initial parameter values.",
83 " Fitted and measured TACs are plotted in specified SVG file.",
85 " Fitted TACs are written in specified TAC file.",
88 "Function parameters are written the format determined by file name extension.",
89 "PET time frames are used in fitting, if available in TAC file.",
91 "See also: fit_feng, fit_suri, fit_gvar, fit2dat, tacframe, fitdt",
93 "Keywords: TAC, curve fitting",
112int main(
int argc,
char **argv)
114 int ai, help=0, version=0, verbose=1;
115 char tacfile[FILENAME_MAX], parfile[FILENAME_MAX], svgfile[FILENAME_MAX], fitfile[FILENAME_MAX];
129 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
130 tacfile[0]=parfile[0]=svgfile[0]=fitfile[0]=(char)0;
131 for(
int i=0; i<3; i++) dtRange[i]=nan(
"");
133 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
135 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
136 if(strcasecmp(cptr,
"W1")==0) {
138 }
else if(strcasecmp(cptr,
"WF")==0) {
140 }
else if(strncasecmp(cptr,
"N=", 2)==0) {
141 if(
atoiCheck(cptr+2, &maxSurgeNr)==0 && maxSurgeNr>0 && maxSurgeNr<=10)
continue;
142 fprintf(stderr,
"Error: invalid option for number of surge functions '%s'.\n", argv[ai]);
144 }
else if(strncasecmp(cptr,
"BFNR=", 5)==0) {
145 if(
atoiCheck(cptr+5, &bfNr)==0 && bfNr>5)
continue;
146 }
else if(strncasecmp(cptr,
"KMIN=", 5)==0) {
148 }
else if(strncasecmp(cptr,
"KMAX=", 5)==0) {
150 }
else if(strncasecmp(cptr,
"DT=", 3)==0) {
151 int n=
atofList(cptr+3,
",", dtRange, 3);
153 dtRange[1]=dtRange[0]; dtRange[2]=0.0;
continue;
155 if(dtRange[0]<dtRange[1] && dtRange[2]<0.2*(dtRange[1]-dtRange[0]))
continue;
157 fprintf(stderr,
"Error: invalid delay time option '%s'.\n", argv[ai]);
159 }
else if(strcasecmp(cptr,
"NLLSQ")==0) {
161 }
else if(strcasecmp(cptr,
"LLSQ")==0) {
163 }
else if(strncasecmp(cptr,
"SVG=", 4)==0 && strlen(cptr)>4) {
164 strlcpy(svgfile, cptr+4, FILENAME_MAX);
continue;
165 }
else if(strncasecmp(cptr,
"FIT=", 4)==0 && strlen(cptr)>4) {
166 strlcpy(fitfile, cptr+4, FILENAME_MAX);
continue;
168 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
177 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
182 if(ai<argc)
strlcpy(tacfile, argv[ai++], FILENAME_MAX);
183 if(ai<argc)
strlcpy(parfile, argv[ai++], FILENAME_MAX);
185 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
190 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
194 if(!isfinite(kMin)) kMin=kMax*1.0E-10;
195 else if(!(kMax>kMin)) {
196 fprintf(stderr,
"Error: invalid k limits.\n");
203 printf(
"tacfile := %s\n", tacfile);
204 if(parfile[0]) printf(
"parfile := %s\n", parfile);
205 if(svgfile[0]) printf(
"svgfile := %s\n", svgfile);
206 if(fitfile[0]) printf(
"fitfile := %s\n", fitfile);
207 printf(
"nllsq := %d\n", nllsq);
208 printf(
"maxSurgeNr := %d\n", maxSurgeNr);
209 printf(
"bfNr := %d\n", bfNr);
210 printf(
"kmin := %g\n", kMin);
211 printf(
"kmax := %g\n", kMax);
212 if(isfinite(dtRange[0]))
213 printf(
"dtMin := %g\ndtMax := %g\ndtStep :=%g\n", dtRange[0], dtRange[1], dtRange[2]);
214 printf(
"weights := %d\n",
weights);
223 if(verbose>1) printf(
"reading %s\n", tacfile);
231 printf(
"tacNr := %d\n", tac.
tacNr);
232 printf(
"sampleNr := %d\n", tac.
sampleNr);
235 printf(
"isframe := %d\n", tac.
isframe);
238 fprintf(stderr,
"Error: file contains no data.\n");
242 fprintf(stderr,
"Error: too few samples.\n");
247 fprintf(stderr,
"Error: data contains missing values.\n");
256 for(
int i=0; i<tac.
sampleNr; i++) tac.
w[i]=1.0;
260 for(
int i=0; i<tac.
sampleNr; i++) tac.
w[i]=1.0;
273 double ymin, ymax, xmin, xmax;
274 tacYRange(&tac, 0, &ymin, &ymax, NULL, NULL, NULL, NULL);
277 printf(
" fitrange_minv := %g\n", ymin);
278 printf(
" fitrange_maxv := %g\n", ymax);
279 printf(
" fitrange_minx := %g\n", xmin);
280 printf(
" fitrange_maxx := %g\n", xmax);
283 fprintf(stderr,
"Error: invalid sample times.\n");
289 double dx=tac.
x[i]-tac.
x[i-1];
290 if(dx>0.0 && dx<sdist) sdist=dx;
292 if(verbose>1) printf(
"sdist := %g\n", sdist);
294 if(!isfinite(dtRange[0])) {
295 dtRange[1]=0.1*(xmax-xmin);
296 dtRange[0]=-dtRange[1];
297 dtRange[2]=0.01*(dtRange[1]-dtRange[0]);
300 printf(
"dtMin := %g\ndtMax := %g\ndtStep :=%g\n", dtRange[0], dtRange[1], dtRange[2]);
308 if(fitfile[0] || svgfile[0]) {
309 if(verbose>1) printf(
"allocating space for fitted TTACs\n");
311 fprintf(stderr,
"Error: cannot allocate space for fitted TACs.\n");
327 par.
parNr=1+2*maxSurgeNr;
330 sprintf(par.
n[0].
name,
"dT");
332 for(
int i=1; i<par.
parNr; i+=2) {
333 sprintf(par.
n[i].
name,
"a%d", 1+i/2);
334 sprintf(par.
n[i+1].
name,
"k%d", 1+i/2);
344 for(
int ci=0; ci<tac.
tacNr; ci++) {
345 if(verbose>1 && tac.
tacNr>1) printf(
"linear fitting of TAC %s\n", tac.
c[ci].
name);
348 double pa[bfNr], pk[bfNr], yfit[tac.
sampleNr], dt=nan(
"");
352 dtRange[0], dtRange[1], dtRange[2],
353 pk, pa, &dt, yfit, &status);
356 dtRange[0], dtRange[1], dtRange[2],
357 pk, pa, &dt, yfit, &status);
363 printf(
"delta_t := %g\n", dt);
364 printf(
"solutions for each k:\n");
365 for(
int bi=0; bi<bfNr; bi++) printf(
"\t%g\t%g\n", pk[bi], pa[bi]);
368 if(verbose>2) printf(
"refining parameters of Spectral analysis\n");
369 double kMin2, kMax2, dtRange2[3];
374 if(kMax2<6.0*kMin2) {kMax2*=3.0; kMin2*=0.75;
if(kMin2<kMin) kMin2=kMin;}
375 dtRange2[0]=dt-2.0*dtRange[2];
if(dtRange2[0]<dtRange[0]) dtRange2[0]=dtRange[0];
376 dtRange2[1]=dt+2.0*dtRange[2];
if(dtRange2[1]>dtRange[1]) dtRange2[1]=dtRange[1];
377 dtRange2[2]=0.02*(dtRange2[1]-dtRange2[0]);
379 printf(
" refined kMin := %g\n refined kMax := %g\n", kMin2, kMax2);
380 printf(
" refined delay range and step size : %g %g %g\n", dtRange2[0], dtRange2[1], dtRange2[2]);
384 dtRange2[0], dtRange2[1], dtRange2[2],
385 pk, pa, &dt, yfit, &status);
388 dtRange2[0], dtRange2[1], dtRange2[2],
389 pk, pa, &dt, yfit, &status);
395 printf(
"refined delta_t := %g\n", dt);
396 printf(
"refined solutions for each k:\n");
397 for(
int bi=0; bi<bfNr; bi++) printf(
"\t%g\t%g\n", pk[bi], pa[bi]);
400 for(
int i=0; i<tac.
sampleNr; i++) ftac.
c[ci].
y[i]=yfit[i];
404 if(verbose>3) printf(
"aMax := %g\n", aMax);
408 if(verbose>2) printf(
"fbfNr := %d\n", fbfNr);
410 fprintf(stderr,
"Error: cannot estimate initial parameters.\n");
416 if(surgeNr>maxSurgeNr) surgeNr=maxSurgeNr;
417 if(verbose>1) printf(
"surgeNr := %d\n", surgeNr);
418 int localParNr=1+2*surgeNr;
419 if(localParNr>maxParNr) maxParNr=localParNr;
422 double init_k[surgeNr], init_a[surgeNr];
425 fprintf(stderr,
"Error: cannot estimate initial parameters.\n");
429 printf(
"\n\tClustered a and k values\n");
430 for(
int i=0; i<surgeNr; i++) printf(
"\t%g\t%g\n", init_a[i], init_k[i]);
431 printf(
"\n"); fflush(stdout);
441 par.
r[ci].
fitNr=2*surgeNr;
if(dtRange[2]>0.0) par.
r[ci].
fitNr++;
443 for(
int i=0, pi=1; i<surgeNr && pi<par.
parNr; i++, pi+=2) par.
r[ci].
p[pi]=init_a[i];
444 for(
int i=0, pi=2; i<surgeNr && pi<par.
parNr; i++, pi+=2) par.
r[ci].
p[pi]=init_k[i];
445 for(
int i=localParNr; i<par.
parNr; i++) par.
r[ci].
p[i]=0.0;
454 fprintf(stderr,
"Error: cannot calculate fitted TAC.\n");
458 double v=tac.
c[ci].
y[i]-yfit[i];
459 par.
r[ci].
wss+=tac.
w[i]*v*v;
463 if(ftac.
tacNr>0)
for(
int i=0; i<tac.
sampleNr; i++) ftac.
c[ci].
y[i]=yfit[i];
469 if(nllsq==0 && ftac.
tacNr>0) {
475 fprintf(stderr,
"Error: cannot calculate fitted TAC.\n");
489 for(
int ci=0; ci<tac.
tacNr; ci++) {
490 if(verbose>1 && tac.
tacNr>1) printf(
"non-linear fitting of TAC %s\n", tac.
c[ci].
name);
491 double final_wss=0.0;
500 for(
unsigned int i=0; i<ipar.
totalNr; i++) ipar.
xfull[i]=par.
r[ci].
p[i];
505 for(
unsigned int i=1; i<ipar.
totalNr; i++) {
520 printf(
"Initial parameters for optimization:\n");
526 ipar.
_fun=func_dmsurge;
530 if(!tac.
isframe) {fitdata.x=tac.
x; fitdata.x2=NULL;}
else {fitdata.x=tac.
x1; fitdata.x2=tac.
x2;}
531 fitdata.ymeas=tac.
c[ci].
y;
532 fitdata.ysim=ftac.
c[ci].
y;
537 printf(
" initial_wss := %g\n", initial_wss);
538 if(!isfinite(initial_wss)) {
539 fprintf(stderr,
"Error: invalid initial parameter guess.\n");
544 if(verbose>2) {printf(
"starting nonlinear optimization\n"); fflush(stdout);}
545 if(verbose>3) printf(
"1st non-linear optimization\n");
553 printf(
"measured and fitted TAC:\n");
555 printf(
"\t%g\t%g\n", tac.
c[ci].
y[i], ftac.
c[ci].
y[i]);
557 if(verbose>3) printf(
" final_wss := %g\n", final_wss);
559 for(
unsigned int i=1; i<ipar.
totalNr; i++) {
563 if(verbose>3) printf(
"2nd non-linear optimization\n");
571 printf(
"measured and fitted TAC:\n");
573 printf(
"\t%g\t%g\n", tac.
c[ci].
y[i], ftac.
c[ci].
y[i]);
575 if(verbose>3) printf(
" final_wss := %g\n", final_wss);
578 for(
unsigned int i=0; i<ipar.
totalNr; i++)
580 par.
r[ci].
wss=final_wss;
597 iftPut(&par.
h,
"datafile", tacfile, 0, NULL);
603 iftPut(&par.
h,
"program", buf, 0, NULL);
607 if(verbose>1) printf(
" saving %s\n", parfile);
608 FILE *fp=fopen(parfile,
"w");
610 fprintf(stderr,
"Error: cannot open file for writing.\n");
619 if(verbose>0) printf(
"function parameters saved in %s\n", parfile);
628 if(verbose>1) printf(
"saving SVG plot\n");
630 fprintf(stderr,
"Error: cannot plot fitted data.\n");
634 if(verbose>0) printf(
"Plots written in %s.\n", svgfile);
641 if(verbose>1) printf(
"writing %s\n", fitfile);
642 FILE *fp; fp=fopen(fitfile,
"w");
644 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", fitfile);
655 if(verbose>0) printf(
"fitted TACs saved in %s.\n", fitfile);
669double func_dmsurge(
int parNr,
double *p,
void *fdata)
671 FITDATA *d=(FITDATA*)fdata;
675 if(
mfEvalFrameY(
"dmsurge", parNr, p, d->n, d->x, d->x2, d->ysim, 0))
return(nan(
""));
677 if(
mfEvalY(
"dmsurge", parNr, p, d->n, d->x, d->ysim, 0))
return(nan(
""));
680 for(
unsigned i=0; i<d->n; i++) {
681 double v=d->ysim[i]-d->ymeas[i];
int spectralBFNr(double *k, double *a, const int n)
int spectralKRange(double *k, double *a, const int n, double *kmin, double *kmax, TPCSTATUS *status)
int spectralBFExtract(double *k, double *a, const int n, double *ke, double *ae, const int ne)
int spectralDMSurge(const double *x, const double *x2, const double *y, double *w, const int sNr, const double kMin, const double kMax, const int fNr, const double dtMin, const double dtMax, const double dtStep, double *k, double *a, double *dtEst, double *yfit, TPCSTATUS *status)
char * ctime_r_int(const time_t *t, char *buf)
Convert calendar time t into a null-terminated string of the form YYYY-MM-DD hh:mm:ss,...
double atofVerified(const char *s)
int atofList(const char *s1, const char *s2, double *x, int maxn)
unsigned int doubleMaxIndex(double *a, const unsigned int n)
int mfEvalY(const char *fid, const int parNr, const double *p, const int sampleNr, const double *x, double *y, const int verbose)
int mfEvalFrameY(const char *fid, const int parNr, const double *p, const int sampleNr, const double *x1, const double *x2, double *y, const int verbose)
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
int atoiCheck(const char *s, int *v)
unsigned int modelCodeIndex(const char *s)
void nloptInit(NLOPT *nlo)
int nloptAllocate(NLOPT *nlo, unsigned int parNr)
unsigned int nloptFixedNr(NLOPT *d)
void nloptFree(NLOPT *nlo)
void nloptWrite(NLOPT *d, FILE *fp)
char * parFormattxt(parformat c)
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
int parFormatFromExtension(const char *s)
int parAllocateWithTAC(PAR *par, TAC *tac, int parNr, TPCSTATUS *status)
Allocate PAR based on data in TAC.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
void tpcPrintBuild(const char *program, FILE *fp)
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
int nloptSimplex(NLOPT *nlo, unsigned int maxIter, TPCSTATUS *status)
void statusInit(TPCSTATUS *s)
char * errorMsg(tpcerror e)
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
double(* _fun)(int, double *, void *)
IFT h
Optional (but often useful) header information.
char name[MAX_PARNAME_LEN+1]
char name[MAX_TACNAME_LEN+1]
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacDuplicate(TAC *tac1, TAC *tac2)
Make a duplicate of TAC structure.
int tacPlotFitSVG(TAC *tac1, TAC *tac2, const char *main_title, const double x1, const double x2, const double y1, const double y2, const char *fname, TPCSTATUS *status)
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
char * tacFormattxt(tacformat c)
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
int tacSortByTime(TAC *d, TPCSTATUS *status)
int tacIsWeighted(TAC *tac)
unsigned int tacWSampleNr(TAC *tac)
int tacWByFreq(TAC *tac, isotope isot, TPCSTATUS *status)
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
int tacYRange(TAC *d, int i, double *ymin, double *ymax, int *smin, int *smax, int *imin, int *imax)
Get the range of y values (concentrations) in TAC struct.
Header file for libtpcbfm.
Header file for library libtpcextensions.
weights
Is data weighted, or are weight factors available with data?
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
char * unitName(int unit_code)
Header file for library libtpcift.
@ ISOTOPE_UNKNOWN
Unknown.
Header file for libtpclinopt.
Header file for library libtpcnlopt.
Header file for libtpcpar.
@ PAR_FORMAT_FIT
Function fit format of Turku PET Centre.
@ PAR_FORMAT_UNKNOWN
Unknown format.
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Header file for libtpcrand.
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Header file for libtpctacmod.