Skip to content

tcksample: Permit 4D input image#2451

Open
Lestropie wants to merge 12 commits intodevfrom
tcksample_4d
Open

tcksample: Permit 4D input image#2451
Lestropie wants to merge 12 commits intodevfrom
tcksample_4d

Conversation

@Lestropie
Copy link
Copy Markdown
Member

Implemented for a specific project; listing here as draft for attribution to 3.1.0 milestone so that it doesn't get forgotten.

If some per-streamline statistic is to be computed, then it is possible to provide as input multiple images to be sampled from as a 4D volume series; the command uotput will then be a 2D matrix (one row per streamline, one column per metric) rather than a 1D vector (one scalar per streamline).
@Lestropie
Copy link
Copy Markdown
Member Author

Lestropie commented Feb 14, 2024

  • Add test data & CI test

@Lestropie Lestropie mentioned this pull request Jul 15, 2024
3 tasks
Implemented class inheritance structure such that code branches based on the fundamental contrast being sampled does not need to occur for each streamline.
@Lestropie Lestropie marked this pull request as ready for review September 16, 2025 09:21
@Lestropie
Copy link
Copy Markdown
Member Author

  • On merge, update dev branch and delete feature branch on test_data repo

github-actions[bot]

This comment was marked as outdated.

github-actions[bot]

This comment was marked as outdated.

Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 40. Check the log or trigger a new build to see more.

};

template <class Interp> class SamplerNonPrecise {
class SamplerBase {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: class 'SamplerBase' defines a non-default destructor and a copy constructor but does not define a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

class SamplerBase {
      ^

const stat_tck _statistic;
};

template <class Interp> class SamplerNonPreciseBase : public SamplerBase {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: class 'SamplerNonPreciseBase' defines a default destructor and a copy constructor but does not define a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

template <class Interp> class SamplerNonPreciseBase : public SamplerBase {
                              ^

SamplerNonPreciseBase(Image<value_type> &image, const contrast_type contrast, const stat_tck statistic)
: BaseType(contrast, statistic), interp(image) {}
SamplerNonPreciseBase(const SamplerNonPreciseBase &that) = default;
virtual ~SamplerNonPreciseBase() = default;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' [cppcoreguidelines-explicit-virtual-functions]

Suggested change
virtual ~SamplerNonPreciseBase() = default;
~SamplerNonPreciseBase() override = default;

}

protected:
Interp interp;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: member variable 'interp' has protected visibility [cppcoreguidelines-non-private-member-variables-in-classes]

  Interp interp;
         ^

};

class SamplerPrecise {
class SamplerPreciseBase : public SamplerBase {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: class 'SamplerPreciseBase' defines a default destructor and a copy constructor but does not define a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

class SamplerPreciseBase : public SamplerBase {
      ^

: ReceiverBase(num_tracks) {
using InputType = ManyPerStreamline;
Receiver_ManyPerStreamline(const size_t num_tracks, const size_t num_metrics, const std::string &path)
: ReceiverBase(num_tracks, false, path), data(matrix_type::Zero(num_tracks, num_metrics)) {}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: narrowing conversion from 'size_t' (aka 'unsigned long') to signed type 'Index' (aka 'long') is implementation-defined [bugprone-narrowing-conversions]

      : ReceiverBase(num_tracks, false, path), data(matrix_type::Zero(num_tracks, num_metrics)) {}
                                                                      ^

Receiver_ManyPerStreamline(const size_t num_tracks, const size_t num_metrics, const std::string &path)
: ReceiverBase(num_tracks, false, path), data(matrix_type::Zero(num_tracks, num_metrics)) {}
Receiver_ManyPerStreamline(const Receiver_ManyPerStreamline &) = delete;
~Receiver_ManyPerStreamline() { File::Matrix::save_matrix(data, path); }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: annotate this function with 'override' or (rarely) 'final' [cppcoreguidelines-explicit-virtual-functions]

Suggested change
~Receiver_ManyPerStreamline() { File::Matrix::save_matrix(data, path); }
~Receiver_ManyPerStreamline() override { File::Matrix::save_matrix(data, path); }

bool operator()(InputType &in) {
// TODO Chance that this will be prohibitively slow if count is not indicated in track file header
if (in.index >= size_t(data.rows()))
data.conservativeResizeLike(matrix_type::Zero(in.index + 1, data.cols()));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: narrowing conversion from 'size_t' (aka 'unsigned long') to signed type 'Index' (aka 'long') is implementation-defined [bugprone-narrowing-conversions]

      data.conservativeResizeLike(matrix_type::Zero(in.index + 1, data.cols()));
                                                    ^

// TODO Chance that this will be prohibitively slow if count is not indicated in track file header
if (in.index >= size_t(data.rows()))
data.conservativeResizeLike(matrix_type::Zero(in.index + 1, data.cols()));
data.row(in.index) = in.values;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: narrowing conversion from 'size_t' (aka 'unsigned long') to signed type 'Index' (aka 'long') is implementation-defined [bugprone-narrowing-conversions]

    data.row(in.index) = in.values;
             ^

matrix_type data;
};

class Receiver_PerVertex : public ReceiverBase {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: class 'Receiver_PerVertex' defines a copy constructor but does not define a destructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]

class Receiver_PerVertex : public ReceiverBase {
      ^

@Lestropie
Copy link
Copy Markdown
Member Author

Anyone with access to a Mac willing to help me look into the tcksample_inputsh_precise test? The CI is reporting a discrepancy of nearly 10%, which is rather extreme. I'm guessing that imprecisions with respect to the streamline-to-voxel mapping algorithm and the SH sampling are somehow stacking, but I wouldn't expect an error of that magnitude.

Add this at `cpp/cmd/tcksample.cpp:575:

    if (tck.get_index() == 112) {
      std::cerr << "Troublesome streamline 112:\n";
      std::cerr << "Intersections:\n";
      for (const auto &i : intersections)
        std::cerr << "  " << i.transpose() << ": " << i.get_length() << "\n";
      std::cerr << "Sampled data:\n";
      for (const auto &i : data)
        std::cerr << "  " << i.length << ": " << i.value << "\n";
      std::cerr << "Final result: " << out.value << "\n";
    }

Here's what my Linux box produces"

Troublesome streamline 112:
Intersections:
  0 4 3: 0.777862
  0 5 3: 1.80769
  0 4 4: 2.70528
  1 4 4: 0.363316
  2 3 5: 1.16057
  1 4 5: 3.05493
  2 4 5: 0.0803039
Sampled data:
  0.777862: -0.0445911
  1.80769: 0.360195
  2.70528: 0.129052
  0.363316: 0.324144
  1.16057: 0.239748
  3.05493: 0.429606
  0.0803039: 0.0256022
Final result: 0.26895

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants