Commit 6b4588dd authored by Vesa Oikonen's avatar Vesa Oikonen
Browse files

started app tacadd

parent 5333777e
......@@ -28,6 +28,7 @@ add_executable (tacadd tacadd.c)
add_executable (tacadd0 tacadd0.c)
add_executable (tacblend tacblend.c)
add_executable (taccalc taccalc.c)
add_executable (taccat taccat.c)
add_executable (taccross taccross.c)
add_executable (taccut taccut.c)
add_executable (taccuty taccuty.c)
......@@ -66,6 +67,7 @@ target_link_libraries (tacadd tpcift tpctac tpcextensions m)
target_link_libraries (tacadd0 tpcift tpctac tpcextensions m)
target_link_libraries (tacblend tpcift tpctac tpcextensions m)
target_link_libraries (taccalc tpcli tpcift tpctac tpcextensions m)
target_link_libraries (taccat tpcift tpctac tpcextensions m)
target_link_libraries (taccross tpctac tpcli tpcextensions m)
target_link_libraries (taccut tpctac tpcextensions m)
target_link_libraries (taccuty tpctac tpcextensions m)
......@@ -106,6 +108,7 @@ install (
${CMAKE_CURRENT_BINARY_DIR}/tacadd0${CMAKE_EXECUTABLE_SUFFIX}
${CMAKE_CURRENT_BINARY_DIR}/tacblend${CMAKE_EXECUTABLE_SUFFIX}
${CMAKE_CURRENT_BINARY_DIR}/taccalc${CMAKE_EXECUTABLE_SUFFIX}
# ${CMAKE_CURRENT_BINARY_DIR}/taccat${CMAKE_EXECUTABLE_SUFFIX}
${CMAKE_CURRENT_BINARY_DIR}/taccross${CMAKE_EXECUTABLE_SUFFIX}
${CMAKE_CURRENT_BINARY_DIR}/taccut${CMAKE_EXECUTABLE_SUFFIX}
${CMAKE_CURRENT_BINARY_DIR}/taccuty${CMAKE_EXECUTABLE_SUFFIX}
......@@ -159,6 +162,7 @@ add_test(tacaddUsage tacadd "--help")
add_test(tacadd0Usage tacadd0 "--help")
add_test(tacblendUsage tacblend "--help")
add_test(taccalcUsage taccalc "--help")
add_test(taccatUsage taccut "--help")
add_test(taccrossUsage taccross "--help")
add_test(taccutUsage taccut "--help")
add_test(taccutyUsage taccuty "--help")
......@@ -189,11 +193,11 @@ add_test(tacunitUsage tacunit "--help")
add_test(tocrUsage tocr "--help")
set_tests_properties(
avgttacUsage interpolUsage tac2xmlUsage tac4frplUsage tacaddUsage tacadd0Usage tacblendUsage
taccalcUsage taccrossUsage taccutUsage taccutyUsage tacdelUsage tacdelnaUsage tacformatUsage
tacframeUsage tacinvUsage tacjoinUsage taclistUsage taclnUsage tacmatchUsage tacmeanUsage
tacmidyUsage tacmsampUsage tacmultxUsage tacnamesUsage tacp2fUsage tacrangeUsage tacrenUsage
tacsetxUsage tacsetyUsage tacsortUsage tacsplitUsage tacstudyUsage tactimeUsage
tacunitUsage tocrUsage
taccalcUsage taccatUsage taccrossUsage taccutUsage taccutyUsage tacdelUsage tacdelnaUsage
tacformatUsage tacframeUsage tacinvUsage tacjoinUsage taclistUsage taclnUsage
tacmatchUsage tacmeanUsage tacmidyUsage tacmsampUsage tacmultxUsage tacnamesUsage
tacp2fUsage tacrangeUsage tacrenUsage tacsetxUsage tacsetyUsage tacsortUsage tacsplitUsage
tacstudyUsage tactimeUsage tacunitUsage tocrUsage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage: *"
)
......@@ -240,6 +244,11 @@ add_test (
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test/taccalc
COMMAND bash "./test_taccalc.sh"
)
add_test (
NAME taccatTests
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test/taccat
COMMAND bash "./test_taccat.sh"
)
add_test (
NAME taccrossTests
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test/taccross
......
/** @file taccat.c
* @brief Catenation of two TAC files.
* @copyright (c) Turku PET Centre
* @author Vesa Oikonen
*/
/// @cond
/*****************************************************************************/
#include "tpcclibConfig.h"
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
/*****************************************************************************/
#include "tpcextensions.h"
#include "tpcift.h"
#include "tpctac.h"
/*****************************************************************************/
/*****************************************************************************/
static char *info[] = {
"Catenate the TACs from the second TAC file to the first one, or to a new",
"datafile. Sample times or correction for physical decay are not changed.",
"Each TAC file must contain the same number of TACs, and if more than one TAC,"
"TAC names must match, too.",
" ",
"Usage: @P [options] tacfile1 tacfile2 [catenated_file]",
" ",
"Options:",
" -both | -first | -second | -cut=<time>",
" In case of overlapping samples, either samples from both (-both),",
" first (-first), or second (-second, default) TAC are saved in",
" combined file, or specified cut time is used.",
" Cut time can also be given in file with keys 'x' or 'time'.",
" --force",
" Program does not mind if the time or calibration units cannot be",
" converted to match, or if TAC names do not match.",
" -stdoptions", // List standard options like --help, -v, etc
" ",
"Example:",
" @P t455ap_pump.kbq t455ap_manual.kbq t455ap_combined.kbq",
" ",
"See also: tacblend, taccut, tacadd0, tacadd, tacunit, tactime, taccross",
" ",
"Keywords: TAC, tool, input, blood",
0};
/*****************************************************************************/
/*****************************************************************************/
/* Turn on the globbing of the command line, since it is disabled by default in
mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
In Unix&Linux wildcard command line processing is enabled by default. */
/*
#undef _CRT_glob
#define _CRT_glob -1
*/
int _dowildcard = -1;
/*****************************************************************************/
/*****************************************************************************/
/**
* Main
*/
int main(int argc, char **argv)
{
int ai, help=0, version=0, verbose=1;
char tacfile1[FILENAME_MAX], tacfile2[FILENAME_MAX], outfile[FILENAME_MAX];
int forceMode=0;
/*
* Get arguments
*/
if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
tacfile1[0]=tacfile2[0]=outfile[0]=(char)0;
/* Options */
for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
if(strcasecmp(cptr, "F")==0 || strcasecmp(cptr, "FORCE")==0) {
forceMode=1; continue;
}
fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
return(1);
} else break; // tac name argument may start with '-'
TPCSTATUS status; statusInit(&status);
statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
status.verbose=verbose-3;
/* Print help or version? */
if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
/* Process other arguments, starting from the first non-option */
if(ai<argc) strlcpy(tacfile1, argv[ai++], FILENAME_MAX);
if(ai<argc) strlcpy(tacfile2, argv[ai++], FILENAME_MAX);
if(ai<argc) strlcpy(outfile, argv[ai++], FILENAME_MAX);
if(ai<argc) {fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]); return(1);}
/* Is something missing? */
if(!tacfile2[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
if(!outfile[0]) strcpy(outfile, tacfile1);
/* In verbose mode print arguments and options */
if(verbose>1) {
for(ai=0; ai<argc; ai++) printf("%s ", argv[ai]);
printf("\n");
printf("tacfile1 := %s\n", tacfile1);
printf("tacfile2 := %s\n", tacfile2);
printf("outfile := %s\n", outfile);
printf("forceMode := %d\n", forceMode);
fflush(stdout);
}
/*
* Read the files
*/
TAC tac1, tac2;
tacInit(&tac1); tacInit(&tac2);
if(verbose>1) printf("reading %s\n", tacfile1);
if(tacRead(&tac1, tacfile1, &status)!=TPCERROR_OK) {
fprintf(stderr, "Error: %s\n", errorMsg(status.error));
tacFree(&tac1); tacFree(&tac2); return(2);
}
if(verbose>2) {
printf("fileformat := %s\n", tacFormattxt(tac1.format));
printf("tacNr := %d\n", tac1.tacNr);
printf("sampleNr := %d\n", tac1.sampleNr);
printf("xunit := %s\n", unitName(tac1.tunit));
printf("yunit := %s\n", unitName(tac1.cunit));
}
if(verbose>1) printf("reading %s\n", tacfile2);
if(tacRead(&tac2, tacfile2, &status)!=TPCERROR_OK) {
fprintf(stderr, "Error: %s\n", errorMsg(status.error));
tacFree(&tac1); tacFree(&tac2); return(3);
}
if(verbose>2) {
printf("fileformat := %s\n", tacFormattxt(tac2.format));
printf("tacNr := %d\n", tac2.tacNr);
printf("sampleNr := %d\n", tac2.sampleNr);
printf("xunit := %s\n", unitName(tac2.tunit));
printf("yunit := %s\n", unitName(tac2.cunit));
}
/* Check if the TAC number is different */
if(verbose>1) printf("checking data...\n");
if(tac1.tacNr!=tac2.tacNr) {
fprintf(stderr, "Error: different number of TACs.\n");
tacFree(&tac1); tacFree(&tac2); return(4);
}
/* Check that TAC names match, if more than one TAC */
if(tac1.tacNr>1 && tacCompareNames(&tac1, &tac2, -1, &status)!=0) {
if(forceMode) {
fprintf(stderr, "Warning: TAC names do not match.\n");
} else {
/* Without force mode this is an error, unless sorting helps */
tacSortByName(&tac1, NULL);
tacSortByName(&tac2, NULL);
if(tacCompareNames(&tac1, &tac2, -1, &status)!=0) {
fprintf(stderr, "Error: TAC names do not match.\n");
tacFree(&tac1); tacFree(&tac2); return(4);
}
fprintf(stderr, "Note: TACs sorted by name.\n");
}
}
/* Delete missing samples */
tacDeleteMissingSamples(&tac1);
if(tacNotNaNs(&tac1, -1)<1) {
fprintf(stderr, "Error: no valid samples in %s\n", tacfile1);
tacFree(&tac1); tacFree(&tac2); return(2);
}
tacDeleteMissingSamples(&tac2);
if(tacNotNaNs(&tac2, -1)<1) {
fprintf(stderr, "Error: no valid samples in %s\n", tacfile2);
tacFree(&tac1); tacFree(&tac2); return(3);
}
/* Sort by sample times */
tacSortByTime(&tac1, NULL);
tacSortByTime(&tac2, NULL);
/* Check time units */
if(tac1.tunit==UNIT_UNKNOWN || tac2.tunit==UNIT_UNKNOWN) {
fprintf(stderr, "Warning: unknown time units.\n");
if(forceMode) { // In force mode use what we got
if(tac1.tunit!=UNIT_UNKNOWN) tac2.tunit=tac1.tunit;
else if(tac2.tunit!=UNIT_UNKNOWN) tac1.tunit=tac2.tunit;
}
/* Try to convert time units to time units in the first file */
int ret=tacXUnitConvert(&tac2, tac1.tunit, &status);
if(ret==TPCERROR_UNKNOWN_UNIT) ret=TPCERROR_OK;
if(ret!=TPCERROR_OK) {
if(verbose>2) fprintf(stderr, "Status: %s\n", errorMsg(status.error));
if(!forceMode) {
fprintf(stderr, "Error: non-compatible TAC time units.\n");
tacFree(&tac1); tacFree(&tac2); return(4);
} else {
fprintf(stderr, "Warning: non-compatible TAC time units.\n");
}
}
}
/* If either TAC file only has frame mid times, then both have */
if(tac1.isframe==0) tac2.isframe=0;
else if(tac2.isframe==0) tac1.isframe=0;
/* Check concentration units */
if(tac1.cunit==UNIT_UNKNOWN || tac2.cunit==UNIT_UNKNOWN) {
fprintf(stderr, "Warning: unknown concentration units.\n");
if(forceMode) { // In force mode use what we got
if(tac1.cunit!=UNIT_UNKNOWN) tac2.cunit=tac1.cunit;
else if(tac2.cunit!=UNIT_UNKNOWN) tac1.cunit=tac2.cunit;
}
/* Try to convert concentration units to units in the first file */
int ret=tacYUnitConvert(&tac2, tac1.tunit, &status);
if(ret==TPCERROR_UNKNOWN_UNIT) ret=TPCERROR_OK;
if(ret!=TPCERROR_OK) {
if(!forceMode) {
fprintf(stderr, "Error: non-compatible TAC concentration units.\n");
tacFree(&tac1); tacFree(&tac2); return(4);
} else {
fprintf(stderr, "Warning: non-compatible TAC concentration units.\n");
}
}
}
tacFree(&tac1); tacFree(&tac2);
return(0);
}
/*****************************************************************************/
/*****************************************************************************/
#if(0)
/**
* Main
*/
int main(int argc, char **argv)
{
int ai, help=0, version=0, verbose=1;
int ret;
int checkData=1;
char tacfile[FILENAME_MAX], outfile[FILENAME_MAX];
int fileNr=0, file1=0;
/*
* Get arguments
*/
if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
tacfile[0]=outfile[0]=(char)0;
/* Options */
for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
if(strcasecmp(cptr, "F")==0 || strcasecmp(cptr, "FORCE")==0) {
checkData=0; continue;
}
fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
return(1);
} else break; // tac name argument may start with '-'
TPCSTATUS status; statusInit(&status);
statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
status.verbose=verbose-3;
/* Print help or version? */
if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
/* Process other arguments, starting from the first non-option */
if(ai<argc) strlcpy(outfile, argv[ai++], FILENAME_MAX);
for(; ai<argc; ai++) {
if(fileNr==0) file1=ai;
fileNr++;
}
/* In verbose mode print arguments and options */
if(verbose>1) {
for(ai=0; ai<argc; ai++) printf("%s ", argv[ai]);
printf("\n");
printf("fileNr := %d\n", fileNr);
printf("outfile := %s\n", outfile);
fflush(stdout);
}
/* Is something missing? */
if(!outfile[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
if(fileNr==0) {
fprintf(stderr, "Error: missing command-line argument; try %s --help\n", argv[0]);
return(1);
}
if(fileNr==1) {
fprintf(stderr, "Error: only one input file specified.\n");
return(1);
}
/* Check that all input files do exist, and that their name does not match output file name */
for(ai=file1; ai<argc; ai++) {
strlcpy(tacfile, argv[ai], FILENAME_MAX);
if(access(tacfile, 0) == -1) {
fprintf(stderr, "Error: input file %s does not exist.\n", tacfile);
return(2);
}
if(strcasecmp(outfile, tacfile)==0) {
fprintf(stderr, "Error: input file would be overwritten.\n");
return(2);
}
}
/*
* Read the first file
*/
TAC tac, pool;
tacInit(&tac); tacInit(&pool);
strlcpy(tacfile, argv[file1], FILENAME_MAX);
if(verbose>1) printf("reading %s\n", tacfile);
ret=tacRead(&pool, tacfile, &status);
if(ret!=TPCERROR_OK) {
fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
tacFree(&pool); return(2);
}
if(checkData) tacSortByName(&pool, &status);
if(verbose>2) {
printf("fileformat := %s\n", tacFormattxt(pool.format));
printf("tacNr := %d\n", pool.tacNr);
printf("sampleNr := %d\n", pool.sampleNr);
printf("xunit := %s\n", unitName(pool.tunit));
printf("yunit := %s\n", unitName(pool.cunit));
}
if(tacXNaNs(&pool)>0) {
fprintf(stderr, "Error: missing x values in %s\n", tacfile);
tacFree(&pool); return(2);
}
/*
* Add the data from the other files
*/
int differentTUnits=0;
int differentCUnits=0;
for(ai=file1+1; ai<argc; ai++) {
strlcpy(tacfile, argv[ai], FILENAME_MAX);
if(verbose>1) printf("reading %s\n", tacfile);
ret=tacRead(&tac, tacfile, &status);
if(ret!=TPCERROR_OK) {
fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
tacFree(&pool); tacFree(&tac); return(2);
}
if(checkData) tacSortByName(&tac, &status);
if(verbose>2) {
printf("fileformat := %s\n", tacFormattxt(tac.format));
printf("tacNr := %d\n", tac.tacNr);
printf("sampleNr := %d\n", tac.sampleNr);
printf("xunit := %s\n", unitName(tac.tunit));
printf("yunit := %s\n", unitName(tac.cunit));
}
if(tacXNaNs(&pool)>0) {
fprintf(stderr, "Error: missing x values in %s\n", tacfile);
tacFree(&pool); tacFree(&tac); return(2);
}
/* Check if the TAC number is different */
if(pool.tacNr!=tac.tacNr) {
fprintf(stderr, "Error: different number of TACs.\n");
tacFree(&pool); tacFree(&tac); return(3);
}
/* Check that TAC names match, if requested */
if(checkData && tacCompareNames(&pool, &tac, -1, &status)!=0) {
fprintf(stderr, "Error: TAC names do not match.\n");
tacFree(&pool); tacFree(&tac); return(3);
}
/* Try to convert time units to time units in the first file */
ret=tacXUnitConvert(&tac, pool.tunit, &status);
if(ret==TPCERROR_UNKNOWN_UNIT) ret=TPCERROR_OK;
if(ret!=TPCERROR_OK) {
if(verbose>2) fprintf(stderr, "Status: %s\n", errorMsg(status.error));
if(checkData) {
fprintf(stderr, "Error: non-compatible TAC time units.\n");
tacFree(&pool); tacFree(&tac); return(4);
}
differentTUnits++;
}
/* Try to convert concentration units to time units in the first file */
ret=tacYUnitConvert(&tac, pool.cunit, &status);
if(ret==TPCERROR_UNKNOWN_UNIT) ret=TPCERROR_OK;
if(ret!=TPCERROR_OK) {
if(verbose>2) fprintf(stderr, "Status: %s\n", errorMsg(status.error));
if(checkData) {
fprintf(stderr, "Error: non-compatible TAC concentration units.\n");
tacFree(&pool); tacFree(&tac); return(5);
}
differentCUnits++;
}
/* If at least one of TAC files only has frame mid times, then all have */
if(tac.isframe==0) pool.isframe=0;
/* Add the new sample values */
ret=tacAllocateMoreSamples(&pool, tac.sampleNr);
if(ret!=TPCERROR_OK) {
fprintf(stderr, "Error: cannot allocate memory.\n");
tacFree(&pool); tacFree(&tac); return(6);
}
for(int i=0; i<tac.sampleNr; i++) {
pool.x[pool.sampleNr]=tac.x[i];
pool.x1[pool.sampleNr]=tac.x1[i];
pool.x2[pool.sampleNr]=tac.x2[i];
for(int j=0; j<pool.tacNr; j++) pool.c[j].y[pool.sampleNr]=tac.c[j].y[i];
pool.w[pool.sampleNr]=tac.w[i];
pool.sampleNr++;
}
tacFree(&tac);
}
if(verbose>0 && differentTUnits>1) fprintf(stderr,
"Warning: time units could not be converted for %d file(s).\n", differentTUnits);
if(verbose>0 && differentCUnits>1) fprintf(stderr,
"Warning: concentration units could not be converted for %d file(s).\n", differentCUnits);
/*
* Sort pooled data by sample time
*/
ret=tacSortByTime(&pool, &status);
if(ret!=TPCERROR_OK) {
fprintf(stderr, "Error: cannot sort the pooled data.\n");
tacFree(&pool); return(8);
}
/* Delete study number, if one exists */
(void)tacSetHeaderStudynr(&pool.h, "");
/*
* Save data
*/
if(verbose>1) printf("writing %s\n", outfile);
FILE *fp; fp=fopen(outfile, "w");
if(fp==NULL) {
fprintf(stderr, "Error: cannot open file for writing (%s)\n", outfile);
tacFree(&tac); return(11);
}
ret=tacWrite(&pool, fp, TAC_FORMAT_UNKNOWN, 1, &status);
fclose(fp);
if(ret!=TPCERROR_OK) {
fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
tacFree(&pool); return(12);
}
if(verbose>=0) {
printf("%d samples from %d TAC files pooled.\n", pool.sampleNr, fileNr);
printf("%s saved.\n", outfile);
}
tacFree(&pool);
return(0);
}
#endif
/*****************************************************************************/
/*****************************************************************************/
/// @endcond
#!/bin/bash
#: Title : test_taccat
#: Date : 2020-07-16
#: Author : "Vesa Oikonen" <vesa.oikonen@utu.fi>
#: Options : None
# Set the name of executable to test
if [ -n "${OS+1}" ] && [ "$OS" = "Windows_NT" ]; then
EXT=.exe;
else
EXT=;
fi
PROGRAM=../../taccat$EXT;
if [ ! -f $PROGRAM ]; then
printf "Failed: executable does not exist.\n"
exit 1
fi
printf "=====================================================================\n"
printf "creating test data for %s\n" $PROGRAM
printf "=====================================================================\n"
exit 1
printf "\n\n"
printf "=====================================================================\n"
printf "testing %s\n" $PROGRAM
printf "=====================================================================\n"
printf "\n0.1.0 Unknown option \n\n"
rm -f stdout.txt output.dft
$PROGRAM -stupidoption test1a.dft test1b.dft output.dft &> stdout.txt
if [ $? -eq 0 ] ; then printf "Failed!\n" ; exit 1 ; fi
printf "\n ok \n"
iftisval stdout.txt Error "invalid option '-stupidoption'."
if [ $? -ne 0 ] ; then printf "Failed!\n" ; exit 1 ; fi
printf "\n passed. \n\n"
printf "\n===================================================================\n"
printf "\n0.2.0 Extra argument \n\n"
rm -f stdout.txt output.dft
$PROGRAM test1a.dft test1b.dft output.dft extra &> stdout.txt
if [ $? -eq 0 ] ; then printf "Failed!\n" ; exit 1 ; fi
printf "\n ok \n"
iftisval stdout.txt Error "invalid argument 'extra'."
if [ $? -ne 0 ] ; then printf "Failed!\n" ; exit 1 ; fi
printf "\n passed. \n\n"
printf "\n===================================================================\n"
printf "\n0.3.0 Missing argument \n\n"
rm -f stdout.txt output.dft
$PROGRAM test1a.dft &> stdout.txt
if [ $? -eq 0 ] ; then printf "Failed!\n" ; exit 1 ; fi
printf "\n ok \n"
printf "\n===================================================================\n"
printf "\n0.4.0 file 1 does not exist \n\n"