1 /*
2   Teem: Tools to process and visualize scientific data and images             .
3   Copyright (C) 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 /* NOTE: this model is a single 2nd-order tensor, not a two-tensor model */
28 
29 #define PARM_NUM 7
30 /* 1/sqrt(2) */
31 #define OST 0.70710678118654752440
32 static const tenModelParmDesc
33 parmDesc[] = {
34   /* 0 */ {"B0", 0.0, TEN_MODEL_B0_MAX, AIR_FALSE, AIR_FALSE, 0},
35   /* 1 */ {"Dxx", -TEN_MODEL_DIFF_MAX,     TEN_MODEL_DIFF_MAX,     AIR_FALSE, AIR_FALSE, 0},
36   /* 2 */ {"Dxy", -TEN_MODEL_DIFF_MAX*OST, TEN_MODEL_DIFF_MAX*OST, AIR_FALSE, AIR_FALSE, 0},
37   /* 3 */ {"Dxz", -TEN_MODEL_DIFF_MAX*OST, TEN_MODEL_DIFF_MAX*OST, AIR_FALSE, AIR_FALSE, 0},
38   /* 4 */ {"Dyy", -TEN_MODEL_DIFF_MAX,     TEN_MODEL_DIFF_MAX,     AIR_FALSE, AIR_FALSE, 0},
39   /* 5 */ {"Dyz", -TEN_MODEL_DIFF_MAX*OST, TEN_MODEL_DIFF_MAX*OST, AIR_FALSE, AIR_FALSE, 0},
40   /* 6 */ {"Dzz", -TEN_MODEL_DIFF_MAX,     TEN_MODEL_DIFF_MAX,     AIR_FALSE, AIR_FALSE, 0}
41 };
42 
43 static void
simulate(double * dwiSim,const double * parm,const tenExperSpec * espec)44 simulate(double *dwiSim, const double *parm, const tenExperSpec *espec) {
45   unsigned int ii;
46   double b0;
47 
48   b0 = parm[0];
49   for (ii=0; ii<espec->imgNum; ii++) {
50     double adc, bb;
51     bb = espec->bval[ii];
52     /* safe because TEN_T3V_CONTR never looks at parm[0] */
53     adc = TEN_T3V_CONTR(parm, espec->grad + 3*ii);
54     dwiSim[ii] = b0*exp(-bb*adc);
55   }
56   return;
57 }
58 
59 static char *
parmSprint(char str[AIR_STRLEN_MED],const double * parm)60 parmSprint(char str[AIR_STRLEN_MED], const double *parm) {
61   sprintf(str, "(%g) [%g %g %g;  %g %g;   %g]", parm[0],
62           parm[1], parm[2], parm[3],
63           parm[4], parm[5],
64           parm[6]);
65   return str;
66 }
67 
68 _TEN_PARM_ALLOC
69 _TEN_PARM_RAND
70 _TEN_PARM_STEP
71 _TEN_PARM_DIST
72 _TEN_PARM_COPY
73 
74 static int
parmConvert(double * parmDst,const double * parmSrc,const tenModel * modelSrc)75 parmConvert(double *parmDst, const double *parmSrc,
76             const tenModel *modelSrc) {
77   int ret;
78 
79   if (modelSrc == tenModelBall) {
80     TEN_T_SET(parmDst, parmSrc[0],
81               parmSrc[1], 0, 0,
82               parmSrc[1], 0,
83               parmSrc[1]);
84     ret = 0;
85   } else if (modelSrc == tenModel1Stick) {
86     double ten[7];
87     TEN_T3V_OUTER(ten, parmSrc + 2);
88     TEN_T_SCALE(parmDst, parmSrc[1], ten);
89     parmDst[0] = parmSrc[0];
90     ret = 0;
91   } else if (modelSrc == tenModelBall1Stick) {
92     double stick[7], ball[7], diff, frac;
93     diff = parmSrc[1];
94     frac = parmSrc[2];
95     TEN_T3V_OUTER(stick, parmSrc + 3);
96     TEN_T_SCALE(stick, diff, stick);
97     TEN_T_SET(ball, 1, diff, 0, 0, diff, 0, diff);
98     TEN_T_LERP(parmDst, frac, ball, stick);
99     parmDst[0] = parmSrc[0];
100     ret = 1;
101   } else if (modelSrc == tenModel1Cylinder) {
102     double stick[7], ball[7], len, rad;
103     len = parmSrc[1];
104     rad = parmSrc[2];
105     TEN_T3V_OUTER(stick, parmSrc + 3);
106     TEN_T_SCALE(stick, len-rad, stick);
107     TEN_T_SET(ball, 1, rad, 0, 0, rad, 0, rad);
108     TEN_T_ADD(parmDst, ball, stick);
109     parmDst[0] = parmSrc[0];
110     ret = 0;
111   } else if (modelSrc == tenModel1Tensor2) {
112     parmCopy(parmDst, parmSrc);
113     ret = 0;
114   } else {
115     unsigned int ii;
116     for (ii=0; ii<PARM_NUM; ii++) {
117       parmDst[ii] = AIR_NAN;
118     }
119     ret = 2;
120   }
121   return ret;
122 }
123 
124 _TEN_SQE
125 _TEN_SQE_GRAD_CENTDIFF
126 _TEN_SQE_FIT(tenModel1Tensor2)
127 
128 _TEN_NLL
129 _TEN_NLL_GRAD_STUB
130 _TEN_NLL_FIT_STUB
131 
132 tenModel
133 _tenModel1Tensor2 = {
134   TEN_MODEL_STR_1TENSOR2,
135   _TEN_MODEL_FIELDS
136 };
137 const tenModel *const tenModel1Tensor2 = &_tenModel1Tensor2;
138