GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/ten/experSpec.c Lines: 51 173 29.5 %
Date: 2017-05-26 Branches: 17 110 15.5 %

Line Branch Exec Source
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
static int
28
_experAlloc(tenExperSpec* espec, unsigned int num) {
29
  static char me[]="_experAlloc";
30
31
16
  airFree(espec->bval); espec->bval = NULL;
32
8
  airFree(espec->grad); espec->grad = NULL;
33
  /* espec->wght = airFree(espec->wght); */
34
8
  if (!num) {
35
    biffAddf(TEN, "%s: need a non-zero number of images", me);
36
    return 1;
37
  }
38
8
  espec->imgNum = num;
39
8
  espec->bval = AIR_CALLOC(num, double);
40
8
  espec->grad = AIR_CALLOC(3*num, double);
41
  /* espec->wght = AIR_CALLOC(num, double); */
42

16
  if (!( espec->bval && espec->grad /* && espec->wght */ )) {
43
    biffAddf(TEN, "%s: couldn't allocate for %u images", me, num);
44
    return 1;
45
  }
46
8
  return 0;
47
8
}
48
49
tenExperSpec*
50
tenExperSpecNew(void) {
51
  tenExperSpec* espec;
52
53
16
  espec = AIR_CALLOC(1, tenExperSpec);
54
8
  espec->set = AIR_FALSE;
55
8
  espec->imgNum = 0;
56
8
  espec->bval = NULL;
57
8
  espec->grad = NULL;
58
  /* espec->wght = NULL; */
59
8
  return espec;
60
}
61
62
int
63
tenExperSpecGradSingleBValSet(tenExperSpec *espec,
64
                              int insertB0,
65
                              double bval,
66
                              const double *grad,
67
                              unsigned int gradNum) {
68
  static const char me[]="tenExperSpecGradSingleBValSet";
69
  unsigned int ii, imgNum, ei;
70
71
16
  if (!espec) {
72
    biffAddf(TEN, "%s: got NULL pointer", me);
73
    return 1;
74
  }
75

8
  if (insertB0 && !ELL_3V_LEN(grad + 3*0)) {
76
    biffAddf(TEN, "%s: wanted insertB0 but gradients "
77
             "already start with (0,0,0)", me);
78
    return 1;
79
  }
80
8
  imgNum = gradNum + !!insertB0;
81
8
  if (_experAlloc(espec, imgNum)) {
82
    biffAddf(TEN, "%s: couldn't allocate", me);
83
    return 1;
84
  }
85
8
  if (insertB0) {
86
    espec->bval[0] = 0;
87
    ELL_3V_SET(espec->grad + 3*0, 1, 0, 0);
88
    ei = 1;
89
  } else {
90
    ei = 0;
91
  }
92
192
  for (ii=0; ii<gradNum; ei++, ii++) {
93
88
    espec->bval[ei] = bval;
94
88
    ELL_3V_COPY(espec->grad + 3*ei, grad + 3*ii);
95
    /* espec->wght[ii] = 1.0; */
96
  }
97
98
8
  return 0;
99
8
}
100
101
int
102
tenExperSpecGradBValSet(tenExperSpec *espec,
103
                        int insertB0,
104
                        const double *bval,
105
                        const double *grad,
106
                        unsigned int bgNum) {
107
  static const char me[]="tenExperSpecGradBValSet";
108
  unsigned int ii, imgNum, ei;
109
110
  if (!espec) {
111
    biffAddf(TEN, "%s: got NULL pointer", me);
112
    return 1;
113
  }
114
  if (insertB0 && (!ELL_3V_LEN(grad + 3*0) || !bval[0])) {
115
    biffAddf(TEN, "%s: wanted insertB0 but gradients "
116
             "already start with (0,0,0) or bvals start with 0", me);
117
    return 1;
118
  }
119
  imgNum = bgNum + !!insertB0;
120
  if (_experAlloc(espec, imgNum)) {
121
    biffAddf(TEN, "%s: couldn't allocate", me);
122
    return 1;
123
  }
124
  if (insertB0) {
125
    espec->bval[0] = 0;
126
    ELL_3V_SET(espec->grad + 3*0, 0, 0, 0);
127
    ei = 1;
128
  } else {
129
    ei = 0;
130
  }
131
  for (ii=0; ii<bgNum; ei++, ii++) {
132
    espec->bval[ei] = bval[ii];
133
    ELL_3V_COPY(espec->grad + 3*ei, grad + 3*ii);
134
    /* espec->wght[ii] = 1.0; */
135
  }
136
137
  return 0;
138
}
139
140
/*
141
int
142
tenExperSpecGradBValWghtSet(tenExperSpec *espec,
143
                            unsigned int imgNum,
144
                            const double *bval,
145
                            const double *grad,
146
                            const double *wght) {
147
  static const char me[]="tenExperSpecGradBValWghtSet";
148
  unsigned int ii;
149
150
  if (!espec) {
151
    biffAddf(TEN, "%s: got NULL pointer", me);
152
    return 1;
153
  }
154
  if (_experAlloc(espec, imgNum)) {
155
    biffAddf(TEN, "%s: couldn't allocate", me);
156
    return 1;
157
  }
158
  for (ii=0; ii<imgNum; ii++) {
159
    espec->bval[ii] = bval[ii];
160
    ELL_3V_COPY(espec->grad + 3*ii, grad + 3*ii);
161
    espec->wght[ii] = wght[ii];
162
  }
163
164
  return 0;
165
}
166
*/
167
168
int
169
tenExperSpecFromKeyValueSet(tenExperSpec *espec, const Nrrd *ndwi) {
170
  static const char me[]="tenExperSpecFromKeyValueSet";
171
  unsigned int *skip, skipNum, ii, imgNum, dwiax;
172
  Nrrd *ngrad, *nbmat;
173
  airArray *mop;
174
  double len, singleBval, *bval, *grad;
175
176
  for (dwiax=0; dwiax<ndwi->dim; dwiax++) {
177
    if (nrrdKindList == ndwi->axis[dwiax].kind
178
        || nrrdKindVector == ndwi->axis[dwiax].kind) {
179
      break;
180
    }
181
  }
182
  if (ndwi->dim == dwiax) {
183
    biffAddf(TEN, "%s: need dwis to have a kind %s or %s axis", me,
184
             airEnumStr(nrrdKind, nrrdKindList),
185
             airEnumStr(nrrdKind, nrrdKindVector));
186
    return 1;
187
  } else {
188
    if (0 != dwiax) {
189
      biffAddf(TEN, "%s: need dwis (kind %s or %s) along axis 0, not %u", me,
190
               airEnumStr(nrrdKind, nrrdKindList),
191
               airEnumStr(nrrdKind, nrrdKindVector), dwiax);
192
      return 1;
193
    }
194
  }
195
  for (ii=dwiax+1; ii<ndwi->dim; ii++) {
196
    if (nrrdKindList == ndwi->axis[ii].kind
197
        || nrrdKindVector == ndwi->axis[ii].kind) {
198
      break;
199
    }
200
  }
201
  if (ii < ndwi->dim) {
202
    biffAddf(TEN, "%s: saw on %u another %s or %s kind axis, after 0", me,
203
             ii, airEnumStr(nrrdKind, nrrdKindList),
204
             airEnumStr(nrrdKind, nrrdKindVector));
205
    return 1;
206
  }
207
  if (tenDWMRIKeyValueParse(&ngrad, &nbmat, &singleBval,
208
                            &skip, &skipNum, ndwi)) {
209
    biffAddf(TEN, "%s: trouble parsing DWI info from key/value pairs", me);
210
    return 1;
211
  }
212
  mop = airMopNew();
213
  if (ngrad) {
214
    airMopAdd(mop, ngrad, (airMopper)nrrdNuke, airMopAlways);
215
  }
216
  if (nbmat) {
217
    airMopAdd(mop, nbmat, (airMopper)nrrdNuke, airMopAlways);
218
  }
219
  if (skip) {
220
    airMopAdd(mop, skip, airFree, airMopAlways);
221
  }
222
223
  if (nbmat) {
224
    biffAddf(TEN, "%s: sorry, currently can't handle B-matrices here", me);
225
    airMopError(mop); return 1;
226
  }
227
  if (skipNum) {
228
    biffAddf(TEN, "%s: sorry, currently can't handle skipping (%u) here", me,
229
             skipNum);
230
    airMopError(mop); return 1;
231
  }
232
233
  imgNum = ngrad->axis[1].size;
234
  bval = AIR_CALLOC(imgNum, double);
235
  airMopAdd(mop, bval, airFree, airMopAlways);
236
  grad = AIR_CAST(double *, ngrad->data);
237
  for (ii=0; ii<imgNum; ii++) {
238
    len = ELL_3V_LEN(grad + 3*ii);
239
    bval[ii] = singleBval*len*len;
240
    if (len) {
241
      ELL_3V_SCALE(grad + 3*ii, 1/len, grad + 3*ii);
242
    } else {
243
      ELL_3V_SET(grad + 3*ii, 0, 0, -1);
244
    }
245
  }
246
  if (tenExperSpecGradBValSet(espec, AIR_FALSE, bval, grad, imgNum)) {
247
    biffAddf(TEN, "%s: trouble", me);
248
    airMopError(mop); return 1;
249
  }
250
  airMopOkay(mop);
251
  return 0;
252
}
253
254
tenExperSpec*
255
tenExperSpecNix(tenExperSpec *espec) {
256
257
16
  if (espec) {
258
8
    airFree(espec->bval);
259
8
    airFree(espec->grad);
260
    /* espec->wght = airFree(espec->wght); */
261
8
    airFree(espec);
262
8
  }
263
8
  return NULL;
264
}
265
266
double
267
_tenExperSpec_sqe(const double *dwiMeas, const double *dwiSim,
268
                  const tenExperSpec *espec, int knownB0) {
269
  unsigned int ii;
270
  double sqe;
271
272
  sqe = 0;
273
  if (knownB0) {
274
    for (ii=0; ii<espec->imgNum; ii++) {
275
      double dd;
276
      if (!espec->bval[ii]) {
277
        continue;
278
      }
279
      dd = dwiMeas[ii] - dwiSim[ii];
280
      sqe += dd*dd;
281
      /*
282
      fprintf(stderr, "!%s: dwi[%u]: %g - %g -> %g\n", "_tenExperSpec_sqe",
283
              ii, dwiMeas[ii], dwiSim[ii], sqe);
284
      */
285
    }
286
  } else {
287
    for (ii=0; ii<espec->imgNum; ii++) {
288
      double dd;
289
      dd = dwiMeas[ii] - dwiSim[ii];
290
      sqe += dd*dd;
291
    }
292
  }
293
  return sqe;
294
}
295
296
double
297
_tenExperSpec_nll(const double *dwiMeas, const double *dwiSim,
298
                  const tenExperSpec *espec,
299
                  int rician, double sigma, int knownB0) {
300
  double nll;
301
  unsigned int ii;
302
303
  nll = 0;
304
  if (rician) {
305
    for (ii=0; ii<espec->imgNum; ii++) {
306
      if (knownB0 && !espec->bval[ii]) {
307
        continue;
308
      }
309
      nll += -airLogRician(dwiMeas[ii], dwiSim[ii], sigma);
310
    }
311
  } else {
312
    double dd, ladd, denom;
313
    ladd = log(sigma*sqrt(2*AIR_PI));
314
    denom = 1.0/(2*sigma*sigma);
315
    for (ii=0; ii<espec->imgNum; ii++) {
316
      if (knownB0 && !espec->bval[ii]) {
317
        continue;
318
      }
319
      dd = dwiMeas[ii] - dwiSim[ii];
320
      nll += dd*dd*denom + ladd;
321
    }
322
  }
323
  return nll;
324
}
325
326
int
327
tenDWMRIKeyValueFromExperSpecSet(Nrrd *ndwi, const tenExperSpec *espec) {
328
  static char me[]="tenDWMRIKeyValueFromExperSpecSet";
329
16
  char keystr[AIR_STRLEN_MED], valstr[AIR_STRLEN_MED];
330
  double maxb, bb;
331
  unsigned int ii;
332
333
8
  if (!(ndwi && espec)) {
334
    biffAddf(TEN, "%s: got NULL pointer", me);
335
    return 1;
336
  }
337
338
8
  nrrdKeyValueAdd(ndwi, tenDWMRIModalityKey, tenDWMRIModalityVal);
339
8
  maxb = tenExperSpecMaxBGet(espec);
340
8
  sprintf(valstr, "%.17g", maxb);
341
8
  nrrdKeyValueAdd(ndwi, tenDWMRIBValueKey, valstr);
342
192
  for (ii=0; ii<espec->imgNum; ii++) {
343
    double vec[3];
344
88
    sprintf(keystr, tenDWMRIGradKeyFmt, ii);
345
88
    ELL_3V_COPY(vec, espec->grad + 3*ii);
346
88
    bb = espec->bval[ii];
347
    /* Thu Dec 20 03:25:20 CST 2012 this rescaling is not, btw,
348
       what is causing the small discrepency between ngrad before
349
       and after saving to KVPs */
350
88
    ELL_3V_SCALE(vec, sqrt(bb/maxb), vec);
351
88
    sprintf(valstr, "%.17g %.17g %.17g", vec[0], vec[1], vec[2]);
352
88
    nrrdKeyValueAdd(ndwi, keystr, valstr);
353
  }
354
  /* HEY what if its a full B-matrix? */
355
356
8
  return 0;
357
8
}
358
359
/*
360
** learns B0 from DWIs by simple averaging of all the dwi[ii]
361
** without any diffusion weighting, as indicated by espec->bval[ii],
362
** or, returns AIR_NAN when there are no such dwi[ii]
363
*/
364
double
365
tenExperSpecKnownB0Get(const tenExperSpec *espec, const double *dwi) {
366
  unsigned int ii, nb;
367
  double ret, b0;
368
369
  if (!( dwi && espec )) {
370
    return AIR_NAN;
371
  }
372
373
  nb = 0;
374
  b0 = 0.0;
375
  for (ii=0; ii<espec->imgNum; ii++) {
376
    if (0 == espec->bval[ii]) {
377
      b0 += dwi[ii];
378
      ++nb;
379
    }
380
  }
381
  if (nb) {
382
    ret = b0/nb;
383
  } else {
384
    ret = AIR_NAN;
385
  }
386
  return ret;
387
}
388
389
double
390
tenExperSpecMaxBGet(const tenExperSpec *espec) {
391
  unsigned int ii;
392
  double bval;
393
394
16
  if (!( espec )) {
395
    return AIR_NAN;
396
  }
397
398
  bval = -1;
399
192
  for (ii=0; ii<espec->imgNum; ii++) {
400
264
    bval = AIR_MAX(bval, espec->bval[ii]);
401
  }
402
8
  return bval;
403
8
}