9#include "tpcclibConfig.h"
24static char *info[] = {
25 "Add or remove the sample (time frame) weighting information to TAC file for",
26 "parameter estimations and curve fitting using formula (Mazoyer et al, 1986):",
27 " weight=(frame duration)^2 / (decay corrected trues in a frame)",
29 " weight=(frame duration),",
31 " weight=(frame duration)*exp(-t*ln(2)/halflife),",
33 "TACs are assumed to be corrected for decay, and SIFs not corrected.",
34 "The relative weights are adjusted using a scan information file (SIF),",
35 "or TACs in the file (volume weighted average of all TACs or given TAC);",
36 "in the latter case the units in TAC file must be set correctly.",
38 "Usage: @P [Options] tacfile [sif | tacname]",
42 " Existing weights are removed.",
44 " Weights are not calculated, but existing weights are printed on screen.",
45 " Return code is non-zero if data does not contain weights.",
47 " With -wf Weights are based only on frame length or sampling interval.",
48 " With -wfd the late frames are given less weight by using formula:",
49 " weight=(frame duration)*exp(-t*ln(2)/halflife) (Thiele et al, 2008).",
51 " Isotope, for example C-11, in case it is not found inside SIF or TAC",
52 " file. Isotope is only needed with SIF, and with option -wfd.",
54 " Weights are moderated by limiting the ratio of maximum and minimum",
55 " weights to the given ratio (100 by default). Weights that are lower",
56 " than maximum/ratio are set to maximum/ratio. Enter zero to not",
57 " moderate the weights. Otherwise ratio must be larger than one.",
59 " SIF data based on TAC file is written in given file; cannot be used",
60 " if SIF is given as argument.",
63 "Note that absolute weights cannot be calculated. Relative weights are",
64 "scaled so that average weight is 1.0 for frames that have weight above 0.",
67 "1. Mazoyer BM, Huesman RH, Budinger TF, Knittel BL. Dynamic PET data",
68 " analysis. J Comput Assist Tomogr 1986; 10:645-653.",
69 "2. Thiele F, Buchert R. Evaluation of non-uniform weighting in non-linear",
70 " regression for pharmacokinetic neuroreceptor modelling.",
71 " Nucl Med Commun. 2008; 29:179-188.",
73 "See also: sifcat, sifisot, taclist, imgweigh, tacframe, imghead, tacdecay",
75 "Keywords: TAC, SIF, modelling, weighting, fitting",
94int main(
int argc,
char **argv)
96 int ai, help=0, version=0, verbose=1;
97 char siffile[FILENAME_MAX], tacfile[FILENAME_MAX], newsif[FILENAME_MAX];
98 double weight_moderate=100.0;
100 int remove_weights=0;
108 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
109 siffile[0]=tacfile[0]=newsif[0]=(char)0;
111 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
113 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
114 if(strncasecmp(cptr,
"LIST", 1)==0) {
115 print_weights=1;
continue;
116 }
else if(strcasecmp(cptr,
"RM")==0 || strcasecmp(cptr,
"DEL")==0) {
117 remove_weights=1;
continue;
118 }
else if(strncasecmp(cptr,
"I=", 2)==0) {
120 fprintf(stderr,
"Error: invalid isotope '%s'.\n", cptr+2);
return(1);}
122 }
else if(strncasecmp(cptr,
"SIF=", 4)==0) {
123 cptr+=4;
strlcpy(newsif, cptr, FILENAME_MAX);
if(strlen(newsif)>0)
continue;
124 }
else if(strncasecmp(cptr,
"moderate=", 9)==0) {
126 if(weight_moderate>1.0)
continue;
127 if(weight_moderate<=0.0)
continue;
128 }
else if(strcasecmp(cptr,
"WF")==0) {
130 }
else if(strcasecmp(cptr,
"WFD")==0) {
133 fprintf(stderr,
"Error: invalid option '%s'\n", argv[ai]);
138 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
147 if(ai<argc) {
strlcpy(tacfile, argv[ai++], FILENAME_MAX);}
148 if(ai<argc) {
strlcpy(siffile, argv[ai++], FILENAME_MAX);}
150 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
154 fprintf(stderr,
"Warning: using options -wf and -wfd with SIF is not recommended.\n");
159 fprintf(stderr,
"Error: missing file name; use option --help\n");
165 printf(
"tacfile := %s\n", tacfile);
167 if(newsif[0]) printf(
"newsif := %s\n", newsif);
168 printf(
"print_weights := %d\n", print_weights);
169 printf(
"remove_weights := %d\n", remove_weights);
170 printf(
"weight_method := %d\n", weight_method);
172 printf(
"moderate := %g\n", weight_moderate);
181 if(verbose>1) {fprintf(stdout,
"reading %s\n", tacfile); fflush(stdout);}
184 fprintf(stderr,
"Error: %s (%s)\n",
errorMsg(status.
error), tacfile);
188 printf(
"weighting := %d\n", tac.
weighting);
190 printf(
"tacNr := %d\n", tac.
tacNr);
191 printf(
"sampleNr := %d\n", tac.
sampleNr);
194 if(tac.
isframe) printf(
"frames := yes\n");
else printf(
"frames := no\n");
198 printf(
"contains_weights := ");
199 if(
tacIsWeighted(&tac)) printf(
"yes\n");
else printf(
"no\n");
207 if(print_weights!=0) {
208 if(verbose>2) printf(
"printing existing weights\n");
210 printf(
"contains_weights := no\n");
214 printf(
"start[]\tend[]\tweight\n");
215 for(
int i=0; i<tac.
sampleNr; i++) printf(
"%g\t%g\t%.4e\n", tac.
x1[i], tac.
x2[i], tac.
w[i]);
218 printf(
"time[]\tweight\n");
219 for(
int i=0; i<tac.
sampleNr; i++) printf(
"%g\t%.4e\n", tac.
x[i], tac.
w[i]);
227 if(verbose>1) printf(
"Note: status of current decay correction is not known.\n");
229 if(verbose>1) fprintf(stderr,
"Note: physical decay is corrected in %s.\n", tacfile);
231 fprintf(stderr,
"Note: physical decay is not corrected in %s.\n", tacfile);
239 if(verbose>3) {printf(
"tac.isotope := %s\n",
isotopeName(fisot)); fflush(stdout);}
242 fprintf(stderr,
"Error: valid isotope not specified.\n");
247 if(verbose>1) printf(
"isotope := %s\n",
isotopeName(isot));
254 fprintf(stderr,
"Error: different isotope in %s\n", tacfile);
264 if(remove_weights!=0) {
265 if(verbose>1) printf(
"removing weights\n");
267 printf(
"%s does not contain weights.\n", tacfile);
271 if(verbose>1) printf(
"saving modified %s\n", tacfile);
272 FILE *fp; fp=fopen(tacfile,
"w");
274 fprintf(stderr,
"Error: cannot open file for writing\n");
284 if(verbose>0) printf(
"Weights removed in %s\n", tacfile);
296 if(verbose>1) {fprintf(stdout,
"trying to read %s\n", siffile); fflush(stdout);}
297 int ret=
tacRead(&sif, siffile, &status);
300 printf(
"sif.weighting := %d\n", sif.
weighting);
302 printf(
"sif.tacNr := %d\n", sif.
tacNr);
303 printf(
"sif.sampleNr := %d\n", sif.
sampleNr);
306 if(sif.
isframe) printf(
"sif.frames := yes\n");
else printf(
"sif.frames := no\n");
310 fprintf(stderr,
"Error: file is not in SIF format.\n");
313 if(verbose>1) printf(
"%s is SIF\n", siffile);
316 fprintf(stderr,
"Error: invalid SIF.\n");
319 double promptMax, randomMax;
320 if(
tacYRange(&sif, 0, NULL, &promptMax, NULL, NULL, NULL, NULL) ||
321 tacYRange(&sif, 1, NULL, &randomMax, NULL, NULL, NULL, NULL))
323 fprintf(stderr,
"Error: invalid SIF.\n");
326 if(verbose>2) printf(
" promptMax := %g\n randomMax := %g\n", promptMax, randomMax);
327 if(!(promptMax>0.0)) {
329 fprintf(stderr,
"Error: SIF does not contain prompts.\n");
332 fprintf(stderr,
"Warning: SIF does not contain prompts.\n"); fflush(stderr);
334 if(!(randomMax>0.0)) {
335 fprintf(stderr,
"Warning: SIF does not contain randoms.\n"); fflush(stderr);
338 if(verbose>1) fprintf(stdout,
"trying to find TAC %s\n", siffile);
341 fprintf(stderr,
"Error: no TAC matching '%s' was found.\n", siffile);
345 if(verbose>1) printf(
" %d TACs match '%s'.\n", n, siffile);
348 for(
int i=0; i<tac.
tacNr; i++)
if(tac.
c[i].
sw) {headIndex=i;
break;}
351 if(verbose>0) printf(
"headTAC := %s\n", tac.
c[headIndex].
name);
353 fprintf(stderr,
"Error: no single TAC matching '%s' was found.\n", siffile);
367 if(verbose>3) {printf(
"sif.isotope := %s\n",
isotopeName(fisot)); fflush(stdout);}
369 fprintf(stderr,
"Error: valid isotope not specified.\n");
375 if(verbose>1) printf(
"isotope := %s\n",
isotopeName(isot));
381 fprintf(stderr,
"Error: different isotope in %s\n", siffile);
386 fprintf(stderr,
"Error: isotope is required with SIF and selected weighting method.\n");
390 fprintf(stderr,
"Error: frame times in TAC and SIF do not match.\n");
398 fprintf(stderr,
"Error: isotope is required for making SIF.\n");
410 if(verbose>1) printf(
"creating SIF data from regional data\n");
416 fprintf(stderr,
"Error: invalid sample times.\n");
421 fprintf(stderr,
"Warning: unknown time unit; assumed min.\n");
422 }
else if(xmax>360.0) {
424 fprintf(stderr,
"Warning: unknown time unit; assumed sec.\n");
426 fprintf(stderr,
"Error: unknown time unit.\n");
433 fprintf(stderr,
"Error: unknown calibration unit.\n");
437 fprintf(stderr,
"Error: invalid unit %s.\n",
unitName(tac.
cunit));
440 }
else if(newsif[0]) {
442 fprintf(stderr,
"Error: unknown calibration unit.\n");
446 fprintf(stderr,
"Error: invalid unit %s.\n",
unitName(tac.
cunit));
452 fprintf(stderr,
"Error: cannot prepare data for SIF.\n");
458 strcpy(sif.
c[0].
name,
"Prompts");
459 strcpy(sif.
c[1].
name,
"Randoms");
460 strcpy(sif.
c[2].
name,
"Trues");
488 for(
int i=0; i<tac.
sampleNr; i++) sif.
c[0].
y[i]=tac.
c[headIndex].
y[i];
492 double sum=0.0, wsum=0.0;
493 for(
int i=0; i<tac.
tacNr; i++) {
494 if(!isfinite(tac.
c[i].
y[j]))
continue;
495 double w=tac.
c[i].
size;
if(!(w>0.0)) w=1.0;
496 sum+=w*tac.
c[i].
y[j]; wsum+=w;
498 if(wsum>0.0) sif.
c[0].
y[j]=sum/wsum;
else sif.
c[0].
y[j]=0.0;
520 for(
int i=0; i<sif.
sampleNr; i++) sif.
c[0].
y[i]*=1000.;
524 for(
int i=0; i<sif.
sampleNr; i++) sif.
c[0].
y[i]*=(sif.
x2[i]-sif.
x1[i]);
528 sif.
c[2].
y[i]=sif.
c[0].
y[i];
533 if(verbose>1) printf(
"writing %s\n", newsif);
534 FILE *fp; fp=fopen(newsif,
"w");
536 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", newsif);
544 if(verbose>=0) printf(
"%s saved.\n", newsif);
552 if(verbose>1) {printf(
"calculating weights from SIF data\n"); fflush(stdout);}
555 fprintf(stderr,
"Error: cannot calculate weights.\n");
561 fprintf(stderr,
"Error: cannot calculate weights.\n");
562 fprintf(stderr,
"Error: %s (%s)\n",
errorMsg(status.
error), tacfile);
567 fprintf(stderr,
"Error: cannot calculate weights.\n");
568 fprintf(stderr,
"Error: %s (%s)\n",
errorMsg(status.
error), tacfile);
572 fprintf(stderr,
"Error: invalid settings.\n");
576 if(weight_moderate>0.0) {
577 if(verbose>1) {printf(
"moderate and normalize weights\n"); fflush(stdout);}
578 double prop=0.0;
if(weight_moderate>1.0) prop=1.0/weight_moderate;
585 if(verbose>1) {printf(
"normalize weights\n"); fflush(stdout);}
601 if(verbose>1) printf(
"saving modified %s\n", tacfile);
602 FILE *fp; fp=fopen(tacfile,
"w");
604 fprintf(stderr,
"Error: cannot open file for writing\n");
614 if(verbose>0) printf(
"Weights added in %s\n", tacfile);
double atofVerified(const char *s)
char * isotopeName(int isotope_code)
int isotopeIdentify(const char *isotope)
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)
int tacWriteSIF(TAC *tac, FILE *fp, int extra, TPCSTATUS *status)
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)
char name[MAX_TACNAME_LEN+1]
IFT h
Optional (but often useful) header information.
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
int tacGetIsotope(TAC *tac)
int tacDecayCorrection(TAC *tac, int isotope, int mode, TPCSTATUS *status)
void tacSetIsotope(TAC *tac, int isotope)
decaycorrection tacGetHeaderDecayCorrection(IFT *h)
int tacGetHeaderStudynr(IFT *h, char *s, TPCSTATUS *status)
int tacSetHeaderStudynr(IFT *h, const char *s)
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 tacSelectTACs(TAC *d, const char *region_name, int reset, TPCSTATUS *status)
int tacSelectBestReference(TAC *d)
int tacYUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
int sifWeight(TAC *sif, isotope isot, TPCSTATUS *status)
int tacIsWeighted(TAC *tac)
int tacWeightModerate(TAC *tac, const double minprop, const int doZeroes, const int doNaNs, TPCSTATUS *status)
int tacWeightNorm(TAC *tac, TPCSTATUS *status)
int tacWCopy(TAC *tac1, TAC *tac2, int i1, int i2)
int tacWByFreq(TAC *tac, isotope isot, TPCSTATUS *status)
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.
int tacXCopy(TAC *tac1, TAC *tac2, int i1, int i2)
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.
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
int tacYRange(TAC *d, int i, double *ymin, double *ymax, int *smin, int *smax, int *imin, int *imax)
Get the range of y values (concentrations) in TAC struct.
Header file for library libtpccsv.
Header file for library libtpcextensions.
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ WEIGHTING_ON_FD
Weights based on decay and sample frequency or frame length (Thiele et al, 2008).
@ WEIGHTING_ON_F
Weights based on sample frequency or frame length.
@ WEIGHTING_ON_COUNTS
Weights based on counts (Mazoyer et al, 1986).
@ UNIT_UNKNOWN
Unknown unit.
int unitIsRadioactivity(int u)
char * unitName(int unit_code)
#define MAX_STUDYNR_LEN
Define max study number length.
Header file for library libtpcift.
@ DECAY_UNKNOWN
Not known; usually assumed that data is corrected.
@ DECAY_NOTCORRECTED
Data is not corrected for physical decay.
@ DECAY_CORRECTED
Data is corrected for physical decay.
@ ISOTOPE_UNKNOWN
Unknown.
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
@ TAC_FORMAT_PMOD
PMOD TAC format.
@ TAC_FORMAT_SIMPLE
x and y's with space delimiters
@ TAC_FORMAT_SIF
Scan information file.