Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
include_ordered for tckgen and tckedit #1238
For years I've been repeatedly frustrated by stray tracks looping when performing tractography.
There were always work arounds - additional exclusion ROIs, making assumptions about brain size and setting the max-length etc, but these were all very hack-ish and tended to be a bit of trouble when dealing with non-standard brains.
This pull request adds -include_ordered <image_path> to tckedit and tckgen. This parameter enforces these include regions to be passed through in a particular order.
For example, to track from A, to B, to C:
This can be combined with standard -include rois as needed. For example, to track from A, to B, to C and at any point pass through X:
This argument requires the -seed_unidirectional flag to be set, because bidirectional tracking does not have defined start and end points. If this flag is not set, an exception is thrown (just as with other checks).
To see this in action, you can find a sample script with accompanying fa/fod/ROIs here:
While building this, I couldn't find any unit testing framework in the code to check that what I had written actually works (?). I didn't want to go assuming which framework you wanted (or I missed) so I've written a very basic one from scratch which tests that the classes I've added. Please note that is purposefully does not use assert() because it's only set up to run tests in series: usually unit tests will continue to run even if one fails, but assert() prevents this. It's also nice to be able to run tests without re-configuring to DEBUG and rebuilding the entire project... I've tried to make this expandable for future additional tests, but ultimately it's probably much smarter to move to an standard established framework that integrates with builds etc.
Please note that existing tests for mrconvert, population_template and tckconvert do not pass but I suspect that has nothing to do with these changes.
My background is predominantly in C#. I ported mrtrix 2.12 tckgen to C# years ago for my PhD work, in which I implemented something very similar. For me, rewriting this functionality in C++ was like hammering in a nail with my forehead. Beyond the syntactical/ differences, C# has standardised code conventions that do not match those of this C++ codebase. I say this because, due to force of habit, I've probably broken a few of your conventions here and there - sorry about this. I tried to adhere to what I saw, but I've probably missed a few things. If you have a style enforcer (e.g. StyleCop) with your rules put into it, please let me know so I don't do this again!
There are probably warnings related to the code I've created but the g++ compiler on mingw spits out so many warnings like this:
...that I have no real hope of finding those which belong to me! The fact that the unit tests pass and behaviour of the executables matches what I'd expect is enough for me to feel confident that this works as advertised.
I have documented my code to a moderate degree. A pull request I will put in in some months time (different feature) will have comments for some of the existing tractography code as well. The lack of commenting in the existing code made penetrating it quite difficult for someone who didn't write it. I hope the comments I've added help others in the future.
Hi @LeeReidCSIRO, just a heads-up; completely apart from the contents of the pull request: when introducing features of the scale and impact of something like this, we typically create a pull request with the
That would be odd... in principle changes can't make it into either
@thijsdhollander Ok, would you like me to try to merge with dev branch and resubmit this?
My assumption about the tests may be proven wrong... I wasn't aware that they should always build in order to in the master branch. I just had no recollection of any of these having to rebuild when I changed the code. If it's my fault I'll try to sort.
I might not be able to go through this in detail for a little while (fellowship application
Small update here: the tests (currently still those from
Thanks for all the help guys. Working on rebasing now...
@Lestropie in answer to your query:
I see a few options here:
Something like option 3 is my preference, because it gives the flexibility that it has now, and means you can add additional attributes when you need new features later on. e.g.
Is there ever a need to be able to do both ordered and unordered? I don't currently have a need, personally. I put things the way they were because behaviour is undefined if two ordered rois overlap. It is undefined because re-entry is not allowed.
I'm not sure what the
Regarding implementation, if you have a peek at ROISet when you have time, you'll see that integrating
Ok, as always, I haven't fully thought this through (yet), but just throwing it out there before I forget:
You could make the ordering "constraint" on inclusion regions also available via an option
Using that latter flexibility you can come up with about any complex ordering, including repetition or omission (from the order constraint) of any inclusion region, that you can imagine; and specify it in a short and efficient manner (that could be scripted in lots of cool ways).
Also note that, in all of the above, the
Any of the
Just to comment on that in particular: it doesn't have to be like that, in principle? If re-entry is not allowed, you could still enter regions in order, right? E.g. if A and B overlap partially, you could still first enter A, and then further "down the track" enter B, either while still in A, or after exiting A.
I think the
Two concerns though. Firstly, if this syntax is to be applied to other input images things get confusing. e.g. in the following example:
which image does
Finally, a very minor thought: you may (??) find yourself inundated with "it doesn't work" messages because people started counting at 1, not 0, or vice versa.
You're right, in principle it could be like you say - so long as A is entered first it should be OK to be in A & B. The code may become a tad inefficient though - at the moment it's very lightweight. I'm not sure if this matters: Rob just recently has highlighted to me that performance of tckgen is a sensitive issue. I'm happy to rewrite how this works if your team is of the consensus that A-->A&B something that should be handled.
@LeeReidCSIRO: GitHub is currently showing this as coming from "unknown repository". Has your repo somehow moved / become private? It might be necessary to make a new PR if something has changed at your end.
On reflection I'm not as fussed on the
One thing I do want to have a look at (preferably in my code editor, hence needing to check the PR source) is the
@Lestropie. Massive face-palm. I had issues with my github account a month or so back and forgot that this pull request was still active. It got wiped both on github and locally. Github has still kept all the diffs, though... If we want changes, and you don't have a local copy, one option is for me to try to get these diffs from github and start a new pull request referencing this one. Another option is to pull it into a different branch of mrtrix and make edits there (though I lack rights). Sorry about this.
Naming: I am happy so long as you are
I've recovered the code but I can't link it back to this thread. https://github.com/LeeReidCSIRO/mrtrix3/tree/ordered_include. Would you like me to make this into a new pull request and close this one?
The example script public link expired. It can also now be found at https://cloudstor.aarnet.edu.au/plus/s/oingnHX61hcvZWC
All good; sorry it's taken me this long to get to it. Been hella hectic trying to extinguish spot fires and put together a workshop having lost 2 core devs.
That's probably best I think: will mean that the merge will appropriately reference your current fork, we can request / propose changes properly, etc.. Can still give a link to this PR in the description in order to link to prior discussions.
I'm not too concerned about the relative performance of the two approaches, it's more the logic of the code layout. At some point I will have to resolve this contribution against my suite of changes including differentiation between GM and WM ROIs, special handling of GM ROIs in the case of ACT, mesh ROIs, probably some other stuff I've done years ago and forgotten about. So I'm trying to keep each new capability as modular and independent as possible. But I'll need to spend some dedicated time looking at the code properly to decide whether or not there's a good justification one way or the other. I'd be curious to know @jdtournier's opinion on the possible code layout since it's his code.
Worth adding as its own issue; pretty sure we have open access for any GitHub account to create issues on our repo, other non-developers have done so in the past. Worst case scenario: someone tests it, they don't find anything, and we close the issue. Best case scenario: there's a problem, it gets fixed, and you get credit for having raised it. That way it'll be better documented, and there's a reminder there for yourself or anyone else to explicitly test it.