TPCCLIB
Loading...
Searching...
No Matches
heartcor.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 "libtpcmisc.h"
17#include "libtpcmodel.h"
18#include "libtpccurveio.h"
19#include "libtpcidi.h"
20/*****************************************************************************/
21#ifndef M_2SQRT2LN2
22#define M_2SQRT2LN2 2.354820045
23#endif
24/*****************************************************************************/
25
26/*****************************************************************************/
27static char *info[] = {
28 "Corrects regional myocardium and blood time-activity curves (TACs)",
29 "measured with PET for recovery and spillover fractions, and contribution",
30 "of blood activity in vascular space (10%) (Henze et al., 1983).",
31 "This method works properly, if regions-of-interest (ROIs) are drawn",
32 "in the middle of cavity and muscle, excluding the border areas.",
33 "Method is valid when cavity radius >> wall thickness and FWHM/2.36.",
34 " ",
35 "Usage: @P tacfile cav_id myo_id diameter thickness FWHM outputfile",
36 " ",
37 "Tacfile must contain at least the TACs of myocardial cavity and entire",
38 "myocardial muscle (or representative region of it). The names or numbers",
39 "of these TACs must be given as next command-line parameters.",
40 "Corrections based on these TACs are applied to any additional TACs in tacfile.",
41 " ",
42 "The diameter of cavity, myocardial wall thickness, and PET image resolution",
43 "must be given in millimeters.",
44 " ",
45 "Options:",
46 " -Vb=<Vascular volume fraction>",
47 " Set vascular volume fraction (0-0.9) in myocardial tissue;",
48 " by default Vb=0.10",
49 " -sim[ulate]",
50 " Recovery and spillover errors are simulated and added to initially",
51 " non-affected data, originating from compartmental model simulations;",
52 " enter blood and muscle tissue TACs instead of cavity and myocardial",
53 " region TACs, respectively.",
54 " -stdoptions", // List standard options like --help, -v, etc
55 " ",
56 "Example 1: correction of regional PET data",
57 " @P s6368dy.tac lv myo 52 10 10 s6368dy_cor.tac",
58 " ",
59 "Example 2: simulation of recovery and spillover effects, assuming Vb=8%%",
60 " @P -simulate original.tac 1 2 40 10 8 simulated.tac",
61 "Example 3: calculate FMM, FMB, FBM, and FBB, without doing anything else",
62 " @P none 1 2 40 10 8 none",
63 " ",
64 "Reference:",
65 "1. Henze E, Huang S-C, Ratib O, Hoffman E, Phelps ME, Schelbert HR.",
66 " Measurements of regional tissue and blood-pool radiotracer",
67 " concentrations from serial tomographic images of the heart.",
68 " J Nucl Med. 1983;24:987-996.",
69 " ",
70 "See also: fitmbf, patlak, logan, simimyoc, taccalc, taccbv, spillinp",
71 " ",
72 "Keywords: TAC, myocardium, cavity, spill-over, recovery, simulation",
73 0};
74/*****************************************************************************/
75
76/*****************************************************************************/
77/* Turn on the globbing of the command line, since it is disabled by default in
78 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
79 In Unix&Linux wildcard command line processing is enabled by default. */
80/*
81#undef _CRT_glob
82#define _CRT_glob -1
83*/
84int _dowildcard = -1;
85/*****************************************************************************/
86
87/*****************************************************************************/
91int main(int argc, char **argv)
92{
93 int ai, help=0, version=0, verbose=1;
94 int ret, ri, fi;
95 double R=-1.0; // radius of cavity and circular ROI (mm)
96 double d=-1.0; // thickness of myocardium (mm)
97 double s=-1.0; // spatial resolution (mm), s=FWHM/2.354820045
98 int simulation=0; // 1=add errors, 0=correct errors
99 char *cptr, dfile[FILENAME_MAX], rfile[FILENAME_MAX];
100 char *cav_roi=NULL, *myo_roi=NULL;
101 int lv=-1; // number of LV TAC in DFT struct
102 int myo=-1; // number of whole myocardium TAC in DFT struct
103 double Vb=0.1; // vascular volume fraction in tissue
104 DFT dft;
105
106
107 /*
108 * Get arguments
109 */
110 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
111 dfile[0]=rfile[0]=(char)0;
112 dftInit(&dft);
113 /* Options */
114 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
115 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
116 cptr=argv[ai]+1; if(!*cptr) continue;
117 if(strncasecmp(cptr, "SIMULATE", 3)==0) {
118 simulation=1; continue;
119 } else if(strncasecmp(cptr, "VB=", 3)==0) {
120 ret=atof_with_check(cptr+3, &Vb);
121 if(ret==0 && Vb>=0.0 && Vb<1.0) continue;
122 }
123 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
124 return(1);
125 } else break;
126
127 /* Print help or version? */
128 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
129 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
130 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
131
132 /* Process other arguments, starting from the first non-option */
133 for(; ai<argc; ai++) {
134 if(!dfile[0]) {
135 strlcpy(dfile, argv[ai], FILENAME_MAX); continue;
136 } else if(cav_roi==NULL) {
137 cav_roi=argv[ai]; continue;
138 } else if(myo_roi==NULL) {
139 myo_roi=argv[ai]; continue;
140 } else if(R<0.0) {
141 R=0.5*atof_dpi(argv[ai]); if(R>0.0) continue;
142 fprintf(stderr, "Error: invalid diameter '%s'\n", argv[ai]); return(1);
143 } else if(d<0.0) {
144 d=atof_dpi(argv[ai]); if(d>0.0) continue;
145 fprintf(stderr, "Error: invalid thickness '%s'\n", argv[ai]); return(1);
146 } else if(s<0.0) {
147 s=atof_dpi(argv[ai])/M_2SQRT2LN2; if(s>0.0) continue;
148 fprintf(stderr, "Error: invalid resolution '%s'\n", argv[ai]); return(1);
149 } else if(!rfile[0]) {
150 strlcpy(rfile, argv[ai], FILENAME_MAX); continue;
151 }
152 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
153 return(1);
154 }
155
156 /* Is something missing? */
157 if(!rfile[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
158 if(strcasecmp(dfile, "NONE")==0 || strcasecmp(rfile, "NONE")==0) {
159 strcpy(dfile, ""); strcpy(rfile, "");
160 }
161
162 /* In verbose mode print arguments and options */
163 if(verbose>1) {
164 printf("dfile := %s\n", dfile);
165 printf("rfile := %s\n", rfile);
166 printf("cav_roi := %s\n", cav_roi);
167 printf("myo_roi := %s\n", myo_roi);
168 printf("R := %g\n", R);
169 printf("d := %g\n", d);
170 printf("s := %.6f\n", s);
171 printf("simulation := %d\n", simulation);
172 printf("Vb := %g\n", Vb);
173 }
174
175
176 /* Calculate correction coefficients */
177 /* Do this before trying to read datafile, to allow user just to calculate
178 these values for some other use */
179 double FMM, FMB, FBM, FBB;
181 &FMM, &FMB, &FBM, &FBB);
182 if(strlen(dfile)==0 || verbose>0) {
183 printf("FMB := %.6f\n", FMB);
184 printf("FMM := %.6f\n", FMM);
185 printf("FBB := %.6f\n", FBB);
186 printf("FBM := %.6f\n", FBM);
187 }
188 if(strlen(dfile)==0) return(0); // we are done then
189
190
191 /* Read datafile */
192 if(verbose>1) printf("reading %s\n", dfile);
193 if(dftRead(dfile, &dft)) {
194 fprintf(stderr, "Error in reading '%s': %s\n", dfile, dfterrmsg);
195 return(2);
196 }
197
198 /* Select the LV and whole myocardium ROIs */
199 ret=dftSelectRegions(&dft, cav_roi, 1);
200 if(ret<1) {
201 fprintf(stderr, "Error: ROI '%s' not found in %s\n", cav_roi, dfile);
202 dftEmpty(&dft); return(3);
203 } else {
204 int len=256, last_len=256;
205 for(ri=0; ri<dft.voiNr; ri++)
206 if(dft.voi[ri].sw==1) {lv=ri; len=last_len=strlen(dft.voi[ri].name); break;}
207 for(;ri<dft.voiNr; ri++)
208 if(dft.voi[ri].sw==1 && (len=strlen(dft.voi[ri].name))<last_len)
209 {lv=ri; last_len=len;}
210 }
211 ret=dftSelectRegions(&dft, myo_roi, 1);
212 if(ret<1) {
213 fprintf(stderr, "Error: ROI '%s' not found in %s\n", myo_roi, dfile);
214 dftEmpty(&dft); return(3);
215 } else {
216 int len=256, last_len=256;
217 for(ri=0; ri<dft.voiNr; ri++)
218 if(dft.voi[ri].sw==1) {myo=ri; len=last_len=strlen(dft.voi[ri].name); break;}
219 for(;ri<dft.voiNr; ri++)
220 if(dft.voi[ri].sw==1 && (len=strlen(dft.voi[ri].name))<last_len)
221 {myo=ri; last_len=len;}
222 }
223 if(verbose>0) {
224 printf("cavity := %s\n", dft.voi[lv].name);
225 printf("myocardium := %s\n", dft.voi[myo].name);
226 }
227 if(lv==myo) {
228 fprintf(stderr, "Error: same ROI selected for cavity and myocardium.\n");
229 dftEmpty(&dft); return(3);
230 }
231
232 /* Correct the TACs */
233 if(verbose>1) printf("correcting TACs\n");
234 double CMO, CBO; // imaged concentrations of myocardium and blood pool
235 double CM, CB; // true concentrations in myocardium and in blood
236 double CMs, CMOs;// concentrations in smaller myocardial regions
237 double K=1.0/(FBB*FMM-FMB*FBM);
238 if(verbose>2 && simulation==0) printf("K := %.5f\n", K);
239 for(fi=0; fi<dft.frameNr; fi++) {
240 if(simulation==1) {
241 /* add errors to blood and whole myocardium TACs */
242 CM=dft.voi[myo].y[fi];
243 CB=dft.voi[lv].y[fi];
244 CMO=FMM*CM + FBM*CB; dft.voi[myo].y[fi]=CMO;
245 CBO=FMB*CM + FBB*CB; dft.voi[lv].y[fi]=CBO;
246 /* add errors to other myocardial curves */
247 for(ri=0; ri<dft.voiNr; ri++) if(ri!=lv && ri!=myo) {
248 CMs=dft.voi[ri].y[fi];
249 CMOs=FMM*CMs + FBM*CB; dft.voi[ri].y[fi]=CMOs;
250 }
251 } else {
252 /* correct the LV and whole myocardium TACs */
253 CMO=dft.voi[myo].y[fi];
254 CBO=dft.voi[lv].y[fi];
255 CM=K*(FBB*CMO-FBM*CBO); dft.voi[myo].y[fi]=CM;
256 CB=K*(FMM*CBO-FMB*CMO); dft.voi[lv].y[fi]=CB;
257 /* correct other myocardial regions */
258 for(ri=0; ri<dft.voiNr; ri++) if(ri!=lv && ri!=myo) {
259 CMOs=dft.voi[ri].y[fi];
260 //CMs=(CMOs - FBM*((CBO-FMB*CM)/FBB)) / FMM;
261 CMs=(CMOs - FBM*CB) / FMM;
262 dft.voi[ri].y[fi]=CMs;
263 }
264 }
265 } // next frame time
266
267 /* Save data */
268 if(dftWrite(&dft, rfile)) {
269 fprintf(stderr, "Error in writing '%s': %s\n", rfile, dfterrmsg);
270 dftEmpty(&dft); return(11);
271 }
272 if(verbose>0) printf("%s written.\n", rfile);
273
274 /* Free memory */
275 dftEmpty(&dft);
276
277 return(0);
278}
279/*****************************************************************************/
280
281/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
double atof_dpi(char *str)
Definition decpoint.c:59
void dftInit(DFT *data)
Definition dft.c:38
char dfterrmsg[64]
Definition dft.c:6
void dftEmpty(DFT *data)
Definition dft.c:20
int dftSelectRegions(DFT *dft, char *region_name, int reset)
Definition dft.c:285
int dftRead(char *filename, DFT *data)
Definition dftio.c:22
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
int heartRecoverySpilloverCorrectionFactors(double R, double d, double s, double Vb, double *FMM, double *FMB, double *FBM, double *FBB)
Definition heartcorr.c:37
Header file for libtpccurveio.
Header file for libtpcidi.
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
Header file for libtpcmodel.
Voi * voi
int voiNr
int frameNr
char sw
double * y
char name[MAX_REGIONNAME_LEN+1]