Dwipreproc & PhaseEncoding handling fixes#1047
Conversation
- When using the -rpe_all option in dwipreproc, paired volumes between the two halves of the acquisitino were not being correctly found. - When calling applytopup, it appears that in some cases it will combine reversed phase-encode volume pairs into a single volume each, even when requesting Jacobian modulation (it did not do this in my own testing); this change explicitly calls applytopup separately for each unique phase encoding setting, to ensure that no such combination takes place. - Many commands that convert DWI volumes into some other mathematical representation were retaining the phase encoding scheme in the output header, resulting in errors being thrown when the number of entries in the table did not match the number of volumes. - dwi2mask was additionally failing to stash the DW scheme, as the relevant function was being called upon a temporary Header instance rather than the output image.
Otherwise use of `-nocleanup` option will result in "File already exists" errors.
Resulted in error "str() object has no method fromUser()" or the like, since variable name "path" was defined and therefore hides the module.
|
OK, so I've successfully tested this with the case reported by the user (all DWIs acquired with reversed phase encoding, but with multiple b=0 volumes), using both |
|
Hadn't had the time to properly "review", but it sounds like it's all good, so I'll ok for the sake of the fix. Minor thing maybe (but I don't think this should hold back the fix in any way):
Any particular reason for not also stashing the PE scheme in a sort of analogous way to the DWI scheme? (or just no good reason to stash it?) Other non-urgent thing now that I think of it: with some of those soon upcoming changes as part of "RC2" happening any way... isn't it maybe about time to reconsider the name of this script while we're still beta enough? The name used to make sense, but is starting to become more and more confusing for new users, as we now also have denoising, maybe soon also unringing, and bias field correction. So this script isn't really "the" one and only preprocessing thing any more. Since the introduction of denoising it isn't even the first step any more. So I'd be eventually maybe thinking of a more specific name that communicates better what this command does (something that refers to distortion and motion somehow). |
thijsdhollander
left a comment
There was a problem hiding this comment.
Fix sounds all right, and I'm all for immediate action to fix things and have proper functioning and scientifically correct software in master asap.
Basically no good reason, weighed off against the awkwardness...
Come to think of it, I suppose 2 and 3 are still outstanding...
Not against it; though I'd maybe wait for release rather than an RC update, don't want to give people a reason to not update. |
|
^^ Don't actually effect |
Ah yes indeed, I hadn't appreciated that. Yes, you're right in that case: there's not really a clear definition of stuff any more, so stashing wouldn't really help (if anything maybe only cause confusion).
Not sure; I'd think if people can agree on a name, it's probably better to change sooner rather than later. |
|
About the renaming of |
|
I'm not too obsessed with its name, Anyway, bringing this up was more about thinking whether the script's name could be more specific and better reveal what it packs. What I think makes the current name a bit more annoying as time goes on, is the introduction of steps that should definitely precede So in conclusion: not overly fussed about it, but I think it's worthwhile to at least start thinking about this a bit, with the future (and a future with a release) somewhere in mind. |
|
Just reviewed the entire code change: as far as I can see, it all looks ok. The only bit I was unsure of is https://github.com/MRtrix3/mrtrix3/pull/1047/files#diff-71c549699e123065bef9ad55c9c01d3fR90 , because I hadn't ever seen an ellipsis in a catch statement like that before (there's another one in another file change part of the pull request as well that I'd spotted). Looked it up, and it seems to be all right, it seems the exception is still successfully being re-thrown in such a scenario as well. I don't have an appropriate dataset to test an I propose we leave the name debate for now; it's a separate thing to the original intentions here any way. I've got the feeling we're not all going to be happy with a name change, or certainly not now already. I'm ok with that. 👍 |
|
|
|
This is an example bit of where it goes wrong: |
|
I'm definitely not sure about this, but my guess would be that it has to do with this line: https://github.com/MRtrix3/mrtrix3/pull/1047/files#diff-8bd7800b444305a9a0153178f4a7ce15R352 |
That's the catch-all statement - perfectly legit C++. We tend not to use it and rely on catching our own exceptions, since anything unexpected should really not be unexpected - all possible errors should be handled by the code responsible, and thrown as a dedicated |
|
About renaming |
Huh, OK. I tend to use ellipsis, with the exception (ba-dum-tish) being those cases where I want to concatenate the exception message (which I'm trying to do increasingly: many forum questions have boiled down to exceptions thrown deep in the stack that users can't translate to their command invocation). That's the pattern I recognized having looked through others' code, anyway. If you'd rather have non- |
👍 No worries, that's fair enough. It would be good to keep an eye on it though, as time goes on. |
Inputs to std::map::erase() must be dereferenceable, which means that attempting to erase based on a string key that doesn't exist will result in an error. This had been used in a number of places, but testing had simply not yet raised the issue.
Fixed... At some point I saw this line and went "oh, you can erase map entries without checking for their existence!". Yeah, nah, you can't... 🙄 |
Proposed solutions to issue #1044.
There was a few issues here and there that I've had a go at; hopefully the core issues that were preventing execution as reported in this thread will be addressed.
eddyis currently refusing to complete on my system, so independent confirmation would be preferable.When determining matching volumes when the
-rpe_alloption is used, I suspect I was being optimistic at the time that it may be possible to handle interleaved phase-encoding acquisitions (e.g. b=0 A>>P, b=0 P>>A, b=3000 [0,0,1] A>>P, b=3000 [0,0,1] P>>A, ...) using this option. However as it stood, that wouldn't be possible since b=0 pairs would be found without any guarantee that the phase-encoding direction was opposing for those two particular volumes. Therefore it now searches for gradient direction matches specifically between the first and second halves of the data; if I want to support the aforementioned case, it will need to be detected and dealt with explicitly.Also a bug in the same area of code that was not appropriately dropping out of the loop once a match was found. The only test case I have only contains one b=0 volume, hence that got processed without issue.
It seems some versions of
applytopupperform volume combination whereas others don't (only way I can explain this code path having completed successfully in the past). So now runapplytopupseparately for each phase-encoding parameter set, and combine manually. Solution should be compatible with more complex acquisitions using the-rpe_headeroption.Commands that stash the DW scheme in order to prevent warnings / errors down the line also need to clear the phase-encoding scheme for the same reason.
TL;DR: I resent ever having created
dwipreproc. :-/