Developer documentation
Version 3.0.3-105-gd3941f44
iFOD1.h
Go to the documentation of this file.
1/* Copyright (c) 2008-2022 the MRtrix3 contributors.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 *
7 * Covered Software is provided under this License on an "as is"
8 * basis, without warranty of any kind, either expressed, implied, or
9 * statutory, including, without limitation, warranties that the
10 * Covered Software is free of defects, merchantable, fit for a
11 * particular purpose or non-infringing.
12 * See the Mozilla Public License v. 2.0 for more details.
13 *
14 * For more details, see http://www.mrtrix.org/.
15 */
16
17#ifndef __dwi_tractography_algorithms_iFOD1_h__
18#define __dwi_tractography_algorithms_iFOD1_h__
19
20#include "math/SH.h"
26
27
28
29namespace MR
30{
31 namespace DWI
32 {
33 namespace Tractography
34 {
35 namespace Algorithms
36 {
37
38 extern const App::OptionGroup iFODOptions;
40
41 using namespace MR::DWI::Tractography::Tracking;
42
43 class iFOD1 : public MethodBase { MEMALIGN(iFOD1)
44 public:
45 class Shared : public SharedBase { MEMALIGN(Shared)
46 public:
47 Shared (const std::string& diff_path, DWI::Tractography::Properties& property_set) :
48 SharedBase (diff_path, property_set),
49 lmax (Math::SH::LforN (source.size(3))),
51 sin_max_angle_1o (std::sin (max_angle_1o)),
52 fod_power (1.0f),
53 mean_samples (0.0),
54 mean_truncations (0.0),
55 max_max_truncation (0.0),
56 num_proc (0) {
57
58 try {
60 } catch (Exception& e) {
61 e.display();
62 throw Exception ("Algorithm iFOD1 expects as input a spherical harmonic (SH) image");
63 }
64
67 rk4);
68
69 // max_angle_1o needs to be set because it influences the cone in which FOD amplitudes are sampled
70 if (rk4) {
71 max_angle_1o = max_angle_ho;
72 cos_max_angle_1o = std::cos (max_angle_1o);
73 max_angle_ho = Math::pi_2;
74 cos_max_angle_ho = 0.0;
75 }
76 sin_max_angle_1o = std::sin (max_angle_1o);
77 set_num_points();
78 set_cutoff (Defaults::cutoff_fod * (is_act() ? Defaults::cutoff_act_multiplier : 1.0));
79
80 properties["method"] = "iFOD1";
81 properties.set (lmax, "lmax");
82 properties.set (max_trials, "max_trials");
83 properties.set (fod_power, "fod_power");
84 bool precomputed = true;
85 properties.set (precomputed, "sh_precomputed");
86 if (precomputed)
87 precomputer.init (lmax);
88
89 }
90
91 ~Shared ()
92 {
93 mean_samples /= double(num_proc);
94 mean_truncations /= double(num_proc);
95 INFO ("mean number of samples per step = " + str (mean_samples));
96 if (mean_truncations) {
97 INFO ("mean number of steps between rejection sampling truncations = " + str (1.0/mean_truncations));
98 INFO ("maximum truncation error = " + str (max_max_truncation));
99 } else {
100 INFO ("no rejection sampling truncations occurred");
101 }
102 }
103
104 void update_stats (double mean_samples_per_run, double mean_truncations_per_run, double max_truncation) const
105 {
106 mean_samples += mean_samples_per_run;
107 mean_truncations += mean_truncations_per_run;
108 if (max_truncation > max_max_truncation)
109 max_max_truncation = max_truncation;
110 ++num_proc;
111 }
112
113 size_t lmax, max_trials;
114 float sin_max_angle_1o, fod_power;
116
117 private:
118 mutable double mean_samples, mean_truncations, max_max_truncation;
119 mutable int num_proc;
120 };
121
122
123
124
125
126
127 iFOD1 (const Shared& shared) :
128 MethodBase (shared),
129 S (shared),
130 source (S.source),
131 mean_sample_num (0),
132 num_sample_runs (0),
133 num_truncations (0),
134 max_truncation (0.0) {
135 calibrate (*this);
136 }
137
138
139 ~iFOD1 ()
140 {
141 S.update_stats (calibrate_list.size() + float(mean_sample_num)/float(num_sample_runs),
142 float(num_truncations) / float(num_sample_runs),
144 }
145
146
147
148 bool init() override
149 {
150 if (!get_data (source))
151 return (false);
152
153 if (!S.init_dir.allFinite()) {
154
155 const Eigen::Vector3f init_dir (dir);
156
157 for (size_t n = 0; n < S.max_seed_attempts; n++) {
158 dir = init_dir.allFinite() ? rand_dir (init_dir) : random_direction();
159 float val = FOD (dir);
160 if (std::isfinite (val))
161 if (val > S.init_threshold)
162 return true;
163 }
164
165 }
166 else {
167 dir = S.init_dir;
168 float val = FOD (dir);
169 if (std::isfinite (val))
170 if (val > S.init_threshold)
171 return true;
172
173 }
174
175 return false;
176 }
177
178
179
180 term_t next () override
181 {
182 if (!get_data (source))
183 return EXIT_IMAGE;
184
185 float max_val = 0.0;
186 for (size_t i = 0; i < calibrate_list.size(); ++i) {
187 float val = FOD (rotate_direction (dir, calibrate_list[i]));
188 if (std::isnan (val))
189 return EXIT_IMAGE;
190 else if (val > max_val)
191 max_val = val;
192 }
193
194 if (max_val <= 0.0)
195 return CALIBRATOR;
196
197 max_val = std::pow (max_val, S.fod_power) * calibrate_ratio;
198
200
201 for (size_t n = 0; n < S.max_trials; n++) {
202 Eigen::Vector3f new_dir = rand_dir (dir);
203 float val = FOD (new_dir);
204
205 if (val > S.threshold) {
206
207 val = std::pow (val, S.fod_power);
208 if (val > max_val) {
209 DEBUG ("max_val exceeded!!! (val = " + str(val) + ", max_val = " + str (max_val) + ")");
211 if (val/max_val > max_truncation)
212 max_truncation = val/max_val;
213 }
214
215 if (uniform(rng) < val/max_val) {
216 dir = new_dir;
217 dir.normalize();
218 pos += S.step_size * dir;
219 mean_sample_num += n;
220 return CONTINUE;
221 }
222
223 }
224 }
225
226 return MODEL;
227 }
228
229
230 float get_metric (const Eigen::Vector3f& position, const Eigen::Vector3f& direction) override
231 {
232 if (!get_data (source, position))
233 return 0.0;
234 return FOD (direction);
235 }
236
237
238 protected:
239 const Shared& S;
245
246 float FOD (const Eigen::Vector3f& d) const
247 {
248 return (S.precomputer ?
249 S.precomputer.value (values, d) :
250 Math::SH::value (values, d, S.lmax)
251 );
252 }
253
254 Eigen::Vector3f rand_dir (const Eigen::Vector3f& d) { return (random_direction (d, S.max_angle_1o, S.sin_max_angle_1o)); }
255
256
257
258
259
261 { MEMALIGN (Calibrate)
262 public:
263 Calibrate (iFOD1& method) :
264 P (method),
265 fod (P.values)
266 {
267 Math::SH::delta (fod, Eigen::Vector3f (0.0, 0.0, 1.0), P.S.lmax);
268 }
269
270 float operator() (float el)
271 {
272 return std::pow (Math::SH::value (P.values, Eigen::Vector3f (std::sin (el), 0.0, std::cos(el)), P.S.lmax), P.S.fod_power);
273 }
274
275 private:
276 iFOD1& P;
277 Eigen::VectorXf& fod;
278 };
279
280 friend void calibrate<iFOD1> (iFOD1& method);
281
282 };
283
284 }
285 }
286 }
287}
288
289#endif
290
float el
Definition: calibrator.h:61
Eigen::Vector3f rand_dir(const Eigen::Vector3f &d)
Definition: iFOD1.h:254
Interpolator< Image< float > >::type source
Definition: iFOD1.h:240
float FOD(const Eigen::Vector3f &d) const
Definition: iFOD1.h:246
vector< Eigen::Vector3f > calibrate_list
Definition: iFOD1.h:244
friend void calibrate(iFOD1 &method)
std::uniform_real_distribution< float > uniform
Definition: method.h:95
Eigen::Vector3f rotate_direction(const Eigen::Vector3f &reference, const Eigen::Vector3f &direction)
Precomputed Associated Legrendre Polynomials - used to speed up SH calculation.
Definition: SH.h:400
#define INFO(msg)
Definition: exception.h:74
#define DEBUG(msg)
Definition: exception.h:75
constexpr double e
Definition: math.h:39
constexpr double pi_2
Definition: math.h:41
void check(const ImageType &H)
convenience function to check if an input image can contain SH coefficients
Definition: SH.h:745
size_t LforN(int N)
returns the largest lmax given N parameters
Definition: SH.h:70
VectorType1 & delta(VectorType1 &delta_vec, const VectorType2 &unit_dir, int lmax)
Definition: SH.h:279
VectorType::Scalar value(const VectorType &coefs, typename VectorType::Scalar cos_elevation, typename VectorType::Scalar cos_azimuth, typename VectorType::Scalar sin_azimuth, int lmax)
Definition: SH.h:233
const App::OptionGroup iFODOptions
void load_iFOD_options(Tractography::Properties &)
thread_local Math::RNG rng
thread-local, but globally accessible RNG to vastly simplify multi-threading
Definition: base.h:24
std::string str(const T &value, int precision=0)
Definition: mrtrix.h:247
#define MEMALIGN(...)
Definition: types.h:185