TPCCLIB
Loading...
Searching...
No Matches
fit_line.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <math.h>
13#include <string.h>
14#include <time.h>
15/*****************************************************************************/
16#include "libtpcmisc.h"
17#include "libtpcmodel.h"
18#include "libtpccurveio.h"
19#include "libtpcsvg.h"
20#include "libtpcmodext.h"
21/*****************************************************************************/
22
23/*****************************************************************************/
24static char *info[] = {
25 "Fits line to PET tissue time-activity curves (TACs).",
26 "Data may contain missing values. Data is not weighted in the fit.",
27 " ",
28 "Usage: @P [Options] tacfile starttime endtime resultfile",
29 " ",
30 "Options:",
31 " -svg=<Filename>",
32 " Fitted and measured TACs are plotted in specified SVG file.",
33 " -stdoptions", // List standard options like --help, -v, etc
34 " ",
35 "Program writes the slope, y axis intercept, Pearson's correlation",
36 "coefficient, and standard deviations to the result file, or,",
37 "intercept and slope into FIT format file if given with extension .fit.",
38 " ",
39 "See also: fit_exp, tacln, tacinv, rescoll, fit2dat, tac2svg",
40 " ",
41 "Keywords: curve fitting, TAC, correlation, clearance, extrapolation",
42 0};
43/*****************************************************************************/
44
45/*****************************************************************************/
46/* Turn on the globbing of the command line, since it is disabled by default in
47 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
48 In Unix&Linux wildcard command line processing is enabled by default. */
49/*
50#undef _CRT_glob
51#define _CRT_glob -1
52*/
53int _dowildcard = -1;
54/*****************************************************************************/
55
56/*****************************************************************************/
60int main(int argc, char **argv)
61{
62 int ai, help=0, version=0, verbose=1;
63 int fi, pi, ri, type=MF_LINE, ret, dataNr;
64 char *cptr, datfile[FILENAME_MAX], outfile[FILENAME_MAX],
65 svgfile[FILENAME_MAX];
66 DFT dft;
67 RES res;
68 double tstart, tstop, minx, maxx, miny, maxy;
69
70
71 /*
72 * Get arguments
73 */
74 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
75 datfile[0]=outfile[0]=svgfile[0]=(char)0;
76 tstart=tstop=nan("");
77 dftInit(&dft); resInit(&res);
78 /* Options */
79 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
80 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
81 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
82 if(strncasecmp(cptr, "SVG=", 4)==0 && strlen(cptr)>4) {
83 strcpy(svgfile, cptr+4); if(strlen(svgfile)>0) continue;
84 }
85 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
86 return(1);
87 } else break;
88
89 /* Print help or version? */
90 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
91 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
92 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
93
94 /* Process other arguments, starting from the first non-option */
95 for(; ai<argc; ai++) {
96 if(!datfile[0]) {strcpy(datfile, argv[ai]); continue;}
97 else if(isnan(tstart)) {if(atof_with_check(argv[ai], &tstart)==0) continue;}
98 else if(isnan(tstop)) {if(atof_with_check(argv[ai], &tstop)==0) continue;}
99 else if(!outfile[0]) {strcpy(outfile, argv[ai]); continue;}
100 fprintf(stderr, "Error: invalid argument '%s'\n", argv[ai]);
101 return(1);
102 }
103
104 /* Is something missing? */
105 if(!outfile[0]) {
106 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
107 return(1);
108 }
109 if(tstop<tstart || (tstart!=0.0 && tstart==tstop)) {
110 fprintf(stderr, "Error: invalid time range.\n");
111 return(1);
112 }
113
114 /* In verbose mode print arguments and options */
115 if(verbose>1) {
116 printf("datfile := %s\n", datfile);
117 printf("outfile := %s\n", outfile);
118 printf("svgfile := %s\n", svgfile);
119 printf("required_tstart := %g\n", tstart);
120 printf("required_tstop := %g\n", tstop);
121 }
122
123
124 /*
125 * Read data
126 */
127 if(verbose>1) printf("reading %s\n", datfile);
128 if(dftRead(datfile, &dft)) {
129 fprintf(stderr, "Error in reading '%s': %s\n", datfile, dfterrmsg);
130 return(2);
131 }
132 if(dft.frameNr<2) {
133 fprintf(stderr, "Error: not enough samples for line fitting.\n");
134 dftEmpty(&dft); return(3);
135 }
136
137 /* Sort the samples by time in case data is catenated from several curves */
138 (void)dftSortByFrame(&dft);
139 if(verbose>30) dftPrint(&dft);
140
141 /* Get the data ranges */
142 ret=dftMinMax(&dft, &minx, &maxx, &miny, &maxy);
143 if(ret!=0 || isnan(minx) || isnan(miny)) {
144 fprintf(stderr, "Error: invalid contents in %s\n", datfile);
145 dftEmpty(&dft); return(2);
146 }
147 if(verbose>1) {
148 printf("xrange := %g - %g\n", minx, maxx);
149 printf("yrange := %g - %g\n", miny, maxy);
150 }
151 if(minx>=maxx) {
152 fprintf(stderr, "Error: invalid data for line fitting.\n");
153 dftEmpty(&dft); return(2);
154 }
155 /* Check or set user-defined time range */
156 if(tstart==tstop) {
157 tstart=minx; tstop=maxx;
158 } else {
159 if(tstart>=maxx || tstop<=minx) {
160 fprintf(stderr, "Error: invalid time range for the data.\n");
161 dftEmpty(&dft); return(2);
162 }
163 }
164 if(verbose>1) {
165 printf("tstart := %g\n", tstart);
166 printf("tstop := %g\n", tstop);
167 }
168 /* Get the nr of valid samples in x,y data inside the time range */
169 dataNr=dftValidNr(&dft, tstart, tstop, -1);
170 if(dataNr<2) {
171 fprintf(stderr, "Error: invalid time range for the data.\n");
172 dftEmpty(&dft); return(2);
173 }
174 if(verbose>1) printf("dataNr := %d\n", dataNr);
175
176 /*
177 * Allocate memory for results
178 */
179 if(verbose>1) printf("allocating memory for results.\n");
180 if(res_allocate_with_dft(&res, &dft)!=0) {
181 fprintf(stderr, "Error: cannot setup memory for results.\n");
182 dftEmpty(&dft); resEmpty(&res); return(3);
183 }
184 /* Copy titles & filenames */
185 tpcProgramName(argv[0], 1, 1, res.program, 128);
186 strncpy(res.datafile, datfile, FILENAME_MAX);
187 sprintf(res.datarange, "%g - %g %s", tstart, tstop, petTunit(dft.timeunit));
188 res.datanr=dataNr;
189 res.time=time(NULL);
190 res.isweight=0;
191 /* Set the parameter names */
192 res.parNr=3;
193 pi=0; strcpy(res.parname[pi], "Intercept"); strcpy(res.parunit[pi], dft.unit);
194 pi++; strcpy(res.parname[pi], "Slope"); strcpy(res.parunit[pi], petCunit(CUNIT_UNITLESS));
195 pi++; strcpy(res.parname[pi], "r"); strcpy(res.parunit[pi], petCunit(CUNIT_UNITLESS));
196
197
198 /*
199 * Fit line to each TAC
200 */
201 if(verbose>1) printf("fitting\n");
202 double f;
203 for(ri=ret=0; ri<dft.voiNr; ri++) {
204 if(verbose>1 && dft.voiNr>1) printf("%s\n", dft.voi[ri].name);
205 ret=pearson4(dft.x, dft.voi[ri].y, dft.frameNr, tstart, tstop,
206 &res.voi[ri].parameter[1], &res.voi[ri].sd[1],
207 &res.voi[ri].parameter[0], &res.voi[ri].sd[0],
208 &res.voi[ri].parameter[2], &f);
209 if(ret!=0) break;
210 } /* next TAC */
211 if(ret) {
212 fprintf(stderr, "Error: cannot fit line to TAC %d\n", 1+ri);
213 dftEmpty(&dft); resEmpty(&res); return(4);
214 }
215
216
217 /*
218 * Print results on screen
219 */
220 if(verbose>0) {
221 printf("\n");
222 resWrite(&res, "stdout", 0);
223 printf("\n");
224 }
225
226
227 /*
228 * Save results
229 */
230 if(verbose>1) printf("saving results\n");
231 cptr=strrchr(outfile, '.');
232 if(cptr!=NULL && strcasecmp(cptr, ".FIT")==0) {
233 if(verbose>2) printf("... in FIT format\n");
234 /* Copy results into FIT struct */
235 FIT fit; fitInit(&fit);
236 if(fit_allocate_with_dft(&fit, &dft)!=0) {
237 fprintf(stderr, "Error: cannot allocate space for fits.\n");
238 dftEmpty(&dft); resEmpty(&res); fitEmpty(&fit); return(5);
239 }
240 fit.voiNr=dft.voiNr;
241 strncpy(fit.datafile, res.datafile, FILENAME_MAX);
242 tpcProgramName(argv[0], 1, 1, fit.program, 1024);
243 strcpy(fit.unit, dft.unit);
244 fit.time=res.time;
245 for(ri=0; ri<dft.voiNr; ri++) {
246 fit.voi[ri].type=type; fit.voi[ri].parNr=2;
247 fit.voi[ri].start=tstart; fit.voi[ri].end=tstop;
248 fit.voi[ri].dataNr=dataNr;
249 fit.voi[ri].p[0]=res.voi[ri].parameter[0];
250 fit.voi[ri].p[1]=res.voi[ri].parameter[1];
251 }
252 /* Write fit file */
253 if(fitWrite(&fit, outfile)) {
254 fprintf(stderr, "Error in writing '%s': %s\n", outfile, fiterrmsg);
255 dftEmpty(&dft); resEmpty(&res); fitEmpty(&fit); return(11);
256 }
257 fitEmpty(&fit);
258 } else {
259 if(verbose>2) printf("... in RES format\n");
260 ret=resWrite(&res, outfile, verbose-3);
261 if(ret) {
262 fprintf(stderr, "Error in writing '%s': %s\n", outfile, reserrmsg);
263 dftEmpty(&dft); resEmpty(&res);
264 return(11);
265 }
266 }
267 if(verbose>0) printf("line fits written in %s\n", outfile);
268
269
270 /*
271 * Plotting of fitted TACs, if requested
272 */
273 if(svgfile[0]) {
274 if(verbose>1) printf("saving SVG plot\n");
275
276 /* Create a DFT containing fitted TACs */
277 char tmp[128];
278 DFT dft2;
279 dftInit(&dft2); ret=dftdup(&dft, &dft2);
280 if(ret) {
281 fprintf(stderr, "Error: cannot plot fitted curves.\n");
282 dftEmpty(&dft); resEmpty(&res);
283 return(21);
284 }
285 dft2.frameNr=2;
287 dft2.x[0]=tstart; dft2.x[1]=tstop;
288 for(ri=0; ri<dft.voiNr; ri++) for(fi=0; fi<dft.frameNr; fi++) {
289 dft2.voi[ri].y[fi]=res.voi[ri].parameter[0] +
290 res.voi[ri].parameter[1]*dft2.x[fi];
291 }
292 /* Save SVG plot of fitted and original data */
293 tpcProgramName(argv[0], 0, 0, tmp, 64); strcat(tmp, " ");
294 if(strlen(dft2.studynr)>1) strcat(tmp, dft.studynr);
295 ret=plot_fit_svg(&dft, &dft2, tmp, svgfile, verbose-8);
296 if(ret) {
297 fprintf(stderr, "Error (%d) in writing '%s'.\n", ret, svgfile);
298 dftEmpty(&dft2); dftEmpty(&dft); resEmpty(&res);
299 return(30+ret);
300 }
301 if(verbose>0) printf("Plots written in %s\n", svgfile);
302 dftEmpty(&dft2);
303 }
304
305 /* Free memory */
306 dftEmpty(&dft); resEmpty(&res);
307
308 return(0);
309}
310/*****************************************************************************/
311
312/*****************************************************************************/
314
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
void dftInit(DFT *data)
Definition dft.c:38
int dftdup(DFT *dft1, DFT *dft2)
Definition dft.c:655
char dfterrmsg[64]
Definition dft.c:6
int dftSortByFrame(DFT *dft)
Definition dft.c:1169
int dftMinMax(DFT *dft, double *minx, double *maxx, double *miny, double *maxy)
Definition dft.c:974
int dftValidNr(DFT *dft, double tstart, double tstop, int index)
Definition dft.c:1638
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
int res_allocate_with_dft(RES *res, DFT *dft)
Definition dftres.c:14
int fit_allocate_with_dft(FIT *fit, DFT *dft)
Definition fitres.c:14
Header file for libtpccurveio.
char reserrmsg[64]
Definition result.c:6
void resInit(RES *res)
Definition result.c:52
#define DFT_TIME_MIDDLE
void fitEmpty(FIT *fit)
Definition mathfunc.c:18
int fitWrite(FIT *fit, char *filename)
Definition mathfunc.c:54
int resWrite(RES *res, char *filename, int verbose)
Definition result.c:565
char fiterrmsg[64]
Definition mathfunc.c:6
void fitInit(FIT *fit)
Definition mathfunc.c:38
void resEmpty(RES *res)
Definition result.c:22
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
char * petCunit(int cunit)
Definition petunits.c:211
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
Definition proginfo.c:101
char * petTunit(int tunit)
Definition petunits.c:226
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 pearson4(double *x, double *y, int nr, double start, double end, double *k, double *kSD, double *b, double *bSD, double *r, double *ySD)
Calculate slope and intercept of a line and Pearson's correlation coefficient.
Definition pearson.c:198
Header file for libtpcmodext.
int plot_fit_svg(DFT *dft1, DFT *dft2, char *main_title, char *fname, int verbose)
Definition plotfit.c:216
Header file for libtpcsvg.
int timetype
Voi * voi
int timeunit
char studynr[MAX_STUDYNR_LEN+1]
int voiNr
int frameNr
double * x
char unit[MAX_UNITS_LEN+1]
int voiNr
char datafile[FILENAME_MAX]
char program[1024]
char unit[MAX_UNITS_LEN+1]
FitVOI * voi
time_t time
double end
double start
double p[MAX_FITPARAMS]
int parNr
char parname[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
int datanr
ResVOI * voi
char program[1024]
char datarange[128]
int isweight
char datafile[FILENAME_MAX]
char parunit[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
time_t time
double parameter[MAX_RESPARAMS]
double sd[MAX_RESPARAMS]
double * y
char name[MAX_REGIONNAME_LEN+1]