9#include "tpcclibConfig.h"
23static char *info[] = {
24 "Catenate the TACs from the second TAC file to the first one, or to a new",
25 "datafile. Sample times or correction for physical decay are not changed.",
26 "Each TAC file must contain the same number of TACs, and if more than one TAC,",
27 "TAC names must match, too.",
29 "Usage: @P [options] tacfile1 tacfile2 [catenated_file]",
32 " -both | -first | -second | -cut=<time>",
33 " In case of overlapping samples, either samples from both (-both),",
34 " first (-first), or second (-second, default) TAC are saved in",
35 " combined file, or specified cut time is used.",
36 " Cut time can also be given in file with keys 'x' or 'time'.",
37 " By default, overlap will lead to an error.",
39 " Program does not mind if the time or calibration units cannot be",
40 " converted to match, or if TAC names do not match.",
44 " @P t455ap_pump.kbq t455ap_manual.kbq t455ap_combined.kbq",
46 "See also: tacblend, taccut, tacadd0, tacadd, tacunit, tactime, taccross",
48 "Keywords: TAC, tool, input, blood",
65enum {OVL_ERROR, OVL_USE_BOTH, OVL_USE_FIRST, OVL_USE_SECOND, OVL_CUTTIME};
70int main(
int argc,
char **argv)
72 int ai, help=0, version=0, verbose=1;
73 char tacfile1[FILENAME_MAX], tacfile2[FILENAME_MAX], outfile[FILENAME_MAX];
75 int overlapMode=OVL_ERROR;
76 double cutTime=nan(
"");
83 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
84 tacfile1[0]=tacfile2[0]=outfile[0]=(char)0;
87 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
89 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
90 if(strcasecmp(cptr,
"F")==0 || strcasecmp(cptr,
"FORCE")==0) {
91 forceMode=1;
continue;
92 }
else if(strncasecmp(cptr,
"BOTH", 1)==0) {
93 overlapMode=OVL_USE_BOTH;
continue;
94 }
else if(strncasecmp(cptr,
"FIRST", 2)==0) {
95 overlapMode=OVL_USE_FIRST;
continue;
96 }
else if(strncasecmp(cptr,
"SECOND", 2)==0) {
97 overlapMode=OVL_USE_SECOND;
continue;
98 }
else if(strncasecmp(cptr,
"CUT=", 4)==0) {
99 overlapMode=OVL_CUTTIME;
103 if(cutTime>0.0)
continue;
106 FILE *fp=fopen(cptr,
"r");
107 if(fp==NULL) {fprintf(stderr,
"Error: invalid cut time.\n");
return(1);}
109 int ret=
iftRead(&ift, fp, 1, 0, NULL);
118 fprintf(stderr,
"Error: invalid cut time.\n");
return(1);
120 fprintf(stderr,
"Error: invalid option '%s'\n", argv[ai]);
129 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
134 if(ai<argc)
strlcpy(tacfile1, argv[ai++], FILENAME_MAX);
135 if(ai<argc)
strlcpy(tacfile2, argv[ai++], FILENAME_MAX);
136 if(ai<argc)
strlcpy(outfile, argv[ai++], FILENAME_MAX);
137 if(ai<argc) {fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
return(1);}
140 if(!tacfile2[0]) {
tpcPrintUsage(argv[0], info, stdout);
return(1);}
141 if(!outfile[0]) strcpy(outfile, tacfile1);
142 if(overlapMode==OVL_CUTTIME && !(cutTime>0.0)) {fprintf(stderr,
"Error: invalid cut time.\n");
return(1);}
146 for(ai=0; ai<argc; ai++) printf(
"%s ", argv[ai]);
148 printf(
"tacfile1 := %s\n", tacfile1);
149 printf(
"tacfile2 := %s\n", tacfile2);
150 printf(
"outfile := %s\n", outfile);
151 printf(
"overlapMode := %d\n", overlapMode);
152 if(overlapMode==OVL_CUTTIME) printf(
"cutTime := %g\n", cutTime);
153 printf(
"forceMode := %d\n", forceMode);
163 if(verbose>1) printf(
"reading %s\n", tacfile1);
170 printf(
"tacNr := %d\n", tac1.
tacNr);
171 printf(
"sampleNr := %d\n", tac1.
sampleNr);
175 if(verbose>1) printf(
"reading %s\n", tacfile2);
182 printf(
"tacNr := %d\n", tac2.
tacNr);
183 printf(
"sampleNr := %d\n", tac2.
sampleNr);
189 if(verbose>1) printf(
"checking data...\n");
191 fprintf(stderr,
"Error: different number of TACs.\n");
198 fprintf(stderr,
"Warning: TAC names do not match.\n");
204 fprintf(stderr,
"Error: TAC names do not match.\n");
207 fprintf(stderr,
"Note: TACs sorted by name.\n");
214 fprintf(stderr,
"Error: no valid samples in %s\n", tacfile1);
219 fprintf(stderr,
"Error: no valid samples in %s\n", tacfile2);
229 fprintf(stderr,
"Warning: unknown time units.\n");
239 if(verbose>2) fprintf(stderr,
"Status: %s\n",
errorMsg(status.
error));
241 fprintf(stderr,
"Warning: non-compatible TAC time units.\n");
243 fprintf(stderr,
"Error: non-compatible TAC time units.\n");
254 fprintf(stderr,
"Warning: unknown concentration units.\n");
264 if(verbose>2) fprintf(stderr,
"Status: %s\n",
errorMsg(status.
error));
266 fprintf(stderr,
"Warning: non-compatible TAC concentration units.\n");
268 fprintf(stderr,
"Error: non-compatible TAC concentration units.\n");
283 if(verbose>1) printf(
"checking for time overlap\n");
285 double xmin1, xmax1, xmin2, xmax2, xmin, xmax;
287 fprintf(stderr,
"Error: invalid sample times.\n");
291 printf(
"x range 1 := %g - %g\n", xmin1, xmax1);
292 printf(
"x range 2 := %g - %g\n", xmin2, xmax2);
294 if(xmax1>xmin2) isOverlap=1;
295 else if(!tac1.
isframe && xmax1>=xmin2) isOverlap=1;
296 if(isOverlap && overlapMode==OVL_ERROR) {
297 fprintf(stderr,
"Error: overlapping sample times.\n");
300 xmin=xmin1;
if(xmin2<xmin) xmin=xmin2;
301 xmax=xmax1;
if(xmax2>xmax) xmax=xmax2;
302 if(overlapMode==OVL_CUTTIME && (cutTime<xmin || cutTime>xmax)) {
303 fprintf(stderr,
"Error: cut time outside of data time range %g - %g\n", xmin, xmax);
308 if(overlapMode==OVL_USE_FIRST && xmin1>xmin2) fail=1;
309 if(overlapMode==OVL_USE_SECOND && xmin2<=xmin1) fail=2;
310 if(overlapMode==OVL_CUTTIME && (xmin1>cutTime || xmax2<cutTime)) fail=3;
312 fprintf(stderr,
"Error: incompatible sample time ranges or wrong file order.\n");
318 if(overlapMode==OVL_USE_BOTH) {
320 fprintf(stderr,
"Warning: overlap in sample times is ignored.\n");
322 fprintf(stderr,
"Warning: overlap in sample times will be removed.\n");
329 if(overlapMode==OVL_USE_FIRST) {cutTime=xmax1;
if(xmax1==xmin2) cutTime+=1.0E-12;}
330 if(overlapMode==OVL_USE_SECOND) {cutTime=xmin2;
if(xmax1==xmin2) cutTime-=1.0E-12;}
331 if(verbose>4 && isOverlap && (overlapMode==OVL_USE_FIRST || overlapMode==OVL_USE_SECOND))
332 printf(
"cutTime := %g\n", cutTime);
336 if(isOverlap && overlapMode!=OVL_USE_FIRST && xmax1>=cutTime) {
337 if(verbose>1) printf(
"deleting overlap from the first dataset\n");
339 for(
int i=tac1.
sampleNr-1; i>=0; i--)
342 for(
int i=tac1.
sampleNr-1; i>=0; i--)
346 fprintf(stderr,
"Error: no data from file 1 included.\n");
349 if(verbose>3) printf(
"final x range 1 := %g - %g\n", xmin1, xmax1);
352 if(isOverlap && overlapMode!=OVL_USE_SECOND && xmin2<=cutTime) {
353 if(verbose>1) printf(
"deleting overlap from the second dataset\n");
355 for(
int i=tac2.
sampleNr-1; i>=0; i--)
358 for(
int i=tac2.
sampleNr-1; i>=0; i--)
362 fprintf(stderr,
"Error: no data from file 2 included.\n");
365 if(verbose>3) printf(
"final x range 2 := %g - %g\n", xmin2, xmax2);
372 if(verbose>1) printf(
"combining data\n");
374 fprintf(stderr,
"Error: cannot allocate memory.\n");
377 for(
int i=0; i<tac2.
sampleNr; i++) {
399 if(verbose>1) printf(
"writing %s\n", outfile);
401 FILE *fp; fp=fopen(outfile,
"w");
403 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", outfile);
409 fprintf(stderr,
"Error (%d): %s\n", ret,
errorMsg(status.
error));
413 printf(
"%d samples saved in %s.\n", tac1.
sampleNr, outfile);
double atofVerified(const char *s)
int iftCopyItems(IFT *ift1, IFT *ift2, int is_key_required, int is_value_required, int is_comment_accepted, TPCSTATUS *status)
int iftDeleteDuplicateKeys(IFT *ift, TPCSTATUS *status)
int iftGetDoubleValue(IFT *ift, const char *key, int index, double *v)
int iftRead(IFT *ift, FILE *fp, int is_key_required, int is_comment_accepted, TPCSTATUS *status)
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)
IFT h
Optional (but often useful) header information.
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacAllocateMoreSamples(TAC *tac, int addNr)
Allocate memory for more samples in TAC data.
int tacCompareNames(TAC *d1, TAC *d2, const int i, TPCSTATUS *status)
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 tacNotNaNs(TAC *tac, const int i)
int tacSortByTime(TAC *d, TPCSTATUS *status)
int tacSortByName(TAC *d, TPCSTATUS *status)
int tacYUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
int tacDeleteMissingSamples(TAC *d)
Delete those samples (time frames) from TAC structure, which contain only missing y values,...
int tacDeleteSample(TAC *d, int i)
Delete a certain sample (time frame) from TAC structure.
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Header file for library libtpcextensions.
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ UNIT_UNKNOWN
Unknown unit.
char * unitName(int unit_code)
Header file for library libtpcift.
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.