9#include "tpcclibConfig.h"
23static char *info[] = {
24 "Make arithmetic calculations with PET time-activity data.",
25 "Operations can be made between two TAC files or between one TAC file and",
28 "Usage: @P [options] file1 operation constant|file2|x outputfile",
32 " Program does not mind if the time or calibration units",
33 " cannot be converted to match.",
36 "Example 1: Add constant 2 to all activity concentrations in pet.dat",
37 " @P pet.dat + 2 sum.dat",
38 "Example 2: Subtract one TAC from all TACs in the first data file",
39 " @P cortex.dat - reference.dat bound.dat",
40 "Example 3: Divide all TACs by the x (time) column",
41 " @P pet.tac div x petperx.tac",
43 "The first TAC file can have one or more TACs. Second TAC file may",
44 "contain either only one TAC or equally many TACs as the first file",
45 "(if the TAC number is different, only the first TAC is used).",
46 "Data is interpolated, if necessary, to the times of the first file.",
47 "If the second file contains only one sample time (frame), the value",
48 "from that sample will be used for all the samples of the first file.",
50 "The following characters are accepted as operators: +, -, x, and :, or",
51 "'plus', 'minus', 'mult', and 'div'.",
53 "See also: tacunit, metabcor, dftsuv, dftratio, taccbv, fit2dat, tacinv",
55 "Keywords: TAC, modelling, simulation, tool",
74int main(
int argc,
char **argv)
76 int ai, help=0, version=0, verbose=1;
82 char *cptr, d1file[FILENAME_MAX], d2file[FILENAME_MAX], rfile[FILENAME_MAX];
84 TAC tac1, tac2, itac2;
90 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
92 d1file[0]=d2file[0]=rfile[0]=(char)0;
94 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
96 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
97 if(strcasecmp(cptr,
"F")==0 || strcasecmp(cptr,
"FORCE")==0) {
98 checkUnits=0;
continue;
99 }
else if(strcasecmp(cptr,
"NT")==0) {
101 checkUnits=0;
continue;
103 fprintf(stderr,
"Error: invalid option '%s'\n", argv[ai]);
112 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
117 if(ai<argc) {
strlcpy(d1file, argv[ai++], FILENAME_MAX);}
119 if(strcasecmp(argv[ai],
"PLUS")==0) {
121 }
else if(strcasecmp(argv[ai],
"MINUS")==0) {
123 }
else if(strncasecmp(argv[ai],
"MULTIPLY", 4)==0) {
125 }
else if(strncasecmp(argv[ai],
"DIVIDE", 3)==0) {
127 }
else if(*argv[ai]==
'+') {
129 }
else if(*argv[ai]==
'-') {
131 }
else if(*argv[ai]==
'*' || *argv[ai]==
'.' || *argv[ai]==
'X' || *argv[ai]==
'x') {
134 }
else if(*argv[ai]==
'/' || *argv[ai]==
':') {
138 fprintf(stderr,
"Error: invalid operator.\n");
148 if(strcasecmp(argv[ai],
"X")) strcpy(d2file, argv[ai]);
else usex=1;
152 if(ai<argc) {
strlcpy(rfile, argv[ai++], FILENAME_MAX);}
154 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
159 if(!rfile[0]) {
tpcPrintUsage(argv[0], info, stdout);
return(1);}
164 for(ai=0; ai<argc; ai++) printf(
"%s ", argv[ai]);
166 printf(
"d1file := %s\n", d1file);
167 printf(
"operation := %d\n", operation);
168 if(isvalue) printf(
"value := %g\n", value);
169 if(d2file[0]) printf(
"d2file := %s\n", d2file);
170 if(usex) printf(
"usex := %d\n", usex);
171 printf(
"rfile := %s\n", rfile);
172 printf(
"checkUnits = %d\n", checkUnits);
180 if(verbose>1) printf(
"reading %s\n", d1file);
181 ret=
tacRead(&tac1, d1file, &status);
183 fprintf(stderr,
"Error (%d): %s\n", ret,
errorMsg(status.
error));
188 printf(
"tacNr := %d\n", tac1.
tacNr);
189 printf(
"sampleNr := %d\n", tac1.
sampleNr);
198 if(isvalue==0 && d2file[0]) {
200 if(verbose>1) printf(
"reading %s\n", d1file);
201 ret=
tacRead(&tac2, d2file, &status);
203 fprintf(stderr,
"Error (%d): %s\n", ret,
errorMsg(status.
error));
208 printf(
"tacNr := %d\n", tac2.
tacNr);
209 printf(
"sampleNr := %d\n", tac2.
sampleNr);
215 if(verbose>2) printf(
"file #2 contains the constant.\n");
219 fprintf(stderr,
"Note: %s and %s have different or unknown concentration units.\n",
221 if(verbose>2) fprintf(stderr,
"Status: %s\n",
errorMsg(status.
error));
233 value=tac2.
c[0].
y[0];
234 if(verbose>1) printf(
"using %g as the constant value.\n", value);
247 fprintf(stderr,
"Error: cannot operate the files.\n");
254 if(verbose>0) fprintf(stderr,
"Note: using only the first TAC.\n");
262 fprintf(stderr,
"Note: %s and %s have different or unknown time units.\n", d1file, d2file);
263 if(verbose>2) fprintf(stderr,
"Status: %s\n",
errorMsg(status.
error));
270 fprintf(stderr,
"Warning: unknown time units.\n");
282 fprintf(stderr,
"Note: %s and %s have different or unknown concentration units.\n",
284 if(verbose>2) fprintf(stderr,
"Status: %s\n",
errorMsg(status.
error));
290 if(operation==3 || operation==4)
302 fprintf(stderr,
"Error: cannot interpolate TAC.\n");
319 if(verbose>1) printf(
"using first sample in %s for all samples in %s\n", d2file, d1file);
321 for(
int fi=0; fi<itac2.
sampleNr; fi++)
322 for(
int ri=0; ri<itac2.
tacNr; ri++)
323 itac2.
c[ri].
y[fi]=tac2.
c[ri].
y[0];
330 if(verbose>1) printf(
"sample times match; no interpolation necessary\n");
331 for(ri=0; ri<itac2.
tacNr; ri++)
333 itac2.
c[ri].
y[fi]=tac2.
c[ri].
y[fi];
335 if(verbose>1) printf(
"interpolating\n");
338 double xmin1, xmin2, xmax1, xmax2, xmin, xmax, xrange;
341 xmin=xmin1;
if(xmin2<xmin) xmin=xmin2;
342 xmax=xmax1;
if(xmax2>xmax) xmax=xmax2;
344 if((xmin2>xmin1 && (xmin2-xmin1)/xrange>0.05) || (xmax2<xmax1 && (xmin1-xmax2)/xrange>0.10)) {
345 fprintf(stderr,
"Warning: check the time ranges.\n");
349 for(ri=0, ret=0; ri<itac2.
tacNr && ret==0; ri++) {
352 itac2.
x1, itac2.
x2, itac2.
c[ri].
y, NULL, NULL, itac2.
sampleNr, 4, 1, verbose-6);
355 itac2.
x, itac2.
c[ri].
y, NULL, NULL, itac2.
sampleNr, 4, 1, verbose-6);
358 fprintf(stderr,
"Error: cannot interpolate TAC %d.\n", 1+ri);
359 if(verbose>1) fprintf(stderr,
"error_code := %d\n", ret);
375 fprintf(stderr,
"Error: cannot allocate memory.\n");
383 for(
int i=0; i<itac2.
sampleNr; i++) itac2.
c[0].
y[i]=0.5*(itac2.
x1[i]+itac2.
x2[i]);
385 for(
int i=0; i<itac2.
sampleNr; i++) itac2.
c[0].
y[i]=itac2.
x[i];
392 if(!isfinite(value)) {
393 fprintf(stderr,
"Error: invalid value of constant.\n");
396 if(operation==4 && fabs(value)<1.0E-12) {
397 fprintf(stderr,
"Error: invalid constant for division.\n");
407 if(verbose>1) printf(
"computing with constant\n");
411 for(ri=0; ri<tac1.
tacNr; ri++)
for(fi=0; fi<tac1.
sampleNr; fi++)
412 if(!isnan(tac1.
c[ri].
y[fi])) tac1.
c[ri].
y[fi]+=value;
415 for(ri=0; ri<tac1.
tacNr; ri++)
for(fi=0; fi<tac1.
sampleNr; fi++)
416 if(!isnan(tac1.
c[ri].
y[fi])) tac1.
c[ri].
y[fi]-=value;
419 for(ri=0; ri<tac1.
tacNr; ri++)
for(fi=0; fi<tac1.
sampleNr; fi++)
420 if(!isnan(tac1.
c[ri].
y[fi])) tac1.
c[ri].
y[fi]*=value;
423 for(ri=0; ri<tac1.
tacNr; ri++)
for(fi=0; fi<tac1.
sampleNr; fi++)
424 if(!isnan(tac1.
c[ri].
y[fi])) tac1.
c[ri].
y[fi]/=value;
428 if(verbose>1) printf(
"computing with TACs\n");
433 for(ri=0; ri<tac1.
tacNr; ri++) {
435 if(itac2.
tacNr==1) y2=itac2.
c[0].
y;
else y2=itac2.
c[ri].
y;
437 if(isfinite(y1[fi]) && isfinite(y2[fi])) y1[fi]+=y2[fi];
else y1[fi]=nan(
"");
441 for(ri=0; ri<tac1.
tacNr; ri++) {
443 if(itac2.
tacNr==1) y2=itac2.
c[0].
y;
else y2=itac2.
c[ri].
y;
445 if(isfinite(y1[fi]) && isfinite(y2[fi])) y1[fi]-=y2[fi];
else y1[fi]=nan(
"");
449 for(ri=0; ri<tac1.
tacNr; ri++) {
451 if(itac2.
tacNr==1) y2=itac2.
c[0].
y;
else y2=itac2.
c[ri].
y;
453 if(isfinite(y1[fi]) && isfinite(y2[fi])) y1[fi]*=y2[fi];
else y1[fi]=nan(
"");
457 for(ri=0; ri<tac1.
tacNr; ri++) {
459 if(itac2.
tacNr==1) y2=itac2.
c[0].
y;
else y2=itac2.
c[ri].
y;
461 if(!isfinite(y1[fi]) || !isfinite(y2[fi])) {y1[fi]=nan(
"");
continue;}
462 if(fabs(y2[fi])<1.0E-12) y1[fi]=0.0;
else y1[fi]/=y2[fi];
475 if(verbose>1) printf(
"writing %s\n", rfile);
476 FILE *fp; fp=fopen(rfile,
"w");
478 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", rfile);
484 fprintf(stderr,
"Error (%d): %s\n", ret,
errorMsg(status.
error));
487 if(verbose>=0) printf(
"%s saved.\n", rfile);
int atofCheck(const char *s, double *v)
int liInterpolate(double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear interpolation and/or integration with trapezoidal method.
int liInterpolateForPET(double *x, double *y, const int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear TAC interpolation and/or integration to PET frames.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
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)
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)
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
int tacCopyTacchdr(TACC *d1, TACC *d2)
int tacCopyHdr(TAC *tac1, TAC *tac2)
Copy TAC header data from tac1 to tac2.
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 tacYUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
int tacXMatch(TAC *d1, TAC *d2, const int verbose)
Check whether sample (frame) times are the same (or very close to) in two TAC structures.
int tacXCopy(TAC *tac1, TAC *tac2, int i1, int i2)
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Header file for library libtpcextensions.
char * unitName(int unit_code)
Header file for library libtpcift.
Header file for libtpcli.
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
@ TAC_FORMAT_PMOD
PMOD TAC format.