TPCCLIB
Loading...
Searching...
No Matches
simdisp.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#include "tpccm.h"
21#include "tpctacmod.h"
22/*****************************************************************************/
23
24/*****************************************************************************/
25static char *info[] = {
26 "Simulation or correction of input curve dispersion and delay.",
27 " ",
28 "Usage: @P [Options] tacfile dispersion delay [outputfile] ",
29 " ",
30 "Options:",
31 " -stdoptions", // List standard options like --help, -v, etc
32 " ",
33 "If file name for output is not given, then the TAC file is modified.",
34 "The units of dispersion and delay time must be the same as sample time",
35 "units of the TAC.",
36 "Negative values can be used to correct the TAC for dispersion and/or delay.",
37 "Zero can be given for dispersion time constant or delay time.",
38 "Simulated data is saved with original sample times.",
39 "For accurate results, input TAC should have very short sampling intervals,",
40 "and in case of dispersion correction also noise-free.",
41 " ",
42 "Example of dispersion and delay simulation:",
43 " @P blood.tac 5.0 17 simulated.tac",
44 " ",
45 "Example of dispersion and delay correction:",
46 " @P blood.tac -5.0 -15 corrected.tac",
47 " ",
48 "Reference:",
49 " Iida H, Kanno I, Miura S, Murakami M, Takahashi K, Uemura K. Error",
50 " analysis of a quantitative cerebral blood flow measurement using H215O",
51 " autoradiography and positron emission tomography, with respect to the",
52 " dispersion of the input function.",
53 " J Cereb Blood Flow Metab. 1986;6:536-545.",
54 " https://doi.org/10.1038/jcbfm.1986.99",
55 " ",
56 "See also: conv1tcm, convexpf, sim_av, interpol, tactime, fitdelay",
57 " ",
58 "Keywords: TAC, input, blood, simulation, dispersion, time delay",
59 0};
60/*****************************************************************************/
61
62/*****************************************************************************/
63/* Turn on the globbing of the command line, since it is disabled by default in
64 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
65 In Unix&Linux wildcard command line processing is enabled by default. */
66/*
67#undef _CRT_glob
68#define _CRT_glob -1
69*/
70int _dowildcard = -1;
71/*****************************************************************************/
72
73/*****************************************************************************/
77int main(int argc, char **argv)
78{
79 int ai, help=0, version=0, verbose=1;
80 char tacfile[FILENAME_MAX], simfile[FILENAME_MAX];
81 double dispersion=nan(""), delay=nan("");
82
83
84 /*
85 * Get arguments
86 */
87 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
88 tacfile[0]=simfile[0]=(char)0;
89 /* Options */
90 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
91 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
92 //char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
93 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
94 return(1);
95 } else break; // tac name argument may start with '-'
96
97 TPCSTATUS status; statusInit(&status);
98 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
99 status.verbose=verbose-1;
100
101 /* Print help or version? */
102 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
103 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
104 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
105
106 /* Process other arguments, starting from the first non-option */
107 if(ai<argc) {strlcpy(tacfile, argv[ai++], FILENAME_MAX);}
108 if(ai<argc) {
109 dispersion=atofVerified(argv[ai]);
110 if(!isfinite(dispersion)) {fprintf(stderr, "Error: invalid dispersion '%s'.\n", argv[ai]); return(1);}
111 ai++;
112 }
113 if(ai<argc) {
114 delay=atofVerified(argv[ai]);
115 if(!isfinite(delay)) {fprintf(stderr, "Error: invalid delay '%s'.\n", argv[ai]); return(1);}
116 ai++;
117 }
118 if(ai<argc) {strlcpy(simfile, argv[ai++], FILENAME_MAX);}
119 if(ai<argc) {
120 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
121 return(1);
122 }
123
124 /* Is something missing? */
125 if(isnan(delay)) {
126 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
127 fflush(stderr); return(1);
128 }
129 if(dispersion==0.0 && delay==0.0) {
130 fprintf(stderr, "Warning: neither dispersion or delay effect simulated.\n");
131 fflush(stderr);
132 }
133 if(!simfile[0]) strcpy(simfile, tacfile);
134
135
136 /* In verbose mode print arguments and options */
137 if(verbose>1) {
138 printf("tacfile := %s\n", tacfile);
139 printf("simfile := %s\n", simfile);
140 printf("dispersion := %g\n", dispersion);
141 printf("delay := %g\n", delay);
142 fflush(stdout);
143 }
144
145
146 /*
147 * Read plasma TAC
148 */
149 if(verbose>1) fprintf(stdout, "reading %s\n", tacfile);
150 TAC tac; tacInit(&tac);
151 if(tacRead(&tac, tacfile, &status)!=TPCERROR_OK) {
152 fprintf(stderr, "Error: %s (%s)\n", errorMsg(status.error), tacfile);
153 tacFree(&tac); return(2);
154 }
155 if(verbose>2) {
156 printf("fileformat := %s\n", tacFormattxt(tac.format));
157 printf("tacNr := %d\n", tac.tacNr);
158 printf("sampleNr := %d\n", tac.sampleNr);
159 printf("xunit := %s\n", unitName(tac.tunit));
160 printf("yunit := %s\n", unitName(tac.cunit));
161 if(tacIsWeighted(&tac)) printf("weighting := yes\n");
162 }
163 /* Check for missing sample times */
164 if(tacXNaNs(&tac)>0) {
165 fprintf(stderr, "Error: missing frame times.\n");
166 tacFree(&tac); return(2);
167 }
168 /* Check for missing concentrations */
169 if(tacYNaNs(&tac, -1)>0) {
170 fprintf(stderr, "Error: missing concentrations.\n");
171 tacFree(&tac); return(2);
172 }
173 if(tac.sampleNr<3) {
174 fprintf(stderr, "Error: too few samples in plasma data.\n");
175 tacFree(&tac); return(2);
176 }
177 if(tac.tacNr>1) {
178 fprintf(stderr, "Warning: file contains %d TACs.\n", tac.tacNr);
179 fflush(stderr);
180 }
181 if(tacSortByTime(&tac, &status)!=TPCERROR_OK) {
182 fprintf(stderr, "Error: invalid sample times.\n");
183 tacFree(&tac); return(2);
184 }
185 if(tac.isframe!=0 && verbose>0) {
186 if(tacSetX(&tac, &status)!=TPCERROR_OK) { // make sure that frame middle times are set
187 fprintf(stderr, "Error: invalid sample times.\n");
188 tacFree(&tac); return(2);
189 }
190 }
191
192 /*
193 * Make copy of the original data
194 */
195 TAC stac; tacInit(&stac);
196 {
197 int ret=tacDuplicate(&tac, &stac);
198 if(ret!=TPCERROR_OK) {
199 fprintf(stderr, "Error: %s.\n", errorMsg(ret));
200 tacFree(&tac); return(3);
201 }
202 }
203
204 /*
205 * Apply delay time
206 */
207 if(delay>0.0) {
208 if(verbose>1) {fprintf(stdout, "simulating delay...\n"); fflush(stdout);}
209 for(int i=0; i<stac.sampleNr; i++) {stac.x[i]+=delay; stac.x1[i]+=delay; stac.x2[i]+=delay;}
210 if(tacAddZeroSample(&stac, &status)!=TPCERROR_OK) {
211 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
212 tacFree(&tac); tacFree(&stac); return(4);
213 }
214 } else if(delay<0.0) {
215 if(verbose>1) {fprintf(stdout, "removing delay...\n"); fflush(stdout);}
216 for(int i=0; i<stac.sampleNr; i++) {
217 stac.x[i]+=delay;
218 if(stac.x[i]>=0.0) {stac.x1[i]+=delay; stac.x2[i]+=delay;}
219 else stac.x[i]=stac.x1[i]=stac.x2[i]=nan("");
220 }
221 if(tacDeleteMissingSamples(&stac)!=TPCERROR_OK || stac.sampleNr<2) {
222 fprintf(stderr, "Error: invalid delay correction for the data.\n");
223 tacFree(&tac); tacFree(&stac); return(4);
224 }
225 }
226
227 /*
228 * Simulate dispersion
229 */
230 if(dispersion>0.0) {
231 if(verbose>1) {fprintf(stdout, "simulating dispersion...\n"); fflush(stdout);}
232 double *t=(double*)malloc(stac.sampleNr*sizeof(double));
233 if(t==NULL) {
234 fprintf(stderr, "Error: cannot allocate memory.\n");
235 tacFree(&tac); tacFree(&stac); return(5);
236 }
237 int ret=0;
238 for(int i=0; i<stac.tacNr; i++) {
239 ret=simDispersion(stac.x, stac.c[i].y, stac.sampleNr, dispersion, 0.0, t);
240 if(ret!=TPCERROR_OK) break;
241 }
242 free(t);
243 if(ret!=TPCERROR_OK) {
244 fprintf(stderr, "Error: cannot calculate dispersed curve.\n");
245 tacFree(&tac); tacFree(&stac); return(5);
246 }
247 } else if(dispersion<0.0) {
248 if(verbose>1) {fprintf(stdout, "correcting dispersion...\n"); fflush(stdout);}
249 double *t=(double*)malloc(stac.sampleNr*sizeof(double));
250 if(t==NULL) {
251 fprintf(stderr, "Error: cannot allocate memory.\n");
252 tacFree(&tac); tacFree(&stac); return(5);
253 }
254 int ret=0;
255 for(int i=0; i<stac.tacNr; i++) {
256 ret=corDispersion(stac.x, stac.c[i].y, stac.sampleNr, -dispersion, t);
257 if(ret!=TPCERROR_OK) break;
258 }
259 free(t);
260 if(ret!=TPCERROR_OK) {
261 fprintf(stderr, "Error: cannot calculate dispersion corrected curve.\n");
262 tacFree(&tac); tacFree(&stac); return(5);
263 }
264 }
265
266 /*
267 * Interpolate modified data into original sample times
268 */
269 {
270 if(verbose>1) {fprintf(stdout, "interpolating to original sample times...\n"); fflush(stdout);}
271 int ret=0;
272 if(tac.isframe==0) {
273 for(int i=0; i<stac.tacNr; i++) {
274 ret=liInterpolate(stac.x, stac.c[i].y, stac.sampleNr, tac.x, tac.c[i].y, NULL, NULL,
275 tac.sampleNr, 4, 1, verbose-10);
276 if(ret!=TPCERROR_OK) break;
277 }
278 } else {
279 for(int i=0; i<stac.tacNr; i++) {
280 ret=liInterpolateForPET(stac.x, stac.c[i].y, stac.sampleNr, tac.x1, tac.x2, tac.c[i].y,
281 NULL, NULL, tac.sampleNr, 4, 1, verbose-10);
282 if(ret!=TPCERROR_OK) break;
283 }
284 }
285 if(ret!=TPCERROR_OK) {
286 fprintf(stderr, "Error: cannot interpolate back.\n");
287 tacFree(&tac); tacFree(&stac); return(6);
288 }
289 }
290 tacFree(&stac);
291
292
293 /*
294 * Write the file
295 */
296 {
297 if(verbose>1) printf("writing noisy data in %s\n", simfile);
298 FILE *fp; fp=fopen(simfile, "w");
299 if(fp==NULL) {
300 fprintf(stderr, "Error: cannot open file for writing (%s)\n", simfile);
301 tacFree(&tac); return(11);
302 }
303 int ret=tacWrite(&tac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
304 fclose(fp); tacFree(&tac);
305 if(ret!=TPCERROR_OK) {
306 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
307 return(12);
308 }
309 if(verbose>=0) printf("Simulated TAC saved in %s\n", simfile);
310 }
311
312 return(0);
313}
314/*****************************************************************************/
316/*****************************************************************************/
double atofVerified(const char *s)
Definition decpoint.c:75
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
int simDispersion(double *x, double *y, const int n, const double tau1, const double tau2, double *tmp)
int corDispersion(double *x, double *y, const int n, const double tau, double *tmp)
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:632
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 tacDuplicate(TAC *tac1, TAC *tac2)
Make a duplicate of TAC structure.
Definition tac.c:356
void tacInit(TAC *tac)
Definition tac.c:24
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 tacYNaNs(TAC *tac, const int i)
Definition tacnan.c:47
int tacXNaNs(TAC *tac)
Definition tacnan.c:23
int tacSortByTime(TAC *d, TPCSTATUS *status)
Definition tacorder.c:74
int tacIsWeighted(TAC *tac)
Definition tacw.c:24
int tacDeleteMissingSamples(TAC *d)
Delete those samples (time frames) from TAC structure, which contain only missing y values,...
Definition tacx.c:450
int tacAddZeroSample(TAC *d, TPCSTATUS *status)
Add an initial sample to TAC(s) with zero time and concentration.
Definition tacx.c:366
int tacSetX(TAC *d, TPCSTATUS *status)
Set TAC x values based on x1 and x2 values, or guess x1 and x2 values based on x values.
Definition tacx.c:653
Header file for libtpccm.
Header file for library libtpcextensions.
@ 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
Header file for libtpctacmod.