17#ifndef __dwi_tractography_tracking_exec_h__
18#define __dwi_tractography_tracking_exec_h__
39#define MAX_NUM_SEED_ATTEMPTS 100000
41#define TRACKING_BATCH_SIZE 10
49 namespace Tractography
64 if (properties.find (
"seed_dynamic") == properties.end()) {
66 typename Method::Shared shared (diff_path, properties);
67 WriteKernel writer (shared, destination, properties);
73 const std::string& fod_path (properties[
"seed_dynamic"]);
74 const std::string max_num_tracks = properties[
"max_num_tracks"];
75 if (max_num_tracks.empty())
76 throw Exception (
"Dynamic seeding requires setting the desired number of tracks using the -select option");
77 const size_t num_tracks = to<size_t>(max_num_tracks);
87 properties.seeds.add (seeder);
89 typename Method::Shared shared (diff_path, properties);
91 Writer writer (shared, destination, properties);
94 TckMapper mapper (fod_data, dirs);
96 mapper.set_use_precise_mapping (
true);
113 Exec (
const typename Method::Shared& shared) :
116 track_excluded (
false),
117 include_visitation (S.properties.include, S.properties.ordered_include) { }
121 method (that.method),
122 track_excluded (
false),
123 include_visitation (S.properties.include, S.properties.ordered_include) { }
127 if (!seed_track (
item))
129 if (track_excluded) {
130 item.set_status (GeneratedTrack::status_t::SEED_REJECTED);
135 if (track_rejected (
item)) {
137 item.set_status (GeneratedTrack::status_t::TRACK_REJECTED);
138 }
else if (S.downsampler.get_ratio() > 1 || (S.is_act() && S.act().crop_at_gmwmi())) {
139 S.downsampler (
item);
140 check_downsampled_length (
item);
142 item.set_status (GeneratedTrack::status_t::ACCEPTED);
150 const typename Method::Shared& S;
158 const term_t method_term = (
S.rk4 ? next_rk4() : method.next());
161 return (
S.is_act() && method.act().sgm_depth) ?
TERM_IN_SGM : method_term;
164 const term_t structural_term = method.act().check_structural (method.pos);
166 return structural_term;
169 if (
S.properties.mask.size() && !
S.properties.mask.contains (method.pos))
172 if (
S.properties.exclude.contains (method.pos))
177 if (!(
S.is_act() &&
S.act().backtrack()))
178 include_visitation (method.pos);
180 if (
S.stop_on_all_include &&
bool(include_visitation))
191 track_excluded =
false;
192 include_visitation.reset();
195 if (
S.properties.seeds.is_finite()) {
197 if (!
S.properties.seeds.get_seed (method.pos, method.dir))
199 if (!method.check_seed() || !method.init()) {
200 track_excluded =
true;
201 tck.set_status (GeneratedTrack::status_t::SEED_REJECTED);
208 if (
S.properties.seeds.get_seed (method.pos, method.dir)) {
209 if (!(method.check_seed() && method.init())) {
210 track_excluded =
true;
211 tck.set_status (GeneratedTrack::status_t::SEED_REJECTED);
226 bool unidirectional =
S.unidirectional;
227 if (
S.is_act() && !unidirectional)
228 unidirectional = method.act().seed_is_unidirectional (method.pos, method.dir);
230 include_visitation (method.pos);
232 const Eigen::Vector3f seed_dir (method.dir);
233 tck.push_back (method.pos);
235 gen_track_unidir (tck);
237 if (!track_excluded && !unidirectional) {
239 method.pos = tck.back();
240 method.dir = -seed_dir;
241 method.reverse_track ();
242 gen_track_unidir (tck);
255 if (
S.is_act() &&
S.act().backtrack()) {
257 size_t revert_step = 1;
258 size_t max_size_at_backtrack = tck.size();
259 unsigned int revert_count = 0;
262 termination = iterate();
264 tck.push_back (method.pos);
266 apply_priors (termination);
268 if (tck.size() > max_size_at_backtrack) {
269 max_size_at_backtrack = tck.size();
278 method.truncate_track (tck, max_size_at_backtrack, revert_step);
279 if (method.pos.allFinite()) {
280 track_excluded =
false;
284 }
else if (tck.size() >=
S.max_num_points_preds) {
287 }
while (!termination);
292 termination = iterate();
294 tck.push_back (method.pos);
295 if (!termination && tck.size() >=
S.max_num_points_preds)
297 }
while (!termination);
301 apply_priors (termination);
304 truncate_exit_sgm (tck);
305 method.pos = tck.back();
308 if (track_excluded) {
309 switch (termination) {
320 throw Exception (
"\nFIXME: Unidirectional track excluded but termination is good!\n");
324 if (
S.is_act() && (termination ==
ENTER_CGM) &&
S.act().crop_at_gmwmi())
325 S.act().crop_at_gmwmi (tck);
327#ifdef DEBUG_TERMINATIONS
328 S.add_termination (termination, method.pos);
330 S.add_termination (termination);
337 void apply_priors (
term_t& termination)
342 switch (termination) {
345 throw Exception (
"\nFIXME: undefined termination of track in apply_priors()\n");
351 track_excluded =
true;
355 if (method.act().sgm_depth)
357 else if (!method.act().in_pathology())
358 track_excluded =
true;
365 switch (termination) {
368 throw Exception (
"\nFIXME: undefined termination of track in apply_priors()\n");
371 throw Exception (
"\nFIXME: Have received ACT-based termination for non-ACT tracking in apply_priors()\n");
377 track_excluded =
true;
395 if (tck.size() == 1 &&
S.min_num_points_preds > 1) {
400 if (tck.size() <
S.min_num_points_preds) {
407 if (!satisfy_wm_requirement (tck)) {
412 if (
S.act().backtrack()) {
413 for (
const auto& i : tck)
414 include_visitation (i);
419 if (!
bool(include_visitation)) {
431 if (
S.max_num_points_preds == 2)
434 if (method.act().seed_in_sgm && !method.act().sgm_seed_to_wm)
440 float integral = 0.0, max_value = 0.0;
441 for (
const auto& i : tck) {
442 if (method.act().fetch_tissue_data (i)) {
443 const float wm = method.act().tissues().get_wm();
444 max_value = std::max (max_value, wm);
456 const size_t sgm_start = tck.size() - method.act().sgm_depth;
457 assert (sgm_start >= 0 && sgm_start < tck.size());
458 size_t best_termination = tck.size() - 1;
459 float min_value = std::numeric_limits<float>::infinity();
460 for (
size_t i = sgm_start; i != tck.size(); ++i) {
461 const Eigen::Vector3f direction = (tck[i] - tck[i-1]).normalized();
462 const float this_value = method.get_metric (tck[i], direction);
463 if (this_value < min_value) {
464 min_value = this_value;
465 best_termination = i;
468 tck.erase (tck.begin() + best_termination + 1, tck.end());
478 if (tck.size() >
S.min_num_points_postds && tck.size() <
S.max_num_points_postds) {
479 tck.set_status (GeneratedTrack::status_t::ACCEPTED);
485 tck.set_status (GeneratedTrack::status_t::TRACK_REJECTED);
487 }
else if (
length >
S.max_dist) {
490 tck.set_status (GeneratedTrack::status_t::TRACK_REJECTED);
493 truncate_maxlength (tck);
494 tck.set_status (GeneratedTrack::status_t::ACCEPTED);
497 tck.set_status (GeneratedTrack::status_t::ACCEPTED);
509 float length_sum = 0.0f;
512 const float seg_length = (tck[
index] - tck[
index-1]).norm();
513 if (length_sum + seg_length >
S.max_dist)
515 length_sum += seg_length;
519 assert (
index != tck.size());
521 if (
index == tck.size())
529 if (tck.get_seed_index() >=
index) {
530 tck.resize (tck.get_seed_index()+1);
532 truncate_maxlength (tck);
539 tck.resize (
index+1);
548 const Eigen::Vector3f init_pos (method.pos);
549 const Eigen::Vector3f init_dir (method.dir);
550 if ((termination = method.next()))
552 const Eigen::Vector3f dir_rk1 (method.dir);
553 method.pos = init_pos + (dir_rk1 * (0.5 *
S.step_size));
554 method.dir = init_dir;
555 if ((termination = method.next()))
557 const Eigen::Vector3f dir_rk2 (method.dir);
558 method.pos = init_pos + (dir_rk2 * (0.5 *
S.step_size));
559 method.dir = init_dir;
560 if ((termination = method.next()))
562 const Eigen::Vector3f dir_rk3 (method.dir);
563 method.pos = init_pos + (dir_rk3 *
S.step_size);
564 method.dir = (dir_rk2 + dir_rk3).normalized();
565 if ((termination = method.next()))
567 const Eigen::Vector3f dir_rk4 (method.dir);
568 method.dir = (dir_rk1 + (dir_rk2 * 2.0) + (dir_rk3 * 2.0) + dir_rk4).normalized();
569 method.pos = init_pos + (method.dir *
S.step_size);
570 const Eigen::Vector3f final_pos (method.pos);
571 const Eigen::Vector3f final_dir (method.dir);
572 if ((termination = method.next()))
574 if (dir_rk1.dot (method.dir) <
S.cos_max_angle_ho)
576 method.pos = final_pos;
577 method.dir = final_dir;
#define ACT_BACKTRACK_ATTEMPTS
class to handle writing tracks to file, with RAM buffer
static Image open(const std::string &image_name, bool read_write_if_existing=false)
#define MAX_NUM_SEED_ATTEMPTS
#define TRACKING_BATCH_SIZE
constexpr T pow2(const T &v)
void check(const ImageType &H)
convenience function to check if an input image can contain SH coefficients
__Multi< typename std::remove_reference< Functor >::type > multi(Functor &&functor, size_t nthreads=threads_to_execute())
used to request multiple threads of the corresponding functor
void run_queue(Source &&source, const Item &item, Sink &&sink, size_t capacity=128)
convenience function to set up and run a 2-stage multi-threaded pipeline.
__Batch< Item > batch(const Item &, size_t number=128)
used to request batched processing of items
size_t determine_upsample_ratio(const Header &, const float, const float)
@ ACT_FAILED_WM_REQUIREMENT
@ NO_PROPAGATION_FROM_SEED
const uint8_t term_add_to_tck[13]
PointType::Scalar length(const vector< PointType > &tck)
std::string str(const T &value, int precision=0)
constexpr default_type NaN