TPCCLIB
Loading...
Searching...
No Matches
taclkup.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 <string.h>
15#include <math.h>
16/*****************************************************************************/
17#include "tpcextensions.h"
18#include "tpcift.h"
19#include "tpctac.h"
20#include "tpcpar.h"
21#include "tpctacmod.h"
22/*****************************************************************************/
23#define LKUP_HIST_NR 25
24/*****************************************************************************/
25
26/*****************************************************************************/
27static char *info[] = {
28 "Replace the y values in TAC file with the values from a given",
29 "look-up table.",
30 "The look-up table must contain two columns: program looks from the first",
31 "column a matching value for the TAC y value, and replaces the y",
32 "value with the value from the second column of the table.",
33 "Look-up table must be sorted in ascending order.",
34 " ",
35 "Usage: @P [options] TAC lkupfile outputfile",
36 " ",
37 "Output file is written in TAC file format, unless filename",
38 "extension is *.res or *.par.",
39 " ",
40 "Options:",
41 " -c[losest]",
42 " If exact match in look-up table is not found, the closest value",
43 " is selected; by default, value is interpolated from the table.",
44 " -his=<Filename>",
45 " Histogram of the results is written in TAC format in specified file.",
46 " -stdoptions", // List standard options like --help, -v, etc
47 " ",
48 "See also: arlkup, imglkup, dftinteg, taccalc, tacunit, tacsety",
49 " ",
50 "Keywords: look-up table, autoradiography, ARG, perfusion, blood flow, radiowater",
51 0};
52/*****************************************************************************/
53
54/*****************************************************************************/
55/* Turn on the globbing of the command line, since it is disabled by default in
56 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
57 In Unix&Linux wildcard command line processing is enabled by default. */
58/*
59#undef _CRT_glob
60#define _CRT_glob -1
61*/
62int _dowildcard = -1;
63/*****************************************************************************/
64
65/*****************************************************************************/
69int main(int argc, char **argv)
70{
71 int ai, help=0, version=0, verbose=1;
72 char tacfile[FILENAME_MAX], lkupfile[FILENAME_MAX], resfile[FILENAME_MAX],
73 hisfile[FILENAME_MAX];
74 char *cptr;
75 int takeClosest=0;
76 int ret, i, j, n;
77
78
79 /*
80 * Get arguments
81 */
82 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
83 tacfile[0]=lkupfile[0]=resfile[0]=hisfile[0]=(char)0;
84 /* Options */
85 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
86 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
87 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
88 if(strncasecmp(cptr, "CLOSEST", 1)==0) {
89 takeClosest=1; continue;
90 } else if(strncasecmp(cptr, "HIS=", 4)==0) {
91 strlcpy(hisfile, cptr+4, FILENAME_MAX); if(strlen(hisfile)>0) continue;
92 }
93 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
94 return(1);
95 } else break;
96
97 TPCSTATUS status; statusInit(&status);
98 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
99 status.verbose=verbose-3;
100
101 /* Print help or version? */
102 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
103 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
104 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
105
106 /* Process other arguments, starting from the first non-option */
107 if(ai<argc) strlcpy(tacfile, argv[ai++], FILENAME_MAX);
108 if(ai<argc) strlcpy(lkupfile, argv[ai++], FILENAME_MAX);
109 if(ai<argc) strlcpy(resfile, argv[ai++], FILENAME_MAX);
110 if(ai<argc) {
111 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
112 return(1);
113 }
114 /* Did we get all the information that we need? */
115 if(!resfile[0]) {
116 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
117 return(1);
118 }
119
120
121 /* In verbose mode print arguments and options */
122 if(verbose>1) {
123 printf("tacfile := %s\n", tacfile);
124 printf("lkupfile := %s\n", lkupfile);
125 printf("resfile := %s\n", resfile);
126 if(hisfile[0]) printf("hisfile := %s\n", hisfile);
127 printf("takeClosest := %d\n", takeClosest);
128 }
129
130
131
132 /*
133 * Read the look-up table
134 */
135 if(verbose>1) printf("reading %s\n", lkupfile);
136 TAC lkup; tacInit(&lkup);
137 ret=tacRead(&lkup, lkupfile, &status);
138 if(ret!=TPCERROR_OK) {
139 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
140 tacFree(&lkup); return(2);
141 }
142 if(verbose>2) {
143 printf("lkup.fileformat := %s\n", tacFormattxt(lkup.format));
144 printf("lkup.tacNr := %d\n", lkup.tacNr);
145 printf("lkup.sampleNr := %d\n", lkup.sampleNr);
146 printf("lkup.xunit := %s\n", unitName(lkup.tunit));
147 printf("lkup.yunit := %s\n", unitName(lkup.cunit));
148 }
149 if(lkup.tacNr>1 || lkup.sampleNr<2) {
150 fprintf(stderr, "Error: invalid look-up table %s\n", lkupfile);
151 tacFree(&lkup); return(2);
152 }
153 /* Check for missing values */
154 if(tacNaNs(&lkup)>0) {
155 fprintf(stderr, "Error: missing look-up table values.\n");
156 tacFree(&lkup); return(2);
157 }
158 /* Set simpler pointers to look-up data */
159 int tableSize=lkup.sampleNr;
160 double *table1=lkup.x;
161 double *table2=lkup.c[0].y;
162 if(verbose>1) {
163 printf("Look-up y: %g - %g\n", table2[0], table2[tableSize-1]);
164 printf("Look-up x: %g - %g\n", table1[0], table1[tableSize-1]);
165 }
166
167
168 /*
169 * Read the TAC file
170 */
171 if(verbose>1) printf("reading %s\n", tacfile);
172 TAC tac; tacInit(&tac);
173 ret=tacRead(&tac, tacfile, &status);
174 if(ret!=TPCERROR_OK) {
175 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
176 tacFree(&lkup); tacFree(&tac); return(3);
177 }
178 if(verbose>2) {
179 printf("tac.fileformat := %s\n", tacFormattxt(tac.format));
180 printf("tac.tacNr := %d\n", tac.tacNr);
181 printf("tac.sampleNr := %d\n", tac.sampleNr);
182 printf("tac.xunit := %s\n", unitName(tac.tunit));
183 printf("tac.yunit := %s\n", unitName(tac.cunit));
184 }
185
186
187 /*
188 * Prepare histogram data
189 */
190 if(verbose>1) printf("allocating memory for the histogram\n");
191 TAC hist; tacInit(&hist);
192 ret=tacAllocate(&hist, LKUP_HIST_NR, 1);
193 if(ret!=TPCERROR_OK) {
194 fprintf(stderr, "Error: cannot allocate memory for histogram.\n");
195 tacFree(&lkup); tacFree(&tac); return(4);
196 }
197 hist.tacNr=1; hist.sampleNr=LKUP_HIST_NR;
198 hist.format=TAC_FORMAT_PMOD; hist.isframe=1;
199 hist.tunit=lkup.cunit; hist.cunit=UNIT_UNITLESS;
200 strcpy(hist.c[0].name, "n");
201 /* Calculate histogram bins and initiate the histogram values */
202 double histogram_bin=(table2[tableSize-1]-table2[0])/(double)LKUP_HIST_NR;
203 if(verbose>2) printf("histogram_bin_size := %g\n", histogram_bin);
204 hist.x1[0]=table2[0]; hist.x2[0]=hist.x1[0]+histogram_bin;
205 for(i=1; i<hist.sampleNr; i++) {
206 hist.x1[i]=hist.x2[i-1];
207 hist.x2[i]=hist.x1[i]+histogram_bin;
208 }
209 for(i=0; i<hist.sampleNr; i++) hist.c[0].y[i]=0.0;
210
211
212 /*
213 * Replace TAC y values with numbers from the look-up table
214 */
215 if(verbose>1) fprintf(stdout, "using look-up table\n");
216 double v;
217 int low, high, mid;
218 for(i=0; i<tac.tacNr; i++) for(j=0; j<tac.sampleNr; j++) {
219 v=tac.c[i].y[j]; //printf("%g ->\n", v);
220 if(isnan(v)) continue;
221 if(v<table1[0]) { /* check if below table values */
222 v=table2[0];
223 //hist.c[0].y[0]+=1.0;
224 } else if(v>table1[tableSize-1]) { /* check if over table values */
225 v=table2[tableSize-1];
226 //hist.c[0].y[hist.sampleNr-1]+=1.0;
227 } else { /* binary search */
228 low=mid=0; high=tableSize-1; ret=1;
229 while(low<=high) {
230 mid=(low+high)/2;
231 if(v<table1[mid]) high=mid-1;
232 else if(v>table1[mid]) low=mid+1;
233 else {v=table2[mid]; ret=0; break;}
234 }
235 /* If not found, get the closest/interpolated value */
236 if(ret) {
237 n=high; high=low; low=n;
238 if(takeClosest) {
239 if(v-table1[low]<table1[high]-v) v=table2[low];
240 else v=table2[high];
241 } else {
242 v=table2[low]+
243 (v-table1[low])*(table2[high]-table2[low])
244 /(table1[high]-table1[low]);
245 }
246 }
247 /* Add to histogram data */
248 for(n=0; n<hist.sampleNr; n++)
249 if(v>=hist.x1[n] && v<=hist.x2[n]) {
250 hist.c[0].y[n]+=1.0; break;
251 }
252 }
253 tac.c[i].y[j]=v; //printf(" %g\n", v);
254 } /* next y */
255
256 /* Copy the unit */
257 tac.cunit=lkup.cunit;
258
259 /* No need for look-up table anymore */
260 tacFree(&lkup);
261
262
263 /*
264 * Save the modified file
265 */
266 if(verbose>1) printf("writing %s\n", resfile);
267 /* If filename extension is .res or .par, then save in RES/PAR format,
268 otherwise in original TAC format */
269 int format=0;
270 cptr=strrchr(resfile, '.'); if(cptr!=NULL) cptr++;
271 if(strcasecmp(cptr, "RES")==0) format=PAR_FORMAT_RES;
272 else if(strcasecmp(cptr, "PAR")==0) format=PAR_FORMAT_CSV_UK;
273 else if(strncasecmp(cptr, "HTML", 3)==0) format=PAR_FORMAT_HTML;
274 /* Open file for writing */
275 FILE *fp; fp=fopen(resfile, "w");
276 if(fp==NULL) {
277 fprintf(stderr, "Error: cannot open file for writing (%s)\n", resfile);
278 tacFree(&tac); tacFree(&hist); return(11);
279 }
280 if(format==0) {
281 /* Write as TAC file */
282 ret=tacWrite(&tac, fp, TAC_FORMAT_UNKNOWN, 0, &status);
283 } else {
284 /* Copy TAC data into a new parameter struct */
285 PAR par; parInit(&par);
286 ret=tacToPAR(&tac, &par, &status);
287 if(ret==TPCERROR_OK)
288 ret=parWrite(&par, fp, format, 1, &status);
289 parFree(&par);
290 }
291 fclose(fp); tacFree(&tac);
292 if(ret!=TPCERROR_OK) {
293 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
294 tacFree(&hist); return(12);
295 }
296 if(verbose>0) printf("Converted data saved in %s.\n", resfile);
297
298
299 /*
300 * Save or print the histogram, if required
301 */
302 if(!hisfile[0] && verbose<=1) {
303 tacFree(&hist); return(0);
304 }
305 if(hisfile[0]) {
306 if(verbose>1) printf("writing %s\n", hisfile);
307 fp=fopen(hisfile, "w");
308 if(fp==NULL) {
309 fprintf(stderr, "Error: cannot open file for writing (%s)\n", hisfile);
310 tacFree(&hist); return(21);
311 }
312 } else {
313 fp=stdout; printf("\nHistogram:\n"); fflush(stdout);
314 }
315 /* Write histogram as TAC file */
316 ret=tacWrite(&hist, fp, TAC_FORMAT_UNKNOWN, 0, &status);
317 tacFree(&hist); if(hisfile[0]) fclose(fp);
318 if(ret!=TPCERROR_OK) {
319 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
320 return(22);
321 }
322 if(verbose>0 && hisfile[0]) printf("Histogram saved in %s.\n", hisfile);
323
324 return(0);
325}
326/*****************************************************************************/
327
328/*****************************************************************************/
void parFree(PAR *par)
Definition par.c:75
void parInit(PAR *par)
Definition par.c:25
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
Definition pario.c:148
int tacToPAR(TAC *tac, PAR *par, TPCSTATUS *status)
Copy the contents of TAC struct into PAR struct.
Definition partac.c:169
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:169
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:339
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:114
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
char * errorMsg(tpcerror e)
Definition statusmsg.c:68
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
Definition tpcpar.h:100
char name[MAX_TACNAME_LEN+1]
Definition tpctac.h:81
double * y
Definition tpctac.h:75
Definition tpctac.h:87
double * x
Definition tpctac.h:97
unit cunit
Definition tpctac.h:105
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
int isframe
Definition tpctac.h:95
TACC * c
Definition tpctac.h:117
double * x2
Definition tpctac.h:101
unit tunit
Definition tpctac.h:109
double * x1
Definition tpctac.h:99
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
void tacFree(TAC *tac)
Definition tac.c:106
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
Definition tac.c:130
void tacInit(TAC *tac)
Definition tac.c:24
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
int tacNaNs(TAC *tac)
Definition tacnan.c:71
Header file for library libtpcextensions.
@ UNIT_UNITLESS
Unitless.
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.
Header file for libtpcpar.
@ PAR_FORMAT_HTML
HTML table format (currently not supported).
Definition tpcpar.h:37
@ PAR_FORMAT_CSV_UK
UK CSV.
Definition tpcpar.h:33
@ PAR_FORMAT_RES
Model result format of Turku PET Centre.
Definition tpcpar.h:29
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28
@ TAC_FORMAT_PMOD
PMOD TAC format.
Definition tpctac.h:33
Header file for libtpctacmod.