Developer documentation
Version 3.0.3-105-gd3941f44
dynamic.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_seeding_dynamic_h__
18#define __dwi_tractography_seeding_dynamic_h__
19
20#include <fstream>
21#include <queue>
22#include <atomic>
23
24#include "transform.h"
25#include "thread_queue.h"
26#include "dwi/fmls.h"
27#include "dwi/directions/set.h"
37
38
39
40
41//#define DYNAMIC_SEED_DEBUGGING
42
43
44
45// TD_sum is set to this at the start of execution to prevent a divide_by_zero error
46#define DYNAMIC_SEED_INITIAL_TD_SUM 1e-6
47
48
49// Initial seeding probability: Smaller will be slower, but allow under-reconstructed fixels
50// to be seeded more densely
51#define DYNAMIC_SEED_INITIAL_PROB 1e-3
52
53
54// Applicable for approach 2 with correlation term only:
55// How much of the projected change in seed probability is included in seeds outside the fixel
56#define DYNAMIC_SEEDING_DAMPING_FACTOR 0.5
57
58
59
60namespace MR
61{
62 namespace DWI
63 {
64 namespace Tractography
65 {
66
67 namespace ACT { class GMWMI_finder; }
68
69 namespace Seeding
70 {
71
72
73
75 { MEMALIGN(Fixel_TD_seed)
76
77 public:
78 Fixel_TD_seed (const FMLS::FOD_lobe& lobe) :
79 SIFT::FixelBase (lobe),
80 voxel (-1, -1, -1),
82 update (true),
84 applied_prob (old_prob),
85 track_count_at_last_update (0),
86 seed_count (0) {
87 updating.clear();
88 }
89
90 Fixel_TD_seed (const Fixel_TD_seed& that) :
91 SIFT::FixelBase (that),
92 voxel (that.voxel),
93 TD (double(that.TD)),
94 update (that.update),
95 old_prob (that.old_prob),
96 applied_prob (that.applied_prob),
97 track_count_at_last_update (that.track_count_at_last_update),
98 seed_count (that.seed_count) {
99 updating.clear();
100 }
101
102 Fixel_TD_seed() :
104 voxel (-1, -1, -1),
105 TD (0.0),
106 update (true),
107 old_prob (DYNAMIC_SEED_INITIAL_PROB),
108 applied_prob (old_prob),
109 track_count_at_last_update (0),
110 seed_count (0) {
111 updating.clear();
112 }
113
114
115 double get_TD () const { return TD.load (std::memory_order_relaxed); }
116 void clear_TD () { TD.store (0.0, std::memory_order_relaxed); }
117 double get_diff (const double mu) const { return ((TD.load (std::memory_order_relaxed) * mu) - FOD); }
118
119 void mask() { update = false; }
120 bool can_update() const { return update; }
121
122
123 Fixel_TD_seed& operator+= (const double length)
124 {
125 // Apparently the first version may be preferable due to bugs in earlier compiler versions...
126 //double old_TD, new_TD;
127 //do {
128 // old_TD = TD.load (std::memory_order_relaxed);
129 // new_TD = old_TD + length;
130 //} while (!TD.compare_exchange_weak (old_TD, new_TD, std::memory_order_relaxed));
131 double old_TD = TD.load (std::memory_order_relaxed);
132 while (!TD.compare_exchange_weak (old_TD, old_TD + length, std::memory_order_relaxed));
133 return *this;
134 }
135
136
137 void set_voxel (const Eigen::Vector3i& i) { voxel = i; }
138 const Eigen::Vector3i& get_voxel() const { return voxel; }
139
140 float get_ratio (const double mu) const { return ((mu * TD.load (std::memory_order_relaxed)) / FOD); }
141
142
143 float get_cumulative_prob (const uint64_t track_count)
144 {
145 while (updating.test_and_set (std::memory_order_acquire));
146 float cumulative_prob = old_prob;
147 if (track_count > track_count_at_last_update) {
148 cumulative_prob = ((track_count_at_last_update * old_prob) + ((track_count - track_count_at_last_update) * applied_prob)) / float(track_count);
149 old_prob = cumulative_prob;
150 track_count_at_last_update = track_count;
151 }
152 return cumulative_prob;
153 }
154
155 void update_prob (const float new_prob, const bool seed_drawn)
156 {
157 applied_prob = new_prob;
158 if (seed_drawn)
159 ++seed_count;
160 updating.clear (std::memory_order_release);
161 }
162
163
164 float get_old_prob() const { return old_prob; }
165 float get_prob() const { return applied_prob; }
166 size_t get_seed_count() const { return seed_count; }
167
168
169
170 private:
171 Eigen::Vector3i voxel;
172 std::atomic<double> TD; // Protect against concurrent reads & writes, though perfect thread concurrency is not necessary
173 bool update; // For small / noisy fixels, exclude the seeding probability from being updated
174
175 // Multiple values to update - use an atomic boolean in a similar manner to a mutex, but with less overhead
176 std::atomic_flag updating;
177 float old_prob, applied_prob;
178 size_t track_count_at_last_update;
179 size_t seed_count;
180
181 };
182
183
184
185
187 { MEMALIGN(Dynamic_ACT_additions)
188
189 public:
190 Dynamic_ACT_additions (const std::string& path) :
191 interp_template (Image<float>::open (path)),
192 gmwmi_finder (interp_template) { }
193
194 bool check_seed (Eigen::Vector3f&);
195
196 private:
197 Interp::Linear<Image<float>> interp_template;
198 ACT::GMWMI_finder gmwmi_finder;
199
200
201 };
202
203
204
205
206
207 class Dynamic : public Base, public SIFT::ModelBase<Fixel_TD_seed>
209 private:
210
211 using Fixel = Fixel_TD_seed;
212
213 using MapVoxel = Fixel_map<Fixel>::MapVoxel;
215
216
217 public:
218 Dynamic (const std::string&, Image<float>&, const size_t, const DWI::Directions::FastLookupSet&);
220
221 Dynamic (const Dynamic&) = delete;
222 Dynamic& operator= (const Dynamic&) = delete;
223
224 bool get_seed (Eigen::Vector3f&) const override;
225 bool get_seed (Eigen::Vector3f&, Eigen::Vector3f&) override;
226
227 // Although the ModelBase version of this function is OK, the Fixel_TD_seed class
228 // includes the voxel location for easier determination of seed location
229 bool operator() (const FMLS::FOD_lobes&) override;
230
231 bool operator() (const Mapping::SetDixel& i) override
232 {
233 if (!i.weight) // Flags that tracking should terminate
234 return false;
235 if (!i.empty()) {
236#ifdef DYNAMIC_SEED_DEBUGGING
237 const size_t updated_count = ++track_count;
238 if (updated_count == target_trackcount / 2)
239 output_fixel_images();
240 if (updated_count >= target_trackcount)
241 return false;
242#else
243 if (++track_count >= target_trackcount)
244 return false;
245#endif
246 }
248 }
249
250
251 private:
254
257
258 // New members required for new dynamic seed probability equation
259 const size_t target_trackcount;
260 std::atomic<size_t> track_count;
261
262 // Want to know statistics on dynamic seeding sampling
263 std::atomic<uint64_t> attempts, seeds;
264
265
266#ifdef DYNAMIC_SEED_DEBUGGING
267 Tractography::Writer<float> seed_output;
268 void write_seed (const Eigen::Vector3f&);
269 size_t test_fixel;
270 void output_fixel_images();
271#endif
272
273 Transform transform;
274
275 std::unique_ptr<Dynamic_ACT_additions> act;
276
277 void perform_fixel_masking();
278
279 };
280
281
282
283
284
286 { MEMALIGN(WriteKernelDynamic)
287 public:
288 WriteKernelDynamic (const Tracking::SharedBase& shared, const std::string& output_file, const Properties& properties) :
289 Tracking::WriteKernel (shared, output_file, properties) { }
290 WriteKernelDynamic (const WriteKernelDynamic&) = delete;
291 WriteKernelDynamic& operator= (const WriteKernelDynamic&) = delete;
292 bool operator() (const Tracking::GeneratedTrack&, Streamline<>&);
293 };
294
295
296
297
298
299 }
300 }
301 }
302}
303
304#endif
305
virtual bool operator()(const FMLS::FOD_lobes &in)
Definition: model_base.h:261
bool operator()(const FMLS::FOD_lobes &) override
bool get_seed(Eigen::Vector3f &, Eigen::Vector3f &) override
Dynamic & operator=(const Dynamic &)=delete
bool get_seed(Eigen::Vector3f &) const override
Dynamic(const std::string &, Image< float > &, const size_t, const DWI::Directions::FastLookupSet &)
class to handle writing tracks to file, with RAM buffer
Definition: file.h:353
functions and classes related to image data input/output
Definition: image.h:41
#define DYNAMIC_SEED_INITIAL_PROB
Definition: dynamic.h:51
PointType::Scalar length(const vector< PointType > &tck)
Definition: streamline.h:134
Definition: base.h:24
#define MEMALIGN(...)
Definition: types.h:185