TPCCLIB
Loading...
Searching...
No Matches
taccalc.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 "tpcift.h"
18#include "tpctac.h"
19#include "tpcli.h"
20/*****************************************************************************/
21
22/*****************************************************************************/
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",
26 "a constant value.",
27 " ",
28 "Usage: @P [options] file1 operation constant|file2|x outputfile",
29 " ",
30 "Options:",
31 " --force",
32 " Program does not mind if the time or calibration units",
33 " cannot be converted to match.",
34 " -stdoptions", // List standard options like --help, -v, etc
35 " ",
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",
42 " ",
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.",
49 " ",
50 "The following characters are accepted as operators: +, -, x, and :, or",
51 "'plus', 'minus', 'mult', and 'div'.",
52 " ",
53 "See also: tacunit, metabcor, dftsuv, dftratio, taccbv, fit2dat, tacinv",
54 " ",
55 "Keywords: TAC, modelling, simulation, tool",
56 0};
57/*****************************************************************************/
58
59/*****************************************************************************/
60/* Turn on the globbing of the command line, since it is disabled by default in
61 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
62 In Unix&Linux wildcard command line processing is enabled by default. */
63/*
64#undef _CRT_glob
65#define _CRT_glob -1
66*/
67int _dowildcard = -1;
68/*****************************************************************************/
69
70/*****************************************************************************/
74int main(int argc, char **argv)
75{
76 int ai, help=0, version=0, verbose=1;
77 int ret;
78 int operation=0; // 1=+, 2=-, 3=*, 4=:
79 int isvalue=0;
80 int usex=0;
81 int checkUnits=1;
82 char *cptr, d1file[FILENAME_MAX], d2file[FILENAME_MAX], rfile[FILENAME_MAX];
83 double value=0.0;
84 TAC tac1, tac2, itac2;
85
86
87 /*
88 * Get arguments
89 */
90 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
91 tacInit(&tac1); tacInit(&tac2); tacInit(&itac2);
92 d1file[0]=d2file[0]=rfile[0]=(char)0;
93 /* Options */
94 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
95 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
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) {
100 // just for compatibility with prev version
101 checkUnits=0; continue;
102 }
103 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
104 return(1);
105 } else break; // tac name argument may start with '-'
106
107 TPCSTATUS status; statusInit(&status);
108 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
109 status.verbose=verbose-1;
110
111 /* Print help or version? */
112 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
113 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
114 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
115
116 /* Arguments */
117 if(ai<argc) {strlcpy(d1file, argv[ai++], FILENAME_MAX);}
118 if(ai<argc) {
119 if(strcasecmp(argv[ai], "PLUS")==0) {
120 operation=1;
121 } else if(strcasecmp(argv[ai], "MINUS")==0) {
122 operation=2;
123 } else if(strncasecmp(argv[ai], "MULTIPLY", 4)==0) {
124 operation=3;
125 } else if(strncasecmp(argv[ai], "DIVIDE", 3)==0) {
126 operation=4;
127 } else if(*argv[ai]=='+') {
128 operation=1;
129 } else if(*argv[ai]=='-') {
130 operation=2;
131 } else if(*argv[ai]=='*' || *argv[ai]=='.' || *argv[ai]=='X' || *argv[ai]=='x') {
132 // '*' might be hard to use, but accept it here anyway
133 operation=3;
134 } else if(*argv[ai]=='/' || *argv[ai]==':') {
135 // MinGW does not work with '/', it requires '//'
136 operation=4;
137 } else {
138 fprintf(stderr, "Error: invalid operator.\n");
139 return(1);
140 }
141 ai++;
142 }
143 if(ai<argc) {
144 ret=atofCheck(argv[ai], &value);
145 if(ret==0) {
146 isvalue=1;
147 } else {
148 if(strcasecmp(argv[ai], "X")) strcpy(d2file, argv[ai]); else usex=1;
149 }
150 ai++;
151 }
152 if(ai<argc) {strlcpy(rfile, argv[ai++], FILENAME_MAX);}
153 if(ai<argc) {
154 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
155 return(1);
156 }
157
158 /* Is something missing? */
159 if(!rfile[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
160
161
162 /* In verbose mode print arguments and options */
163 if(verbose>1) {
164 for(ai=0; ai<argc; ai++) printf("%s ", argv[ai]);
165 printf("\n");
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);
173 fflush(stdout);
174 }
175
176
177 /*
178 * Read the file #1
179 */
180 if(verbose>1) printf("reading %s\n", d1file);
181 ret=tacRead(&tac1, d1file, &status);
182 if(ret!=TPCERROR_OK) {
183 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
184 tacFree(&tac1); return(2);
185 }
186 if(verbose>2) {
187 printf("fileformat := %s\n", tacFormattxt(tac1.format));
188 printf("tacNr := %d\n", tac1.tacNr);
189 printf("sampleNr := %d\n", tac1.sampleNr);
190 printf("xunit := %s\n", unitName(tac1.tunit));
191 printf("yunit := %s\n", unitName(tac1.cunit));
192 }
193
194
195 /*
196 * Read data file #2, if necessary
197 */
198 if(isvalue==0 && d2file[0]) {
199
200 if(verbose>1) printf("reading %s\n", d1file);
201 ret=tacRead(&tac2, d2file, &status);
202 if(ret!=TPCERROR_OK) {
203 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
204 tacFree(&tac1); tacFree(&tac2); return(3);
205 }
206 if(verbose>2) {
207 printf("fileformat := %s\n", tacFormattxt(tac2.format));
208 printf("tacNr := %d\n", tac2.tacNr);
209 printf("sampleNr := %d\n", tac2.sampleNr);
210 printf("xunit := %s\n", unitName(tac2.tunit));
211 printf("yunit := %s\n", unitName(tac2.cunit));
212 }
213 /* If file contains only one sample, then use that as a constant */
214 if(tac2.sampleNr==1 && tac2.tacNr==1) {
215 if(verbose>2) printf("file #2 contains the constant.\n");
216 /* Convert conc units, if necessary and possible */
217 ret=tacYUnitConvert(&tac2, tac1.cunit, &status);
218 if(ret!=TPCERROR_OK && verbose>1) {
219 fprintf(stderr, "Note: %s and %s have different or unknown concentration units.\n",
220 d1file, d2file);
221 if(verbose>2) fprintf(stderr, "Status: %s\n", errorMsg(status.error));
222 }
223 /* Error does not matter, if user told so */
224 if(!checkUnits) ret=TPCERROR_OK;
225 /* Neither does it matter if unitless, and multiplication or division */
226 if(tac2.cunit==UNIT_UNITLESS && (operation==3 || operation==4)) ret=TPCERROR_OK;
227 /* If none of the previous excuses can be accepted, then exit */
228 if(ret!=TPCERROR_OK) {
229 fprintf(stderr, "Error: %s.\n", errorMsg(status.error));
230 tacFree(&tac1); tacFree(&tac2); return(3);
231 }
232 isvalue=1;
233 value=tac2.c[0].y[0];
234 if(verbose>1) printf("using %g as the constant value.\n", value);
235 tacFree(&tac2);
236 }
237 }
238
239 /* Continue processing data # 2, if necessary */
240 if(tac2.sampleNr>0) {
241
242 /* Check if the TAC numbers are different */
243 if(tac1.tacNr!=tac2.tacNr) {
244 if(tac2.sampleNr<2) {
245 /* Different TAC nr and only one sample in data #2; probably user
246 gave files in wrong order or wrong files */
247 fprintf(stderr, "Error: cannot operate the files.\n");
248 tacFree(&tac1); tacFree(&tac2); return(4);
249 }
250 /* We have >1 samples in data #2, that seems fair */
251 if(tac2.tacNr>1) {
252 /* We will use just the first TAC in data #2; note the user only if
253 file #2 contains more than one TAC */
254 if(verbose>0) fprintf(stderr, "Note: using only the first TAC.\n");
255 tac2.tacNr=1;
256 }
257 }
258
259 /* Try to convert time units in data #2 to time units in data #1 */
260 ret=tacXUnitConvert(&tac2, tac1.tunit, &status);
261 if(ret!=TPCERROR_OK && verbose>1) {
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));
264 }
265 /* Error does not matter, if user told so */
266 if(!checkUnits) ret=TPCERROR_OK;
267 /* .. or if data #2 has only one sample time and data #1 has more */
268 if(tac1.tacNr>1 && tac2.tacNr==1) {
269 if(ret!=TPCERROR_OK && verbose>0) // but give a warning
270 fprintf(stderr, "Warning: unknown time units.\n");
271 ret=TPCERROR_OK;
272 }
273 /* If none of the previous excuses can be accepted, then exit */
274 if(ret!=TPCERROR_OK) {
275 fprintf(stderr, "Error: %s.\n", errorMsg(status.error));
276 tacFree(&tac1); tacFree(&tac2); return(3);
277 }
278
279 /* Try to convert conc units in data #2 to conc units in data #1 */
280 ret=tacYUnitConvert(&tac2, tac1.cunit, &status);
281 if(ret!=TPCERROR_OK && verbose>1) {
282 fprintf(stderr, "Note: %s and %s have different or unknown concentration units.\n",
283 d1file, d2file);
284 if(verbose>2) fprintf(stderr, "Status: %s\n", errorMsg(status.error));
285 }
286 /* Error does not matter, if user told so */
287 if(!checkUnits) ret=TPCERROR_OK;
288 /* .. or if either is unitless, and multiplication or division */
289 if(tac1.cunit==UNIT_UNITLESS || tac2.cunit==UNIT_UNITLESS)
290 if(operation==3 || operation==4)
291 ret=TPCERROR_OK;
292 /* If none of the previous excuses can be accepted, then exit */
293 if(ret!=TPCERROR_OK) {
294 fprintf(stderr, "Error: %s.\n", errorMsg(status.error));
295 tacFree(&tac1); tacFree(&tac2); return(3);
296 }
297
298 /* Allocate memory for interpolated data #2 */
299 // tacNr in interpolated data will be either 1 or equal to tacNr in data #1
300 ret=tacAllocate(&itac2, tac1.sampleNr, tac2.tacNr);
301 if(ret!=TPCERROR_OK) {
302 fprintf(stderr, "Error: cannot interpolate TAC.\n");
303 tacFree(&tac1); tacFree(&tac2); tacFree(&itac2); return(4);
304 }
305 itac2.sampleNr=tac1.sampleNr; itac2.tacNr=tac2.tacNr;
306 /* Copy the headers from file #2 */
307 ret=tacCopyHdr(&tac2, &itac2);
308 for(int i=0; i<tac2.tacNr && ret==TPCERROR_OK ; i++)
309 ret=tacCopyTacchdr(&tac2.c[i], &itac2.c[i]);
310 /* Copy sample times from data #1 */
311 tacXCopy(&tac1, &itac2, 0, itac2.sampleNr-1);
312 itac2.isframe=tac1.isframe;
313
314 /*
315 * Copy or interpolate concentrations
316 */
317 if(tac2.sampleNr==1) {
318 /* If just one sample time, then use that for all samples in data #1 */
319 if(verbose>1) printf("using first sample in %s for all samples in %s\n", d2file, d1file);
320 // we have already checked that we now have same nr of TACs
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];
324 } else {
325 /* more than one sample times */
326 int ri, fi;
327 /* Check whether sample times in data #1 and data #2 are the same,
328 so that we do not interpolate unnecessarily */
329 if(itac2.sampleNr<=tac2.sampleNr && tacXMatch(&tac1, &tac2, verbose-1)) {
330 if(verbose>1) printf("sample times match; no interpolation necessary\n");
331 for(ri=0; ri<itac2.tacNr; ri++)
332 for(fi=0; fi<itac2.sampleNr; fi++)
333 itac2.c[ri].y[fi]=tac2.c[ri].y[fi];
334 } else {
335 if(verbose>1) printf("interpolating\n");
336
337 /* Check the time range */
338 double xmin1, xmin2, xmax1, xmax2, xmin, xmax, xrange;
339 tacXRange(&tac1, &xmin1, &xmax1);
340 tacXRange(&tac2, &xmin2, &xmax2);
341 xmin=xmin1; if(xmin2<xmin) xmin=xmin2;
342 xmax=xmax1; if(xmax2>xmax) xmax=xmax2;
343 xrange=xmax-xmin;
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");
346 }
347
348 /* Interpolate */
349 for(ri=0, ret=0; ri<itac2.tacNr && ret==0; ri++) {
350 if(itac2.isframe)
351 ret=liInterpolateForPET(tac2.x, tac2.c[ri].y, tac2.sampleNr,
352 itac2.x1, itac2.x2, itac2.c[ri].y, NULL, NULL, itac2.sampleNr, 4, 1, verbose-6);
353 if(itac2.isframe==0 || ret!=0)
354 ret=liInterpolate(tac2.x, tac2.c[ri].y, tac2.sampleNr,
355 itac2.x, itac2.c[ri].y, NULL, NULL, itac2.sampleNr, 4, 1, verbose-6);
356 }
357 if(ret!=0) {
358 fprintf(stderr, "Error: cannot interpolate TAC %d.\n", 1+ri);
359 if(verbose>1) fprintf(stderr, "error_code := %d\n", ret);
360 tacFree(&tac1); tacFree(&tac2); tacFree(&itac2); return(5);
361 }
362 }
363 }
364 if(verbose>4) tacWrite(&itac2, stdout, TAC_FORMAT_PMOD, 0, NULL);
365 /* data #2 is not needed later */
366 tacFree(&tac2);
367 }
368
369 /*
370 * Make data with x values as concentrations, if requested
371 */
372 if(usex) {
373 ret=tacAllocate(&itac2, tac1.sampleNr, 1);
374 if(ret!=TPCERROR_OK) {
375 fprintf(stderr, "Error: cannot allocate memory.\n");
376 tacFree(&tac1); tacFree(&tac2); tacFree(&itac2); return(4);
377 }
378 itac2.sampleNr=tac1.sampleNr; itac2.tacNr=1;
379 /* Copy sample times from data #1 */
380 tacXCopy(&tac1, &itac2, 0, itac2.sampleNr-1);
381 itac2.isframe=tac1.isframe;
382 if(itac2.isframe)
383 for(int i=0; i<itac2.sampleNr; i++) itac2.c[0].y[i]=0.5*(itac2.x1[i]+itac2.x2[i]);
384 else
385 for(int i=0; i<itac2.sampleNr; i++) itac2.c[0].y[i]=itac2.x[i];
386 }
387
388 /*
389 * Check the constant value
390 */
391 if(isvalue) {
392 if(!isfinite(value)) {
393 fprintf(stderr, "Error: invalid value of constant.\n");
394 tacFree(&tac1); tacFree(&itac2); return(1);
395 }
396 if(operation==4 && fabs(value)<1.0E-12) {
397 fprintf(stderr, "Error: invalid constant for division.\n");
398 tacFree(&tac1); tacFree(&itac2); return(1);
399 }
400 }
401
402
403 /*
404 * Do the operation (not with NaNs)
405 */
406 if(isvalue) {
407 if(verbose>1) printf("computing with constant\n");
408 int ri, fi;
409 switch(operation) {
410 case 1: /* Add */
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;
413 break;
414 case 2: /* Subtract */
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;
417 break;
418 case 3: /* Multiply */
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;
421 break;
422 case 4: /* Divide; already verified that !=0 */
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;
425 break;
426 }
427 } else {
428 if(verbose>1) printf("computing with TACs\n");
429 int ri, fi;
430 double *y1, *y2;
431 switch(operation) {
432 case 1: /* Add */
433 for(ri=0; ri<tac1.tacNr; ri++) {
434 y1=tac1.c[ri].y;
435 if(itac2.tacNr==1) y2=itac2.c[0].y; else y2=itac2.c[ri].y;
436 for(fi=0; fi<tac1.sampleNr; fi++)
437 if(isfinite(y1[fi]) && isfinite(y2[fi])) y1[fi]+=y2[fi]; else y1[fi]=nan("");
438 }
439 break;
440 case 2: /* Subtract */
441 for(ri=0; ri<tac1.tacNr; ri++) {
442 y1=tac1.c[ri].y;
443 if(itac2.tacNr==1) y2=itac2.c[0].y; else y2=itac2.c[ri].y;
444 for(fi=0; fi<tac1.sampleNr; fi++)
445 if(isfinite(y1[fi]) && isfinite(y2[fi])) y1[fi]-=y2[fi]; else y1[fi]=nan("");
446 }
447 break;
448 case 3: /* Multiply */
449 for(ri=0; ri<tac1.tacNr; ri++) {
450 y1=tac1.c[ri].y;
451 if(itac2.tacNr==1) y2=itac2.c[0].y; else y2=itac2.c[ri].y;
452 for(fi=0; fi<tac1.sampleNr; fi++)
453 if(isfinite(y1[fi]) && isfinite(y2[fi])) y1[fi]*=y2[fi]; else y1[fi]=nan("");
454 }
455 break;
456 case 4: /* Divide */
457 for(ri=0; ri<tac1.tacNr; ri++) {
458 y1=tac1.c[ri].y;
459 if(itac2.tacNr==1) y2=itac2.c[0].y; else y2=itac2.c[ri].y;
460 for(fi=0; fi<tac1.sampleNr; fi++) {
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];
463 }
464 }
465 tac1.cunit=UNIT_UNITLESS;
466 break;
467 }
468 }
469 tacFree(&itac2);
470
471
472 /*
473 * Save data
474 */
475 if(verbose>1) printf("writing %s\n", rfile);
476 FILE *fp; fp=fopen(rfile, "w");
477 if(fp==NULL) {
478 fprintf(stderr, "Error: cannot open file for writing (%s)\n", rfile);
479 tacFree(&tac1); return(11);
480 }
481 ret=tacWrite(&tac1, fp, TAC_FORMAT_UNKNOWN, 1, &status);
482 fclose(fp); tacFree(&tac1);
483 if(ret!=TPCERROR_OK) {
484 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
485 return(12);
486 }
487 if(verbose>=0) printf("%s saved.\n", rfile);
488
489 return(0);
490}
491/*****************************************************************************/
492
493/*****************************************************************************/
int atofCheck(const char *s, double *v)
Definition decpoint.c:94
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)
Definition proginfo.c:47
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 strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:630
double * y
Definition tpctac.h:75
Definition tpctac.h:87
double * x
Definition tpctac.h:97
unit cunit
Definition tpctac.h:105
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
int isframe
Definition tpctac.h:95
TACC * c
Definition tpctac.h:117
double * x2
Definition tpctac.h:101
unit tunit
Definition tpctac.h:109
double * x1
Definition tpctac.h:99
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
void tacFree(TAC *tac)
Definition tac.c:106
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
Definition tac.c:130
void tacInit(TAC *tac)
Definition tac.c:24
int tacCopyTacchdr(TACC *d1, TACC *d2)
Definition tac.c:282
int tacCopyHdr(TAC *tac1, TAC *tac2)
Copy TAC header data from tac1 to tac2.
Definition tac.c:310
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
int tacYUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:72
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:23
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.
Definition tacx.c:249
int tacXCopy(TAC *tac1, TAC *tac2, int i1, int i2)
Definition tacx.c:24
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Definition tacx.c:124
Header file for library libtpcextensions.
@ UNIT_UNITLESS
Unitless.
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.
Header file for libtpcli.
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28
@ TAC_FORMAT_PMOD
PMOD TAC format.
Definition tpctac.h:33