TPCCLIB
Loading...
Searching...
No Matches
tac2suv.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 "tpctac.h"
18/*****************************************************************************/
19
20/*****************************************************************************/
21static char *info[] = {
22 "Converts TAC radioactivity concentrations into standardized uptake values",
23 "(SUV, DUR, DAR) or PID/L, using administered radioligand dose and subject",
24 "weight. Injected dose must be given in units MBq at the time of injection.",
25 "Subject weight must be given in kg or litres.",
26 "Instead of SUV, the percentage of injected dose per tissue volume ",
27 "(PID/L, %i.d./L) is calculated, if the subject weight is set to 0.",
28 " ",
29 "Usage: @P [Options] tacfile dose weight [outputfile]",
30 " ",
31 "Options:",
32 " -stdoptions", // List standard options like --help, -v, etc
33 " ",
34 "TAC file must be correct for physical decay to the injection time.",
35 "If the units of radioactivity concentrations are not specified inside",
36 "the TAC file, the units are assumed to be in kBq/mL;",
37 "units can be specified by adding line(s) to the end of the TAC file,",
38 "for example:",
39 "# unit := Bq/cc",
40 "# time_unit := sec",
41 " ",
42 "If name for output file is not given, then TAC file is overwritten.",
43 " ",
44 "Example:",
45 " @P uia15.dat 330 77 uia15suv.dat",
46 " ",
47 "See also: tacunit, tactime, taccalc, dftinteg, dftsuv, imgsuv",
48 " ",
49 "Keywords: TAC, SUV, PID, dose, modelling",
50 0};
51/*****************************************************************************/
52
53/*****************************************************************************/
54/* Turn on the globbing of the command line, since it is disabled by default in
55 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
56 In Unix&Linux wildcard command line processing is enabled by default. */
57/*
58#undef _CRT_glob
59#define _CRT_glob -1
60*/
61int _dowildcard = -1;
62/*****************************************************************************/
63
64/*****************************************************************************/
68int main(int argc, char **argv)
69{
70 int ai, help=0, version=0, verbose=1;
71 char tacfile[FILENAME_MAX], outfile[FILENAME_MAX];
72 double weight=nan(""), dose=nan("");
73
74 /*
75 * Get arguments
76 */
77 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
78 tacfile[0]=outfile[0]=(char)0;
79 /* Options */
80 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
81 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
82 //char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
83 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
84 return(1);
85 } else break;
86
87 TPCSTATUS status; statusInit(&status);
88 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
89 status.verbose=verbose-1;
90
91 /* Print help or version? */
92 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
93 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
94 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
95
96 /* Process other arguments, starting from the first non-option */
97 if(ai<argc) {strlcpy(tacfile, argv[ai], FILENAME_MAX); ai++;}
98 if(ai<argc) {
99 if(atofCheck(argv[ai], &dose) || !(dose>0.0)) {
100 fprintf(stderr, "Error: invalid dose '%s'.\n", argv[ai]);
101 return(1);
102 }
103 ai++;
104 }
105 if(ai<argc) {
106 double v;
107 if(atofCheck(argv[ai], &v)) {
108 fprintf(stderr, "Error: invalid weight '%s'.\n", argv[ai]);
109 return(1);
110 }
111 if(v>1.0E-100) weight=v;
112 ai++;
113 } else {fprintf(stderr, "Error: missing weight.\n"); return(1);}
114 if(ai<argc) {strlcpy(outfile, argv[ai], FILENAME_MAX); ai++;}
115 if(ai<argc) {
116 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
117 return(1);
118 }
119
120 /* Is something missing? */
121 if(!(dose>0.0)) {
122 fprintf(stderr, "Error: missing dose.\n");
123 return(1);
124 }
125 if(!outfile[0]) strcpy(outfile, tacfile);
126
127 /* In verbose mode print arguments and options */
128 if(verbose>1) {
129 printf("tacfile := %s\n", tacfile);
130 printf("outfile := %s\n", outfile);
131 printf("dose := %g MBq\n", dose);
132 if(!isnan(weight)) printf("weight := %g kg\n", weight);
133 fflush(stdout);
134 }
135
136
137 /*
138 * Read TAC data
139 */
140 if(verbose>1) printf("reading TAC data in %s\n", tacfile);
141 TAC tac; tacInit(&tac);
142 if(tacRead(&tac, tacfile, &status)!=TPCERROR_OK) {
143 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
144 tacFree(&tac); return(2);
145 }
146 if(verbose>1) {
147 printf("fileformat := %s\n", tacFormattxt(tac.format));
148 printf("tacNr := %d\n", tac.tacNr);
149 printf("sampleNr := %d\n", tac.sampleNr);
150 printf("unit := %s\n", unitName(tac.cunit));
151 printf("timeunit := %s\n", unitName(tac.tunit));
152 fflush(stdout);
153 }
154
155 /* Check the radioactivity units */
156 if(tac.cunit==UNIT_UNKNOWN) {
158 printf("Warning: assuming unit %s\n", unitName(tac.cunit));
159 }
160 if(tac.cunit!=UNIT_KBQ_PER_ML && tac.cunit!=UNIT_KBQ_PER_G) {
161 int ret=1, oldunit=tac.cunit;
162 if(unitDividerHasVolume(tac.cunit)) ret=tacYUnitConvert(&tac, UNIT_KBQ_PER_ML, &status);
163 else if(unitDividerHasMass(tac.cunit)) ret=tacYUnitConvert(&tac, UNIT_KBQ_PER_G, &status);
164 if(ret) {
165 fprintf(stderr, "Error: cannot convert units %s\n", unitName(tac.tunit));
166 return(3);
167 }
168 if(verbose>1) {
169 printf("%s: units converted from '%s' to '%s'\n",
170 tacfile, unitName(oldunit), unitName(tac.cunit));
171 fflush(stdout);
172 }
173 }
174
175
176 /*
177 * Calculate SUV or PID curve
178 */
179 double f=dose;
180 if(!isnan(weight)) {
181 if(verbose>1) printf("calculating SUV TAC\n");
182 f/=weight; /* Act / (Dose/Weight) */
183 } else {
184 if(verbose>1) printf("calculating PID TAC\n");
185 /* Percent of injected dose / mL */
186 f*=1000.0/100.0; /* 100% * Act / (Dose*1000) */
187 /* per L instead of mL */
188 f/=1000.0;
189 }
190 if(verbose>2) {printf("conversion factor := %g\n", f); fflush(stdout);}
191 /* Calculate curve */
192 for(int i=0; i<tac.tacNr; i++) for(int j=0; j<tac.sampleNr; j++) tac.c[i].y[j]/=f;
193 /* Set calibration units */
194 if(unitDividerHasVolume(tac.cunit)) {
195 if(!isnan(weight)) tac.cunit=UNIT_G_PER_ML; else tac.cunit=UNIT_PID_PER_L;
196 } else if(unitDividerHasMass(tac.cunit)) {
197 if(!isnan(weight)) tac.cunit=UNIT_UNITLESS; else tac.cunit=UNIT_PID_PER_KG;
198 }
199
200
201 /*
202 * Save modified data
203 */
204 {
205 if(verbose>1) printf("writing %s\n", outfile);
206 FILE *fp; fp=fopen(outfile, "w");
207 if(fp==NULL) {
208 fprintf(stderr, "Error: cannot open file for writing.\n");
209 tacFree(&tac); return(11);
210 }
211 int ret=tacWrite(&tac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
212 fclose(fp);
213 if(ret!=TPCERROR_OK) {
214 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
215 tacFree(&tac); return(12);
216 }
217 tacFree(&tac);
218 }
219 if(verbose>0) {
220 char tmp[32];
221 if(!isnan(weight)) strcpy(tmp, "SUV"); else strcpy(tmp, "%i.d.");
222 printf("%s written in %s\n", tmp, outfile);
223 }
224
225 return(0);
226}
227/*****************************************************************************/
228
229/*****************************************************************************/
int atofCheck(const char *s, double *v)
Definition decpoint.c:94
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:632
double * y
Definition tpctac.h:75
Definition tpctac.h:87
unit cunit
Definition tpctac.h:105
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
TACC * c
Definition tpctac.h:117
unit tunit
Definition tpctac.h:109
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
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 tacYUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:72
Header file for library libtpcextensions.
@ UNIT_PID_PER_L
Percent of injected dose / L.
@ UNIT_UNKNOWN
Unknown unit.
@ UNIT_KBQ_PER_ML
kBq/mL
@ UNIT_UNITLESS
Unitless.
@ UNIT_G_PER_ML
g/mL
@ UNIT_KBQ_PER_G
kBq/g
@ UNIT_PID_PER_KG
Percent of injected dose / kg.
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
int unitDividerHasVolume(int u)
Definition units.c:678
int unitDividerHasMass(int u)
Definition units.c:694
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28