TPCCLIB
Loading...
Searching...
No Matches
parai.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 <string.h>
14#include <math.h>
15/*****************************************************************************/
16#include "tpcextensions.h"
17#include "tpcpar.h"
18/*****************************************************************************/
19
20/*****************************************************************************/
21static char *info[] = {
22 "Calculate Asymmetry Index (AI) from PET results inside a parameter file.",
23 " ",
24 " (dx - sin) ",
25 " Asymmetry index AI = ------------ x 100 ",
26 " (dx + sin)/2 ",
27 " ",
28 "The right and left hemisphere is recognized from the following strings:",
29 " dx, dex, dexter, right, rgt, sn, sin, sinist, left, lft",
30 " ",
31 "Usage: @P [options] file [resultfile]",
32 " ",
33 "Options:",
34 " -stdoptions", // List standard options like --help, -v, etc
35 " ",
36 "See also: pardiff, paradd, parcoll, parformat, tacren, parget, parrenp",
37 " ",
38 "Keywords: parameter, tool, ratio",
39 0};
40/*****************************************************************************/
41
42/*****************************************************************************/
43/* Turn on the globbing of the command line, since it is disabled by default in
44 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
45 In Unix&Linux wildcard command line processing is enabled by default. */
46/*
47#undef _CRT_glob
48#define _CRT_glob -1
49*/
50int _dowildcard = -1;
51/*****************************************************************************/
52
53/*****************************************************************************/
57int main(int argc, char **argv)
58{
59 int ai, help=0, version=0, verbose=1;
60 char parfile[FILENAME_MAX], outfile[FILENAME_MAX];
61 /* List of identified dx/sin representation in region names */
62 static char *dx_string[] = {"dx", "dex", "dexter", "right", "rgt", "d", 0};
63 static char *sin_string[] = {"sn", "sin", "sinist", "left", "lft", "s", 0};
64
65
66 /*
67 * Get arguments
68 */
69 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
70 parfile[0]=outfile[0]=(char)0;
71 /* Options */
72 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
73 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
74 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
75 if(strcasecmp(cptr, "DRY")==0) {
76 continue;
77 }
78 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
79 return(1);
80 } else break; // tac name argument may start with '-'
81
82 TPCSTATUS status; statusInit(&status);
83 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
84 status.verbose=verbose-5;
85
86 /* Print help or version? */
87 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
88 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
89 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
90
91 /* Process other arguments, starting from the first non-option */
92 if(ai<argc) strlcpy(parfile, argv[ai++], FILENAME_MAX);
93 if(ai<argc) strlcpy(outfile, argv[ai++], FILENAME_MAX);
94 if(ai<argc) {fprintf(stderr, "Error: too many arguments: '%s'.\n", argv[ai]); return(1);}
95
96 /* Is something missing? */
97 if(!parfile[0]) {tpcPrintUsage(argv[0], info, stderr); return(1);}
98 if(strcasecmp(parfile, outfile)==0) {
99 fprintf(stderr, "Error: input file would be overwritten.\n");
100 return(1);
101 }
102
103 /* In verbose mode print arguments and options */
104 if(verbose>1) {
105 printf("parfile := %s\n", parfile);
106 if(outfile[0]) printf("outfile := %s\n", outfile);
107 fflush(stdout);
108 }
109
110
111 /*
112 * Read the file
113 */
114 if(verbose>1) printf("reading %s\n", parfile);
115 PAR par; parInit(&par);
116 if(parRead(&par, parfile, &status)!=TPCERROR_OK) {
117 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
118 parFree(&par); return(2);
119 }
120 if(verbose>2) {
121 printf("fileformat := %s\n", parFormattxt(par.format));
122 printf("parNr := %d\n", par.parNr);
123 printf("tacNr := %d\n", par.tacNr);
124 }
125 if(par.tacNr<2) {
126 fprintf(stderr, "Error: no data to calculate AI.\n");
127 parFree(&par); return(2);
128 }
129 /* Sort regions by name */
130 if(parSortByName(&par, &status)!=TPCERROR_OK) {
131 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
132 parFree(&par); return(2);
133 }
134
135 /* List the region names */
136 if(verbose>10) {
137 fflush(stdout);
138 for(int i=0; i<par.tacNr; i++) printf("%s\n", par.r[i].name);
139 fflush(stdout);
140 }
141
142
143 /*
144 * Search and count the dx and sin regions
145 * Set sw=1 for dx and sw=2 for sin, and sw=0 for those that are neither
146 */
147 if(verbose>1) {printf("counting dx and sin regions\n"); fflush(stdout);}
148 int ndx=0, nsin=0;
149 char test_string[MAX_TACNAME_LEN+1];
150
151 for(int ri=0; ri<par.tacNr; ri++) {
152 if(verbose>3) printf("--------------\n%s\n", par.r[ri].name);
153 par.r[ri].sw=0;
154 if(strnlen(par.r[ri].name, 4)<3) continue;
155 /* Try to find hemisphere strings */
156 int j=0;
157 while(dx_string[j]!=0) {
158 /* Try to find in the middle */
159 sprintf(test_string, "-%s-", dx_string[j]);
160 if(verbose>6) printf(" testing '%s'\n", test_string);
161 if(strcasestr(par.r[ri].name, test_string)!=NULL) {
162 par.r[ri].sw=1; break;
163 }
164 sprintf(test_string, "_%s_", dx_string[j]);
165 if(verbose>6) printf(" testing '%s'\n", test_string);
166 if(strcasestr(par.r[ri].name, test_string)!=NULL) {
167 par.r[ri].sw=1; break;
168 }
169 sprintf(test_string, " %s ", dx_string[j]);
170 if(verbose>6) printf(" testing '%s'\n", test_string);
171 if(strcasestr(par.r[ri].name, test_string)!=NULL) {
172 par.r[ri].sw=1; break;
173 }
174 /* Try to find in the end */
175 unsigned int n=strlen(par.r[ri].name);
176 sprintf(test_string, "-%s", dx_string[j]);
177 if(verbose>6) printf(" testing '%s'\n", test_string);
178 if(n>strlen(test_string) && strcasecmp(par.r[ri].name+n-strlen(test_string), test_string)==0) {
179 par.r[ri].sw=1; break;
180 }
181 sprintf(test_string, "_%s", dx_string[j]);
182 if(verbose>6) printf(" testing '%s'\n", test_string);
183 if(n>strlen(test_string) && strcasecmp(par.r[ri].name+n-strlen(test_string), test_string)==0) {
184 par.r[ri].sw=1; break;
185 }
186 sprintf(test_string, " %s", dx_string[j]);
187 if(verbose>6) printf(" testing '%s'\n", test_string);
188 if(n>strlen(test_string) && strcasecmp(par.r[ri].name+n-strlen(test_string), test_string)==0) {
189 par.r[ri].sw=1; break;
190 }
191 j++;
192 }
193 if(par.r[ri].sw!=0) {
194 ndx++;
195 if(verbose>3) printf(" found string '%s'\n", test_string);
196 (void)strdelstr(par.r[ri].name, test_string);
197 continue;
198 }
199 j=0;
200 while(sin_string[j]!=0) {
201 sprintf(test_string, "-%s-", sin_string[j]);
202 if(verbose>6) printf(" testing '%s'\n", test_string);
203 if(strcasestr(par.r[ri].name, test_string)!=NULL) {
204 par.r[ri].sw=2; break;
205 }
206 sprintf(test_string, "_%s_", sin_string[j]);
207 if(verbose>6) printf(" testing '%s'\n", test_string);
208 if(strcasestr(par.r[ri].name, test_string)!=NULL) {
209 par.r[ri].sw=2; break;
210 }
211 sprintf(test_string, " %s ", sin_string[j]);
212 if(verbose>6) printf(" testing '%s'\n", test_string);
213 if(strcasestr(par.r[ri].name, test_string)!=NULL) {
214 par.r[ri].sw=2; break;
215 }
216 /* Try to find in the end */
217 unsigned int n=strlen(par.r[ri].name);
218 sprintf(test_string, "-%s", sin_string[j]);
219 if(verbose>6) printf(" testing '%s'\n", test_string);
220 if(n>strlen(test_string) && strcasecmp(par.r[ri].name+n-strlen(test_string), test_string)==0) {
221 par.r[ri].sw=2; break;
222 }
223 sprintf(test_string, "_%s", sin_string[j]);
224 if(verbose>6) printf(" testing '%s'\n", test_string);
225 if(n>strlen(test_string) && strcasecmp(par.r[ri].name+n-strlen(test_string), test_string)==0) {
226 par.r[ri].sw=2; break;
227 }
228 sprintf(test_string, " %s", sin_string[j]);
229 if(verbose>6) printf(" testing '%s'\n", test_string);
230 if(n>strlen(test_string) && strcasecmp(par.r[ri].name+n-strlen(test_string), test_string)==0) {
231 par.r[ri].sw=2; break;
232 }
233 j++;
234 }
235 if(par.r[ri].sw!=0) {
236 nsin++;
237 if(verbose>3) printf(" found string '%s'\n", test_string);
238 (void)strdelstr(par.r[ri].name, test_string);
239 continue;
240 }
241 }
242 if(ndx<1 || nsin<1) {
243 fprintf(stderr, "Error: no dx/sin pairs were identified.\n");
244 parFree(&par); return(3);
245 }
246 /* Delete regions where dx/sin was not identified */
247 if(verbose>2) {printf("deleting unidentified regions from list\n"); fflush(stdout);}
248 {
249 int i=0;
250 while(i<par.tacNr) {
251 if(par.r[i].sw==0) parDeleteTAC(&par, i); else i++;
252 }
253 }
254 /* List the region names */
255 if(verbose>3) {
256 fflush(stdout);
257 for(int i=0; i<par.tacNr; i++) printf("%s\n", par.r[i].name);
258 fflush(stdout);
259 }
260
261 /*
262 * Create a new parameter structure for AIs.
263 */
264 if(verbose>2) {printf("allocating place for AIs\n"); fflush(stdout);}
265 PAR pai; parInit(&pai);
266 int pn=ndx; if(nsin<pn) pn=nsin;
267 if(parAllocate(&pai, par.parNr, pn)) {
268 fprintf(stderr, "Error: cannot allocate memory for AIs.\n");
269 parFree(&par); parFree(&pai); return(4);
270 }
271 /* Set results information */
272 pai.tacNr=0; pai.parNr=par.parNr;
273 pai.format=par.format;
274 for(int i=0; i<pai.parNr; i++) {
275 strcpy(pai.n[i].name, par.n[i].name);
276 pai.n[i].unit=UNIT_PERCENTAGE;
277 }
278 {
279 char buf[256];
280 tpcProgramName(argv[0], 1, 1, buf, 256);
281 iftPut(&pai.h, "program", buf, 0, NULL);
282 time_t t=time(NULL);
283 iftPut(&pai.h, "analysis_time", ctime_r_int(&t, buf), 0, NULL);
284 }
285 iftPut(&pai.h, "datafile", parfile, 0, NULL);
286
287
288 /*
289 * Compute AIs
290 */
291 if(verbose>1) {printf("computing AIs\n"); fflush(stdout);}
292 for(int ri=0; ri<par.tacNr; ri++) if(par.r[ri].sw==1) {
293 /* now search for the matching left hemisphere */
294 for(int rj=0; rj<par.tacNr; rj++) if(par.r[rj].sw==2) {
295 /* check that the remaining region name is matching */
296 if(strcasecmp(par.r[ri].name, par.r[rj].name)!=0) continue;
297 /* Set AI region name */
298 strcpy(pai.r[pai.tacNr].name, par.r[ri].name);
299 /* Calculate AI for all parameters */
300 for(int pi=0; pi<par.parNr; pi++) {
301 double f=par.r[ri].p[pi]+par.r[rj].p[pi];
302 if(f==0.) pai.r[pai.tacNr].p[pi]=0.;
303 else pai.r[pai.tacNr].p[pi]=200.*(par.r[ri].p[pi]-par.r[rj].p[pi])/f;
304 } /* next parameter */
305 pai.tacNr++;
306 /* Do not process these regions again */
307 par.r[rj].sw=0;
308 break;
309 }
310 /* Do not process this region again */
311 par.r[ri].sw=0;
312 } /* next region */
313 /* Original parameter data no more needed */
314 parFree(&par);
315 if(pai.tacNr<1) {
316 fprintf(stderr, "Error: no data to calculate AI.\n");
317 parFree(&par); return(6);
318 }
319
320
321 /* Print and save */
322 if(verbose>0 || !outfile[0]) parWrite(&pai, stdout, PAR_FORMAT_TSV_UK, 0, NULL);
323 if(outfile[0]) {
324 /* Save file */
325 if(verbose>1) printf(" saving %s\n", outfile);
326 FILE *fp;
327 fp=fopen(outfile, "w");
328 if(fp==NULL) {
329 fprintf(stderr, "Error: cannot open file for writing.\n");
330 parFree(&pai); return(11);
331 }
332 int ret=parWrite(&pai, fp, PAR_FORMAT_UNKNOWN, 1, &status);
333 fclose(fp);
334 if(ret!=TPCERROR_OK) {
335 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
336 parFree(&pai); return(12);
337 }
338 if(verbose>0) printf("parameter AIs saved in %s\n", outfile);
339 }
340
341 parFree(&pai);
342 return(0);
343}
344/*****************************************************************************/
345
346/*****************************************************************************/
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,...
Definition datetime.c:119
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
Definition ift.c:63
void parFree(PAR *par)
Definition par.c:75
int parAllocate(PAR *par, int parNr, int tacNr)
Definition par.c:108
void parInit(PAR *par)
Definition par.c:25
int parDeleteTAC(PAR *par, int ti)
Definition par.c:519
char * parFormattxt(parformat c)
Definition pario.c:59
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
Definition pario.c:148
int parRead(PAR *par, const char *fname, TPCSTATUS *status)
Definition pario.c:232
int parSortByName(PAR *d, TPCSTATUS *status)
Definition parorder.c:30
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
Definition proginfo.c:406
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 strnlen(const char *s, size_t n)
Definition stringext.c:566
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
char * strdelstr(char *s1, const char *s2)
Definition stringext.c:688
char * strcasestr(const char *haystack, const char *needle)
Definition stringext.c:155
Definition tpcpar.h:100
int format
Definition tpcpar.h:102
IFT h
Optional (but often useful) header information.
Definition tpcpar.h:147
int parNr
Definition tpcpar.h:108
int tacNr
Definition tpcpar.h:104
PARR * r
Definition tpcpar.h:114
PARN * n
Definition tpcpar.h:112
int unit
Definition tpcpar.h:86
char name[MAX_PARNAME_LEN+1]
Definition tpcpar.h:82
char name[MAX_TACNAME_LEN+1]
Definition tpcpar.h:50
char sw
Definition tpcpar.h:74
double * p
Definition tpcpar.h:64
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
Header file for library libtpcextensions.
#define MAX_TACNAME_LEN
Max length of TAC ID name (not including trailing zero).
@ UNIT_PERCENTAGE
Percentage (%).
@ TPCERROR_OK
No error.
Header file for libtpcpar.
@ PAR_FORMAT_UNKNOWN
Unknown format.
Definition tpcpar.h:28
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Definition tpcpar.h:35