File: | src/ten/tendEstim.c |
Location: | line 329, column 5 |
Description: | Value stored to 'EE' is never read |
1 | /* |
2 | Teem: Tools to process and visualize scientific data and images . |
3 | Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago |
4 | Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann |
5 | Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah |
6 | |
7 | This library is free software; you can redistribute it and/or |
8 | modify it under the terms of the GNU Lesser General Public License |
9 | (LGPL) as published by the Free Software Foundation; either |
10 | version 2.1 of the License, or (at your option) any later version. |
11 | The terms of redistributing and/or modifying this software also |
12 | include exceptions to the LGPL that facilitate static linking. |
13 | |
14 | This library is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | Lesser General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Lesser General Public License |
20 | along with this library; if not, write to Free Software Foundation, Inc., |
21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 | */ |
23 | |
24 | #include "ten.h" |
25 | #include "privateTen.h" |
26 | |
27 | #define INFO"Estimate tensors from a set of DW images" "Estimate tensors from a set of DW images" |
28 | static const char *_tend_estimInfoL = |
29 | (INFO"Estimate tensors from a set of DW images" |
30 | ". The tensor coefficient weightings associated with " |
31 | "each of the DWIs, the B-matrix, is given either as a separate array, " |
32 | "(see \"tend bmat\" usage info for details), or by the key-value pairs " |
33 | "in the DWI nrrd header. A \"confidence\" value is computed with the " |
34 | "tensor, based on a soft thresholding of the sum of all the DWIs, " |
35 | "according to the threshold and softness parameters. "); |
36 | |
37 | int |
38 | tend_estimMain(int argc, const char **argv, const char *me, |
39 | hestParm *hparm) { |
40 | int pret; |
41 | hestOpt *hopt = NULL((void*)0); |
42 | char *perr, *err; |
43 | airArray *mop; |
44 | |
45 | Nrrd **nin, *nin4d, *nbmat, *nterr, *nB0, *nout; |
46 | char *outS, *terrS, *bmatS, *eb0S; |
47 | float soft, scale, sigma; |
48 | int dwiax, EE, knownB0, oldstuff, estmeth, verbose, fixneg; |
49 | unsigned int ninLen, axmap[4], wlsi, *skip, skipNum, skipIdx; |
50 | double valueMin, thresh; |
51 | |
52 | Nrrd *ngradKVP=NULL((void*)0), *nbmatKVP=NULL((void*)0); |
53 | double bKVP, bval; |
54 | |
55 | tenEstimateContext *tec; |
56 | |
57 | hestOptAdd(&hopt, "old", NULL((void*)0), airTypeInt, 0, 0, &oldstuff, NULL((void*)0), |
58 | "instead of the new tenEstimateContext code, use " |
59 | "the old tenEstimateLinear code"); |
60 | hestOptAdd(&hopt, "sigma", "sigma", airTypeFloat, 1, 1, &sigma, "nan", |
61 | "Rician noise parameter"); |
62 | hestOptAdd(&hopt, "v", "verbose", airTypeInt, 1, 1, &verbose, "0", |
63 | "verbosity level"); |
64 | hestOptAdd(&hopt, "est", "estimate method", airTypeEnum, 1, 1, &estmeth, |
65 | "lls", |
66 | "estimation method to use. \"lls\": linear-least squares", |
67 | NULL((void*)0), tenEstimate1Method); |
68 | hestOptAdd(&hopt, "wlsi", "WLS iters", airTypeUInt, 1, 1, &wlsi, "1", |
69 | "when using weighted-least-squares (\"-est wls\"), how " |
70 | "many iterations to do after the initial weighted fit."); |
71 | hestOptAdd(&hopt, "fixneg", NULL((void*)0), airTypeInt, 0, 0, &fixneg, NULL((void*)0), |
72 | "after estimating the tensor, ensure that there are no negative " |
73 | "eigenvalues by adding (to all eigenvalues) the amount by which " |
74 | "the smallest is negative (corresponding to increasing the " |
75 | "non-DWI image value)."); |
76 | hestOptAdd(&hopt, "ee", "filename", airTypeString, 1, 1, &terrS, "", |
77 | "Giving a filename here allows you to save out the tensor " |
78 | "estimation error: a value which measures how much error there " |
79 | "is between the tensor model and the given diffusion weighted " |
80 | "measurements for each sample. By default, no such error " |
81 | "calculation is saved."); |
82 | hestOptAdd(&hopt, "eb", "filename", airTypeString, 1, 1, &eb0S, "", |
83 | "In those cases where there is no B=0 reference image given " |
84 | "(\"-knownB0 false\"), " |
85 | "giving a filename here allows you to save out the B=0 image " |
86 | "which is estimated from the data. By default, this image value " |
87 | "is estimated but not saved."); |
88 | hestOptAdd(&hopt, "t", "thresh", airTypeDouble, 1, 1, &thresh, "nan", |
89 | "value at which to threshold the mean DWI value per pixel " |
90 | "in order to generate the \"confidence\" mask. By default, " |
91 | "the threshold value is calculated automatically, based on " |
92 | "histogram analysis."); |
93 | hestOptAdd(&hopt, "soft", "soft", airTypeFloat, 1, 1, &soft, "0", |
94 | "how fuzzy the confidence boundary should be. By default, " |
95 | "confidence boundary is perfectly sharp"); |
96 | hestOptAdd(&hopt, "scale", "scale", airTypeFloat, 1, 1, &scale, "1", |
97 | "After estimating the tensor, scale all of its elements " |
98 | "(but not the confidence value) by this amount. Can help with " |
99 | "downstream numerical precision if values are very large " |
100 | "or small."); |
101 | hestOptAdd(&hopt, "mv", "min val", airTypeDouble, 1, 1, &valueMin, "1.0", |
102 | "minimum plausible value (especially important for linear " |
103 | "least squares estimation)"); |
104 | hestOptAdd(&hopt, "B", "B-list", airTypeString, 1, 1, &bmatS, NULL((void*)0), |
105 | "6-by-N list of B-matrices characterizing " |
106 | "the diffusion weighting for each " |
107 | "image. \"tend bmat\" is one source for such a matrix; see " |
108 | "its usage info for specifics on how the coefficients of " |
109 | "the B-matrix are ordered. " |
110 | "An unadorned plain text file is a great way to " |
111 | "specify the B-matrix.\n **OR**\n " |
112 | "Can say just \"-B kvp\" to try to learn B matrices from " |
113 | "key/value pair information in input images."); |
114 | hestOptAdd(&hopt, "b", "b", airTypeDouble, 1, 1, &bval, "nan", |
115 | "\"b\" diffusion-weighting factor (units of sec/mm^2)"); |
116 | hestOptAdd(&hopt, "knownB0", "bool", airTypeBool, 1, 1, &knownB0, NULL((void*)0), |
117 | "Indicates if the B=0 non-diffusion-weighted reference image " |
118 | "is known, or if it has to be estimated along with the tensor " |
119 | "elements.\n " |
120 | "\b\bo if \"true\": in the given list of diffusion gradients or " |
121 | "B-matrices, there are one or more with zero norm, which are " |
122 | "simply averaged to find the B=0 reference image value\n " |
123 | "\b\bo if \"false\": there may or may not be diffusion-weighted " |
124 | "images among the input; the B=0 image value is going to be " |
125 | "estimated along with the diffusion model"); |
126 | hestOptAdd(&hopt, "i", "dwi0 dwi1", airTypeOther, 1, -1, &nin, "-", |
127 | "all the diffusion-weighted images (DWIs), as separate 3D nrrds, " |
128 | "**OR**: One 4D nrrd of all DWIs stacked along axis 0", |
129 | &ninLen, NULL((void*)0), nrrdHestNrrd); |
130 | hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-", |
131 | "output tensor volume"); |
132 | |
133 | mop = airMopNew(); |
134 | airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); |
135 | USAGE(_tend_estimInfoL)if (!argc) { hestInfo(__stdoutp, me, (_tend_estimInfoL), hparm ); hestUsage(__stdoutp, hopt, me, hparm); hestGlossary(__stdoutp , hopt, hparm); airMopError(mop); return 0; }; |
136 | JUSTPARSE()if ((pret=hestParse(hopt, argc, argv, &perr, hparm))) { if (1 == pret) { fprintf(__stderrp, "%s: %s\n", me, perr); free (perr); hestUsage(__stderrp, hopt, me, hparm); airMopError(mop ); return 2; } else { exit(1); } }; |
137 | airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); |
138 | |
139 | nout = nrrdNew(); |
140 | airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); |
141 | nbmat = nrrdNew(); |
142 | airMopAdd(mop, nbmat, (airMopper)nrrdNuke, airMopAlways); |
143 | |
144 | /* figure out B-matrix */ |
145 | if (strcmp("kvp", airToLower(bmatS))) { |
146 | /* its NOT coming from key/value pairs */ |
147 | if (!AIR_EXISTS(bval)(((int)(!((bval) - (bval)))))) { |
148 | fprintf(stderr__stderrp, "%s: need to specify scalar b-value\n", me); |
149 | airMopError(mop); return 1; |
150 | } |
151 | if (nrrdLoad(nbmat, bmatS, NULL((void*)0))) { |
152 | airMopAdd(mop, err=biffGetDone(NRRDnrrdBiffKey), airFree, airMopAlways); |
153 | fprintf(stderr__stderrp, "%s: trouble loading B-matrix:\n%s\n", me, err); |
154 | airMopError(mop); return 1; |
155 | } |
156 | nin4d = nin[0]; |
157 | skip = NULL((void*)0); |
158 | skipNum = 0; |
159 | } else { |
160 | /* it IS coming from key/value pairs */ |
161 | if (1 != ninLen) { |
162 | fprintf(stderr__stderrp, "%s: require a single 4-D DWI volume for " |
163 | "key/value pair based calculation of B-matrix\n", me); |
164 | airMopError(mop); return 1; |
165 | } |
166 | if (oldstuff) { |
167 | if (knownB0) { |
168 | fprintf(stderr__stderrp, "%s: sorry, key/value-based DWI info not compatible " |
169 | "with older implementation of knownB0\n", me); |
170 | airMopError(mop); return 1; |
171 | } |
172 | } |
173 | if (tenDWMRIKeyValueParse(&ngradKVP, &nbmatKVP, &bKVP, |
174 | &skip, &skipNum, nin[0])) { |
175 | airMopAdd(mop, err=biffGetDone(TENtenBiffKey), airFree, airMopAlways); |
176 | fprintf(stderr__stderrp, "%s: trouble parsing DWI info:\n%s\n", me, err); |
177 | airMopError(mop); return 1; |
178 | } |
179 | if (AIR_EXISTS(bval)(((int)(!((bval) - (bval)))))) { |
180 | fprintf(stderr__stderrp, "%s: WARNING: key/value pair derived b-value %g " |
181 | "over-riding %g from command-line", me, bKVP, bval); |
182 | } |
183 | bval = bKVP; |
184 | if (ngradKVP) { |
185 | airMopAdd(mop, ngradKVP, (airMopper)nrrdNuke, airMopAlways); |
186 | if (tenBMatrixCalc(nbmat, ngradKVP)) { |
187 | airMopAdd(mop, err=biffGetDone(TENtenBiffKey), airFree, airMopAlways); |
188 | fprintf(stderr__stderrp, "%s: trouble finding B-matrix:\n%s\n", me, err); |
189 | airMopError(mop); return 1; |
190 | } |
191 | } else { |
192 | airMopAdd(mop, nbmatKVP, (airMopper)nrrdNuke, airMopAlways); |
193 | if (nrrdConvert(nbmat, nbmatKVP, nrrdTypeDouble)) { |
194 | airMopAdd(mop, err=biffGetDone(NRRDnrrdBiffKey), airFree, airMopAlways); |
195 | fprintf(stderr__stderrp, "%s: trouble converting B-matrix:\n%s\n", me, err); |
196 | airMopError(mop); return 1; |
197 | } |
198 | } |
199 | /* this will work because of the impositions of tenDWMRIKeyValueParse */ |
200 | dwiax = ((nrrdKindList == nin[0]->axis[0].kind || |
201 | nrrdKindVector == nin[0]->axis[0].kind) |
202 | ? 0 |
203 | : ((nrrdKindList == nin[0]->axis[1].kind || |
204 | nrrdKindVector == nin[0]->axis[1].kind) |
205 | ? 1 |
206 | : ((nrrdKindList == nin[0]->axis[2].kind || |
207 | nrrdKindVector == nin[0]->axis[2].kind) |
208 | ? 2 |
209 | : 3))); |
210 | if (0 == dwiax) { |
211 | nin4d = nin[0]; |
212 | } else { |
213 | axmap[0] = dwiax; |
214 | axmap[1] = 1 > dwiax ? 1 : 0; |
215 | axmap[2] = 2 > dwiax ? 2 : 1; |
216 | axmap[3] = 3 > dwiax ? 3 : 2; |
217 | nin4d = nrrdNew(); |
218 | airMopAdd(mop, nin4d, (airMopper)nrrdNuke, airMopAlways); |
219 | if (nrrdAxesPermute(nin4d, nin[0], axmap)) { |
220 | airMopAdd(mop, err=biffGetDone(NRRDnrrdBiffKey), airFree, airMopAlways); |
221 | fprintf(stderr__stderrp, "%s: trouble creating DWI volume:\n%s\n", me, err); |
222 | airMopError(mop); return 1; |
223 | } |
224 | } |
225 | } |
226 | |
227 | nterr = NULL((void*)0); |
228 | nB0 = NULL((void*)0); |
229 | if (!oldstuff) { |
230 | if (1 != ninLen) { |
231 | fprintf(stderr__stderrp, "%s: sorry, currently need single 4D volume " |
232 | "for new implementation\n", me); |
233 | airMopError(mop); return 1; |
234 | } |
235 | if (!AIR_EXISTS(thresh)(((int)(!((thresh) - (thresh)))))) { |
236 | unsigned char *isB0 = NULL((void*)0); |
237 | double bten[7], bnorm, *bmat; |
238 | unsigned int sl; |
239 | /* from nbmat, create an array that indicates B0 images */ |
240 | if (tenBMatrixCheck(nbmat, nrrdTypeDouble, 6)) { |
241 | biffAddf(TENtenBiffKey, "%s: problem within given b-matrix", me); |
242 | airMopError(mop); return 1; |
243 | } |
244 | isB0 = AIR_CAST(unsigned char *, malloc(nbmat->axis[1].size))((unsigned char *)(malloc(nbmat->axis[1].size))); |
245 | airMopAdd(mop, isB0, airFree, airMopAlways); |
246 | bmat = (double*) nbmat->data; |
247 | for (sl=0; sl<nbmat->axis[1].size; sl++) { |
248 | TEN_T_SET(bten, 1.0,( (bten)[0] = (1.0), (bten)[1] = (bmat[0]), (bten)[2] = (bmat [1]), (bten)[3] = (bmat[2]), (bten)[4] = (bmat[3]), (bten)[5] = (bmat[4]), (bten)[6] = (bmat[5]) ) |
249 | bmat[0], bmat[1], bmat[2],( (bten)[0] = (1.0), (bten)[1] = (bmat[0]), (bten)[2] = (bmat [1]), (bten)[3] = (bmat[2]), (bten)[4] = (bmat[3]), (bten)[5] = (bmat[4]), (bten)[6] = (bmat[5]) ) |
250 | bmat[3], bmat[4],( (bten)[0] = (1.0), (bten)[1] = (bmat[0]), (bten)[2] = (bmat [1]), (bten)[3] = (bmat[2]), (bten)[4] = (bmat[3]), (bten)[5] = (bmat[4]), (bten)[6] = (bmat[5]) ) |
251 | bmat[5])( (bten)[0] = (1.0), (bten)[1] = (bmat[0]), (bten)[2] = (bmat [1]), (bten)[3] = (bmat[2]), (bten)[4] = (bmat[3]), (bten)[5] = (bmat[4]), (bten)[6] = (bmat[5]) ); |
252 | bnorm = TEN_T_NORM(bten)(sqrt(( (bten)[1]*(bten)[1] + 2*(bten)[2]*(bten)[2] + 2*(bten )[3]*(bten)[3] + (bten)[4]*(bten)[4] + 2*(bten)[5]*(bten)[5] + (bten)[6]*(bten)[6] ))); |
253 | isB0[sl]=(bnorm==0.0); |
254 | bmat+=6; |
255 | } |
256 | if (tenEstimateThresholdFind(&thresh, isB0, nin4d)) { |
257 | airMopAdd(mop, err=biffGetDone(TENtenBiffKey), airFree, airMopAlways); |
258 | fprintf(stderr__stderrp, "%s: trouble finding threshold:\n%s\n", me, err); |
259 | airMopError(mop); return 1; |
260 | } |
261 | /* HACK to lower threshold a titch */ |
262 | thresh *= 0.93; |
263 | fprintf(stderr__stderrp, "%s: using mean DWI threshold %g\n", me, thresh); |
264 | } |
265 | tec = tenEstimateContextNew(); |
266 | tec->progress = AIR_TRUE1; |
267 | airMopAdd(mop, tec, (airMopper)tenEstimateContextNix, airMopAlways); |
268 | EE = 0; |
269 | if (!EE) tenEstimateVerboseSet(tec, verbose); |
270 | if (!EE) tenEstimateNegEvalShiftSet(tec, fixneg); |
271 | if (!EE) EE |= tenEstimateMethodSet(tec, estmeth); |
272 | if (!EE) EE |= tenEstimateBMatricesSet(tec, nbmat, bval, !knownB0); |
273 | if (!EE) EE |= tenEstimateValueMinSet(tec, valueMin); |
274 | for (skipIdx=0; skipIdx<skipNum; skipIdx++) { |
275 | /* fprintf(stderr, "%s: skipping %u\n", me, skip[skipIdx]); */ |
276 | if (!EE) EE |= tenEstimateSkipSet(tec, skip[skipIdx], AIR_TRUE1); |
277 | } |
278 | switch(estmeth) { |
279 | case tenEstimate1MethodLLS: |
280 | if (airStrlen(terrS)) { |
281 | tec->recordErrorLogDwi = AIR_TRUE1; |
282 | /* tec->recordErrorDwi = AIR_TRUE; */ |
283 | } |
284 | break; |
285 | case tenEstimate1MethodNLS: |
286 | if (airStrlen(terrS)) { |
287 | tec->recordErrorDwi = AIR_TRUE1; |
288 | } |
289 | break; |
290 | case tenEstimate1MethodWLS: |
291 | if (!EE) tec->WLSIterNum = wlsi; |
292 | if (airStrlen(terrS)) { |
293 | tec->recordErrorDwi = AIR_TRUE1; |
294 | } |
295 | break; |
296 | case tenEstimate1MethodMLE: |
297 | if (!(AIR_EXISTS(sigma)(((int)(!((sigma) - (sigma))))) && sigma > 0.0)) { |
298 | fprintf(stderr__stderrp, "%s: can't do %s w/out sigma > 0 (not %g)\n", |
299 | me, airEnumStr(tenEstimate1Method, tenEstimate1MethodMLE), |
300 | sigma); |
301 | airMopError(mop); return 1; |
302 | } |
303 | if (!EE) EE |= tenEstimateSigmaSet(tec, sigma); |
304 | if (airStrlen(terrS)) { |
305 | tec->recordLikelihoodDwi = AIR_TRUE1; |
306 | } |
307 | break; |
308 | } |
309 | if (!EE) EE |= tenEstimateThresholdSet(tec, thresh, soft); |
310 | if (!EE) EE |= tenEstimateUpdate(tec); |
311 | if (EE) { |
312 | airMopAdd(mop, err=biffGetDone(TENtenBiffKey), airFree, airMopAlways); |
313 | fprintf(stderr__stderrp, "%s: trouble setting up estimation:\n%s\n", me, err); |
314 | airMopError(mop); return 1; |
315 | } |
316 | if (tenEstimate1TensorVolume4D(tec, nout, &nB0, |
317 | airStrlen(terrS) |
318 | ? &nterr |
319 | : NULL((void*)0), |
320 | nin4d, nrrdTypeFloat)) { |
321 | airMopAdd(mop, err=biffGetDone(TENtenBiffKey), airFree, airMopAlways); |
322 | fprintf(stderr__stderrp, "%s: trouble doing estimation:\n%s\n", me, err); |
323 | airMopError(mop); return 1; |
324 | } |
325 | if (airStrlen(terrS)) { |
326 | airMopAdd(mop, nterr, (airMopper)nrrdNuke, airMopAlways); |
327 | } |
328 | } else { |
329 | EE = 0; |
Value stored to 'EE' is never read | |
330 | if (1 == ninLen) { |
331 | EE = tenEstimateLinear4D(nout, airStrlen(terrS) ? &nterr : NULL((void*)0), &nB0, |
332 | nin4d, nbmat, knownB0, thresh, soft, bval); |
333 | } else { |
334 | EE = tenEstimateLinear3D(nout, airStrlen(terrS) ? &nterr : NULL((void*)0), &nB0, |
335 | (const Nrrd*const*)nin, ninLen, nbmat, |
336 | knownB0, thresh, soft, bval); |
337 | } |
338 | if (EE) { |
339 | airMopAdd(mop, err=biffGetDone(TENtenBiffKey), airFree, airMopAlways); |
340 | fprintf(stderr__stderrp, "%s: trouble making tensor volume:\n%s\n", me, err); |
341 | airMopError(mop); return 1; |
342 | } |
343 | } |
344 | if (nterr) { |
345 | /* it was allocated by tenEstimate*, we have to clean it up */ |
346 | airMopAdd(mop, nterr, (airMopper)nrrdNuke, airMopAlways); |
347 | } |
348 | if (nB0) { |
349 | /* it was allocated by tenEstimate*, we have to clean it up */ |
350 | airMopAdd(mop, nB0, (airMopper)nrrdNuke, airMopAlways); |
351 | } |
352 | if (1 != scale) { |
353 | if (tenSizeScale(nout, nout, scale)) { |
354 | airMopAdd(mop, err=biffGetDone(TENtenBiffKey), airFree, airMopAlways); |
355 | fprintf(stderr__stderrp, "%s: trouble doing scaling:\n%s\n", me, err); |
356 | airMopError(mop); return 1; |
357 | } |
358 | } |
359 | if (nterr) { |
360 | if (nrrdSave(terrS, nterr, NULL((void*)0))) { |
361 | airMopAdd(mop, err=biffGetDone(NRRDnrrdBiffKey), airFree, airMopAlways); |
362 | fprintf(stderr__stderrp, "%s: trouble writing error image:\n%s\n", me, err); |
363 | airMopError(mop); return 1; |
364 | } |
365 | } |
366 | if (!knownB0 && airStrlen(eb0S)) { |
367 | if (nrrdSave(eb0S, nB0, NULL((void*)0))) { |
368 | airMopAdd(mop, err=biffGetDone(NRRDnrrdBiffKey), airFree, airMopAlways); |
369 | fprintf(stderr__stderrp, "%s: trouble writing estimated B=0 image:\n%s\n", |
370 | me, err); |
371 | airMopError(mop); return 1; |
372 | } |
373 | } |
374 | |
375 | if (nrrdSave(outS, nout, NULL((void*)0))) { |
376 | airMopAdd(mop, err=biffGetDone(NRRDnrrdBiffKey), airFree, airMopAlways); |
377 | fprintf(stderr__stderrp, "%s: trouble writing:\n%s\n", me, err); |
378 | airMopError(mop); return 1; |
379 | } |
380 | |
381 | airMopOkay(mop); |
382 | return 0; |
383 | } |
384 | TEND_CMD(estim, INFO)unrrduCmd tend_estimCmd = { "estim", "Estimate tensors from a set of DW images" , tend_estimMain, 0 }; |