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;
105 FILE *fp=fopen(cptr,
"r");
106 if(fp==NULL) {fprintf(stderr,
"Error: invalid cut time.\n");
return(1);}
108 if(
iftRead(&ift, fp, 1, 0, NULL)==0) {
114 fprintf(stderr,
"Error: invalid cut time.\n");
return(1);
116 fprintf(stderr,
"Error: invalid option '%s'\n", argv[ai]);
125 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
130 if(ai<argc)
strlcpy(tacfile1, argv[ai++], FILENAME_MAX);
131 if(ai<argc)
strlcpy(tacfile2, argv[ai++], FILENAME_MAX);
132 if(ai<argc)
strlcpy(outfile, argv[ai++], FILENAME_MAX);
133 if(ai<argc) {fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
return(1);}
136 if(!tacfile2[0]) {
tpcPrintUsage(argv[0], info, stdout);
return(1);}
137 if(!outfile[0]) strcpy(outfile, tacfile1);
138 if(overlapMode==OVL_CUTTIME && !(cutTime>0.0)) {fprintf(stderr,
"Error: invalid cut time.\n");
return(1);}
142 for(ai=0; ai<argc; ai++) printf(
"%s ", argv[ai]);
144 printf(
"tacfile1 := %s\n", tacfile1);
145 printf(
"tacfile2 := %s\n", tacfile2);
146 printf(
"outfile := %s\n", outfile);
147 printf(
"overlapMode := %d\n", overlapMode);
148 if(overlapMode==OVL_CUTTIME) printf(
"cutTime := %g\n", cutTime);
149 printf(
"forceMode := %d\n", forceMode);
159 if(verbose>1) printf(
"reading %s\n", tacfile1);
166 printf(
"tacNr := %d\n", tac1.
tacNr);
167 printf(
"sampleNr := %d\n", tac1.
sampleNr);
171 if(verbose>1) printf(
"reading %s\n", tacfile2);
178 printf(
"tacNr := %d\n", tac2.
tacNr);
179 printf(
"sampleNr := %d\n", tac2.
sampleNr);
185 if(verbose>1) printf(
"checking data...\n");
187 fprintf(stderr,
"Error: different number of TACs.\n");
194 fprintf(stderr,
"Warning: TAC names do not match.\n");
200 fprintf(stderr,
"Error: TAC names do not match.\n");
203 fprintf(stderr,
"Note: TACs sorted by name.\n");
210 fprintf(stderr,
"Error: no valid samples in %s\n", tacfile1);
215 fprintf(stderr,
"Error: no valid samples in %s\n", tacfile2);
225 fprintf(stderr,
"Warning: unknown time units.\n");
235 if(verbose>2) fprintf(stderr,
"Status: %s\n",
errorMsg(status.
error));
237 fprintf(stderr,
"Warning: non-compatible TAC time units.\n");
239 fprintf(stderr,
"Error: non-compatible TAC time units.\n");
250 fprintf(stderr,
"Warning: unknown concentration units.\n");
260 if(verbose>2) fprintf(stderr,
"Status: %s\n",
errorMsg(status.
error));
262 fprintf(stderr,
"Warning: non-compatible TAC concentration units.\n");
264 fprintf(stderr,
"Error: non-compatible TAC concentration units.\n");
279 if(verbose>1) printf(
"checking for time overlap\n");
281 double xmin1, xmax1, xmin2, xmax2, xmin, xmax;
283 fprintf(stderr,
"Error: invalid sample times.\n");
287 printf(
"x range 1 := %g - %g\n", xmin1, xmax1);
288 printf(
"x range 2 := %g - %g\n", xmin2, xmax2);
290 if(xmax1>xmin2) isOverlap=1;
291 else if(!tac1.
isframe && xmax1>=xmin2) isOverlap=1;
292 if(isOverlap && overlapMode==OVL_ERROR) {
293 fprintf(stderr,
"Error: overlapping sample times.\n");
296 xmin=xmin1;
if(xmin2<xmin) xmin=xmin2;
297 xmax=xmax1;
if(xmax2>xmax) xmax=xmax2;
298 if(overlapMode==OVL_CUTTIME && (cutTime<xmin || cutTime>xmax)) {
299 fprintf(stderr,
"Error: cut time outside of data time range %g - %g\n", xmin, xmax);
304 if(overlapMode==OVL_USE_FIRST && xmin1>xmin2) fail=1;
305 if(overlapMode==OVL_USE_SECOND && xmin2<=xmin1) fail=2;
306 if(overlapMode==OVL_CUTTIME && (xmin1>cutTime || xmax2<cutTime)) fail=3;
308 fprintf(stderr,
"Error: incompatible sample time ranges or wrong file order.\n");
314 if(overlapMode==OVL_USE_BOTH) {
316 fprintf(stderr,
"Warning: overlap in sample times is ignored.\n");
318 fprintf(stderr,
"Warning: overlap in sample times will be removed.\n");
325 if(overlapMode==OVL_USE_FIRST) {cutTime=xmax1;
if(xmax1==xmin2) cutTime+=1.0E-12;}
326 if(overlapMode==OVL_USE_SECOND) {cutTime=xmin2;
if(xmax1==xmin2) cutTime-=1.0E-12;}
327 if(verbose>4 && isOverlap && (overlapMode==OVL_USE_FIRST || overlapMode==OVL_USE_SECOND))
328 printf(
"cutTime := %g\n", cutTime);
332 if(isOverlap && overlapMode!=OVL_USE_FIRST && xmax1>=cutTime) {
333 if(verbose>1) printf(
"deleting overlap from the first dataset\n");
335 for(
int i=tac1.
sampleNr-1; i>=0; i--)
338 for(
int i=tac1.
sampleNr-1; i>=0; i--)
342 fprintf(stderr,
"Error: no data from file 1 included.\n");
345 if(verbose>3) printf(
"final x range 1 := %g - %g\n", xmin1, xmax1);
348 if(isOverlap && overlapMode!=OVL_USE_SECOND && xmin2<=cutTime) {
349 if(verbose>1) printf(
"deleting overlap from the second dataset\n");
351 for(
int i=tac2.
sampleNr-1; i>=0; i--)
354 for(
int i=tac2.
sampleNr-1; i>=0; i--)
358 fprintf(stderr,
"Error: no data from file 2 included.\n");
361 if(verbose>3) printf(
"final x range 2 := %g - %g\n", xmin2, xmax2);
368 if(verbose>1) printf(
"combining data\n");
370 fprintf(stderr,
"Error: cannot allocate memory.\n");
373 for(
int i=0; i<tac2.
sampleNr; i++) {
395 if(verbose>1) printf(
"writing %s\n", outfile);
397 FILE *fp; fp=fopen(outfile,
"w");
399 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", outfile);
405 fprintf(stderr,
"Error (%d): %s\n", ret,
errorMsg(status.
error));
409 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.