TPCCLIB
Loading...
Searching...
No Matches
fit2dat.c
Go to the documentation of this file.
1
9/*****************************************************************************/
10#include "tpcclibConfig.h"
11/*****************************************************************************/
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <math.h>
16#include <string.h>
17#include <time.h>
18/*****************************************************************************/
19#include "libtpcmisc.h"
20#include "libtpcmodel.h"
21#include "libtpccurveio.h"
22/*****************************************************************************/
23int FIT2DAT_MAXNR=50000;
24/*****************************************************************************/
25
26/*****************************************************************************/
27static char *info[] = {
28 "Calculates the PET time-activity curves (TACs) using parameters of",
29 "a mathematical function, which have been fitted to the data previously.",
30 " ",
31 "Usage: @P [Options] fitfile tacfile",
32 " ",
33 "Fitfile must be in the DFT fit format; it contains the parameters",
34 "of the functions fitted to one or more PET TACs. Fitfile specifications:",
35 "https://www.turkupetcentre.net/petanalysis/format_tpc_fit.html",
36 " ",
37 "Options:",
38 " -i Integrals of functions from zero to sample time are calculated;",
39 " not available for all functions.",
40 " -mid | -frames",
41 " Function values are calculated at frame mid times (default), or as",
42 " means between frame start and end times, when possible.",
43 " -stdoptions", // List standard options like --help, -v, etc
44 " ",
45 " The sample times, where function values are to be calculated, can",
46 " be specified with one of the following options:",
47 " -A[=<stop>]",
48 " autointerpolate the data from 0 to stop time, or to fit range end time",
49 " (default), with decreasing sample frequency.",
50 " -C=<start,stop,step>",
51 " specify the first and last sample time, and the sample frequence.",
52 " -F=<file>",
53 " specify a TAC file, which contains the time framing information.",
54 " -N=<nr>",
55 " specify the number of sample points between fit start and end times.",
56 " -X=<x1,x2,x3,...>",
57 " specify the sample times individually.",
58 " -R=<low,up,nr>",
59 " Specified nr of random x values between low and up are generated.",
60 " -RST=<low,up,nr>",
61 " Specified nr of random x values between low and up are generated",
62 " with distribution biased towards low absolute values.",
63 " ",
64 "See also: simframe, fit_ppf, fit_sinf, fit_sigm, metabcor, fit2res",
65 " ",
66 "Keywords: TAC, simulation, input, interpolation, extrapolation",
67 0};
68/*****************************************************************************/
69
70/*****************************************************************************/
71/* Turn on the globbing of the command line, since it is disabled by default in
72 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
73 In Unix&Linux wildcard command line processing is enabled by default. */
74/*
75#undef _CRT_glob
76#define _CRT_glob -1
77*/
78int _dowildcard = -1;
79/*****************************************************************************/
80
81/*****************************************************************************/
85int main(int argc, char **argv)
86{
87 int ai, help=0, version=0, verbose=1;
88 int ri, fi, xnr=0, rnr=0, integr=0, ret;
89 int useFrames=0; // 0=no, 1=yes if possible
90 FIT fit;
91 DFT dft;
92 char *cptr, fitfile[FILENAME_MAX], datafile[FILENAME_MAX],
93 xfile[FILENAME_MAX], tmp[FILENAME_MAX];
94 double numbers[FIT2DAT_MAXNR], a, b, c, d, aiendtime=-9.9;
95
96
97
98 /* Set seed for random number generator */
99 drandSeed(1);
100
101
102 /*
103 * Get arguments
104 */
105 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
106 fitfile[0]=datafile[0]=xfile[0]=(char)0;
107 fitInit(&fit); dftInit(&dft);
108 /* Options */
109 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
110 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
111 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
112 if(strcasecmp(cptr, "I")==0) {
113 integr=1; continue;
114 } else if(strcasecmp(cptr, "MID")==0) {
115 useFrames=0; continue;
116 } else if(strcasecmp(cptr, "FRAMES")==0) {
117 useFrames=1; continue;
118 } else if(strncasecmp(cptr, "X", 1)==0) {
119 cptr++; if(*cptr=='=') cptr++;
120 if(xnr>0 || strlen(xfile)) {fprintf(stderr, "Error: invalid x value(s).\n"); return(1);}
121 /* Separate x values specified */
122 strcpy(tmp, cptr); cptr=strtok(tmp, ";,:|");
123 while(cptr!=NULL && xnr<FIT2DAT_MAXNR) {
124 numbers[xnr++]=atof_dpi(cptr); cptr=strtok(NULL, ";,:|");}
125 if(xnr<1) {tpcPrintUsage(argv[0], info, stderr); return 1;}
126 /* Sort the numbers */
127 for(ri=0; ri<xnr; ri++) for(fi=ri+1; fi<xnr; fi++)
128 if(numbers[ri]>numbers[fi]) {d=numbers[fi]; numbers[fi]=numbers[ri]; numbers[ri]=d;}
129 continue;
130 } else if(strncasecmp(cptr, "C=", 2)==0) {
131 cptr+=2;
132 if(xnr>0 || strlen(xfile)) {fprintf(stderr, "Error: invalid x value(s).\n"); return(1);}
133 /* Start, stop and step for x values */
134 a=b=c=0.; strcpy(tmp, cptr); cptr=strtok(tmp, ";,");
135 if(cptr!=NULL) {a=atof_dpi(cptr); cptr=strtok(NULL, ";,:|");}
136 if(cptr!=NULL) {b=atof_dpi(cptr); cptr=strtok(NULL, ";,:|");}
137 if(cptr!=NULL) {c=atof_dpi(cptr);}
138 if(a>=b || c<1.0E-14) {fprintf(stderr, "Error: invalid x value(s).\n"); return(1);}
139 double v=a;
140 for(xnr=0; v<(b+0.2*c) && xnr<FIT2DAT_MAXNR; v=a+c*(double)xnr) numbers[xnr++]=v;
141 continue;
142 } else if(strncasecmp(cptr, "R=", 2)==0) {
143 cptr+=2;
144 if(xnr>0 || rnr>0 || strlen(xfile)) {
145 fprintf(stderr, "Error: invalid x value(s).\n"); return(1);}
146 /* Lower and Upper limit and Nr of x values */
147 a=b=0.; xnr=0; strcpy(tmp, cptr); cptr=strtok(tmp, ";,");
148 if(cptr!=NULL) {a=atof_dpi(cptr); cptr=strtok(NULL, ";,:|");}
149 if(cptr!=NULL) {b=atof_dpi(cptr); cptr=strtok(NULL, ";,:|");}
150 if(cptr!=NULL) {xnr=atoi(cptr);}
151 if(a>=b || xnr<=0 || xnr>FIT2DAT_MAXNR) {
152 fprintf(stderr, "Error: invalid x value(s).\n"); return(1);}
153 rand_range(xnr, numbers, a, b, 0);
154 continue;
155 } else if(strncasecmp(cptr, "RST=", 4)==0) {
156 cptr+=4;
157 if(xnr>0 || rnr>0 || strlen(xfile)) {
158 fprintf(stderr, "Error: invalid x value(s).\n"); return(1);}
159 /* Lower and Upper limit and Nr of x values */
160 a=b=0.; xnr=0; strcpy(tmp, cptr); cptr=strtok(tmp, ";,");
161 if(cptr!=NULL) {a=atof_dpi(cptr); cptr=strtok(NULL, ";,:|");}
162 if(cptr!=NULL) {b=atof_dpi(cptr); cptr=strtok(NULL, ";,:|");}
163 if(cptr!=NULL) {xnr=atoi(cptr);}
164 if(a>=b || xnr<=0 || xnr>FIT2DAT_MAXNR) {
165 fprintf(stderr, "Error: invalid x value(s).\n"); return(1);}
166 rand_range(xnr, numbers, a, b, 1);
167 continue;
168 } else if(strncasecmp(cptr, "F=", 2)==0) {
169 cptr+=2;
170 if(xnr>0 || strlen(xfile)) {fprintf(stderr, "Error: invalid x value(s).\n"); return(1);}
171 /* X values are given in a DFT file */
172 strcpy(xfile, cptr);
173 continue;
174 } else if(strncasecmp(cptr, "N=", 2)==0) {
175 cptr+=2;
176 if(xnr>0 || strlen(xfile)) {fprintf(stderr, "Error: invalid x value(s).\n"); return(1);}
177 /* The nr of x values between fit start and end */
178 rnr=atoi(cptr);
179 if(rnr<2) {fprintf(stderr, "Error: invalid nr of x values.\n"); return 1;}
180 continue;
181 } else if(strcasecmp(cptr, "A")==0) {
182 aiendtime=0.0; continue;
183 } else if(strncasecmp(cptr, "A=", 2)==0) {
184 cptr+=2;
185 if(xnr>0 || strlen(xfile)) {fprintf(stderr, "Error: invalid x value(s).\n"); return(1);}
186 /* Try to get the time for stopping autointerpolation */
187 aiendtime=atof_dpi(cptr); if(aiendtime>0.0) continue;
188 }
189 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
190 return(1);
191 } else break;
192
193 /* Print help or version? */
194 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
195 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
196 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
197
198 /* Process other arguments, starting from the first non-option */
199 for(; ai<argc; ai++) {
200 if(!fitfile[0]) {strcpy(fitfile, argv[ai]); continue;}
201 else if(!datafile[0]) {strcpy(datafile, argv[ai]); continue;}
202 /* we should never get this far */
203 fprintf(stderr, "Error: too many arguments: '%s'.\n", argv[ai]);
204 return(1);
205 }
206 if(verbose>2) MATHFUNC_TEST=verbose-2; else MATHFUNC_TEST=0;
207
208 /* Is something missing? */
209 if(!fitfile[0]) {
210 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
211 return(1);
212 }
213 if(xnr<1 && rnr<1 && !strlen(xfile) && aiendtime<0.0) {
214 aiendtime=0.0; // autointerpolate sample times based on fit time range
215 }
216 if(integr) useFrames=0; // not applicable to integrals
217
218 /* In verbose mode print arguments and options */
219 if(verbose>1) {
220 printf("fitfile := %s\n", fitfile);
221 printf("datafile := %s\n", datafile);
222 printf("xfile := %s\n", xfile);
223 printf("integr := %d\n", integr);
224 printf("useFrames := %d\n", useFrames);
225 printf("x :=");
226 for(ri=0; ri<xnr; ri++) printf(" %g", numbers[ri]);
227 printf("\n");
228 printf("rnr := %d\n", rnr);
229 printf("aiendtime := %g\n", aiendtime);
230 }
231 if(verbose>3) {
232 printf("Available functions:\n");
233 for(ri=1; ri<2000; ri++) {
234 if(!fitFunctionname(ri, tmp)) printf("%04d: %s\n", ri, tmp);
235 if(!fitFunctionformat(ri, tmp)) printf(" %s\n", tmp);
236 }
237 }
238
239 /*
240 * Read fits
241 */
242 if(verbose>1) printf("Reading fitfile\n");
243 if((ret=fitRead(fitfile, &fit, verbose-2))) {
244 fprintf(stderr, "Error %d in reading '%s': %s\n", ret, fitfile, fiterrmsg);
245 return(4);
246 }
247 if(verbose>10) fitPrint(&fit);
248
249
250 /*
251 * Make data for calculated function values
252 */
253 /* If xfile was specified, read it, and form the data out of it */
254 if(strlen(xfile)) {
255 if(verbose>1) printf("Reading x values from file %s\n", xfile);
256 if(dftRead(xfile, &dft)) {
257 fprintf(stderr, "Error in reading '%s': %s\n", xfile, dfterrmsg);
258 fitEmpty(&fit); return(3);
259 }
260 /* Allocate memory for all regions */
261 if(verbose>2) printf("Allocating more memory.\n");
262 if(dftAddmem(&dft, fit.voiNr)) {
263 fprintf(stderr, "Memory allocation error.\n");
264 fitEmpty(&fit); return(3);
265 }
266 for(ri=0; ri<dft.voiNr; ri++) for(fi=0; fi<dft.frameNr; fi++)
267 dft.voi[ri].y[fi]=dft.voi[ri].y2[fi]=dft.voi[ri].y3[fi]=0.0;
268 dft.voiNr=fit.voiNr;
269 } else if(xnr>0) { /* If x values were specified, allocate memory for data */
270 if(dftSetmem(&dft, xnr, fit.voiNr)) {
271 fprintf(stderr, "Memory allocation error.\n");
272 fitEmpty(&fit); return(3);
273 }
274 dft.voiNr=fit.voiNr; dft.frameNr=xnr;
275 for(fi=0; fi<xnr; fi++) dft.x[fi]=numbers[fi];
277 } else if(rnr>0) { /* Just the number of x values was specified */
278 if(dftSetmem(&dft, rnr, fit.voiNr)) {
279 fprintf(stderr, "Memory allocation error.\n");
280 fitEmpty(&fit); return(3);
281 }
282 dft.voiNr=fit.voiNr; dft.frameNr=rnr;
283 a=fit.voi[0].start; b=fit.voi[0].end;
284 for(ri=1; ri<fit.voiNr; ri++) {
285 if(fit.voi[ri].start<a) a=fit.voi[ri].start;
286 if(fit.voi[ri].end>b) b=fit.voi[ri].end;
287 }
288 c=(b-a)/(double)(rnr-1); for(fi=0; fi<rnr; fi++) dft.x[fi]=a+c*(double)fi;
290 } else if(aiendtime>=0.0) { /* If autointerpolation was selected */
291 /* find the fit time range */
292 a=fit.voi[0].start; b=fit.voi[0].end;
293 for(ri=1; ri<fit.voiNr; ri++) {
294 if(fit.voi[ri].start<a) a=fit.voi[ri].start;
295 if(fit.voi[ri].end>b) b=fit.voi[ri].end;
296 }
297 /* set autointerpolation end time, if it was not specified */
298 if(aiendtime<=0.0 || aiendtime<=a) aiendtime=b;
299 /* calculate the nr of interpolated data points */
300 c=0.0; d=0.02; rnr=1;
301 while(c+d<aiendtime && rnr<9999) {c+=d; d*=1.05; rnr++;}
302 d=aiendtime-c; c=aiendtime; rnr++;
303 /* allocate memory */
304 if(dftSetmem(&dft, rnr, fit.voiNr)) {
305 fprintf(stderr, "Memory allocation error.\n");
306 fitEmpty(&fit); return(3);
307 }
308 dft.voiNr=fit.voiNr; dft.frameNr=rnr;
309 /* set times */
311 c=0.0; d=0.02; fi=0; dft.x[fi++]=c;
312 while(c+d<aiendtime && rnr<9999) {c+=d; d*=1.05; dft.x[fi++]=c;}
313 d=aiendtime-c; c=aiendtime; dft.x[fi++]=c; dft.frameNr=fi;
314 rnr=0;
315 } else {
316 fprintf(stderr, "Error: invalid arguments.\n");
317 fitEmpty(&fit); return(3);
318 }
319 /* Copy header info from fit data to TAC data */
320 dft.isweight=0; sprintf(dft.comments, "# %s: %s\n", "fit2dat", fitfile);
321 strcpy(dft.unit, fit.unit); dft.timeunit=fit.timeunit;
322 for(ri=0; ri<dft.voiNr; ri++) {
323 strlcpy(dft.voi[ri].name, fit.voi[ri].name, MAX_REGIONNAME_LEN+1);
324 strlcpy(dft.voi[ri].voiname, fit.voi[ri].voiname, MAX_REGIONSUBNAME_LEN+1);
326 strlcpy(dft.voi[ri].place, fit.voi[ri].place, MAX_REGIONSUBNAME_LEN+1);
327 dft.voi[ri].size=0.0;
328 }
329 if(strlen(dft.studynr)<1) studynr_from_fname(datafile, dft.studynr);
330 /* Set datafile format to pure data, if only one region with no name */
331 if(fit.voiNr==1 && !strlen(fit.voi[0].voiname)) dft._type=0; else dft._type=1;
332
333 if(verbose>3) {
334 printf("X values:\n");
335 if(dft.timetype==DFT_TIME_STARTEND) for(fi=0; fi<dft.frameNr; fi++)
336 printf(" %03d: %8.4f - %8.4f mid %8.4f\n", fi+1, dft.x1[fi], dft.x2[fi], dft.x[fi]);
337 else for(fi=0; fi<dft.frameNr; fi++)
338 printf(" %03d: mid %8.4f\n", fi+1, dft.x[fi]);
339 }
340
341
342 /*
343 * Calculate TACs
344 */
345 if(dft.timetype!=DFT_TIME_STARTEND) useFrames=0;
346 ret=0;
347 if(integr) { // Integral from zero requested
348 for(ri=0; ri<fit.voiNr && !ret; ri++) {
349 ret=fitIntegralEvaltac(&fit.voi[ri], dft.x, dft.voi[ri].y, dft.frameNr);
350 }
351 } else if(useFrames) {
352 for(ri=0; ri<fit.voiNr && !ret; ri++) {
353 ret=fitEvaltacframes(&fit.voi[ri], dft.x1, dft.x2, dft.voi[ri].y, dft.frameNr);
354 // in case of an error, try frame mid times
355 if(ret) ret=fitEvaltac(&fit.voi[ri], dft.x, dft.voi[ri].y, dft.frameNr);
356 }
357 } else { // Function value at certain time points requested
358 for(ri=0; ri<fit.voiNr && !ret; ri++) {
359 ret=fitEvaltac(&fit.voi[ri], dft.x, dft.voi[ri].y, dft.frameNr);
360 }
361 }
362 if(ret) {
363 fprintf(stderr, "Error: cannot evaluate function.\n");
364 dftEmpty(&dft); fitEmpty(&fit); return(7);
365 }
366
367 /* In specific case:
368 Add Ta and Ti as comments, if just one TAC, and if included as function parameters */
369 if(fit.voiNr==1 && (fit.voi[0].type==331 || fit.voi[0].type==332)) {
370 sprintf(tmp, "# Ta := %g\n# Ti := %g\n", fit.voi[0].p[0], fit.voi[0].p[1]);
371 strcat(dft.comments, tmp);
372 }
373
374 /*
375 * Write output data
376 */
378 /* Set file format to PMOD, if extension is .tac or .bld */
379 {
380 char *cptr=filenameGetExtension(datafile);
381 if(!strcasecmp(cptr, ".tac") || !strcasecmp(cptr, ".bld"))
383 }
384 /* Write to file or stdout */
385 if(strlen(datafile)) ret=dftWrite(&dft, datafile);
386 else {dftWrite(&dft, "stdout"); ret=0;}
387 if(ret) {
388 fprintf(stderr, "Error in writing output: %s\n", dfterrmsg);
389 dftEmpty(&dft); fitEmpty(&fit); return(11);
390 }
391 if(verbose>0) fprintf(stdout, " %s written.\n", datafile);
392
393
394 /* Free memory */
395 fitEmpty(&fit); dftEmpty(&dft);
396
397 return(0);
398}
399/*****************************************************************************/
400
401/*****************************************************************************/
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 dftSetmem(DFT *data, int frameNr, int voiNr)
Definition dft.c:57
void dftEmpty(DFT *data)
Definition dft.c:20
int dftRead(char *filename, DFT *data)
Definition dftio.c:22
int DFT_NR_OF_DECIMALS
Definition dftio.c:13
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
char * filenameGetExtension(char *s)
Get the last extension of a filename.
Definition filename.c:139
int rand_range(int nr, double *d, double low, double up, int type)
Definition gaussdev.c:159
unsigned int drandSeed(short int seed)
Make and optionally set the seed for rand(), drand, drandRange, and drandGaussian().
Definition gaussdev.c:63
Header file for libtpccurveio.
#define DFT_FORMAT_PMOD
#define DFT_TIME_MIDDLE
int fitEvaltac(FitVOI *r, double *x, double *y, int dataNr)
Definition mathfunc.c:1234
void fitEmpty(FIT *fit)
Definition mathfunc.c:18
int fitRead(char *filename, FIT *fit, int verbose)
Definition mathfunc.c:196
int fitIntegralEvaltac(FitVOI *r, double *x, double *yi, int dataNr)
Definition mathfunc.c:1512
int MATHFUNC_TEST
Definition mathfunc.c:5
int fitFunctionformat(int type, char *str)
Definition mathfunc.c:351
char fiterrmsg[64]
Definition mathfunc.c:6
void fitInit(FIT *fit)
Definition mathfunc.c:38
#define DFT_TIME_STARTEND
int fitEvaltacframes(FitVOI *r, double *x1, double *x2, double *y, int dataNr)
Definition mathfunc.c:1536
int fitFunctionname(int type, char *str)
Definition mathfunc.c:511
void fitPrint(FIT *fit)
Definition mathfunc.c:180
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
#define MAX_REGIONNAME_LEN
Definition libtpcmisc.h:154
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
int studynr_from_fname(char *fname, char *studynr)
Definition studynr.c:119
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
#define MAX_REGIONSUBNAME_LEN
Definition libtpcmisc.h:158
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
Header file for libtpcmodel.
int _type
int timetype
Voi * voi
int timeunit
char studynr[MAX_STUDYNR_LEN+1]
double * x1
char comments[_DFT_COMMENT_LEN+1]
int voiNr
double * x2
int frameNr
int isweight
double * x
char unit[MAX_UNITS_LEN+1]
int timeunit
int voiNr
char unit[MAX_UNITS_LEN+1]
FitVOI * voi
double end
char place[MAX_REGIONSUBNAME_LEN+1]
char hemisphere[MAX_REGIONSUBNAME_LEN+1]
char voiname[MAX_REGIONSUBNAME_LEN+1]
char name[MAX_REGIONNAME_LEN+1]
double start
double p[MAX_FITPARAMS]
double size
double * y2
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
char name[MAX_REGIONNAME_LEN+1]
double * y3
char hemisphere[MAX_REGIONSUBNAME_LEN+1]
char place[MAX_REGIONSUBNAME_LEN+1]