-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Take NonUniformFastFourierOp out of FourierOp #463
base: main
Are you sure you want to change the base?
Conversation
📚 Documentation |
Mid-term, I would still really like to decouple us from torchkbnufft and have a NufftOperator option in the FourierOperator, Also, long-term, I would like to fix the axes sorting code, such that for example a RPE with fft direction along k1 and kz works, i.e. a mismatch in the order of the axes. |
If not to difficult, yes. Or at least allow both, KTrajectory and tensor inputs.
In case cartesian fft removes stuff? Does it matter? |
Co-authored-by: Felix F Zimmermann <[email protected]>
FFT and NUFFT always act on separate dimensions so it does not matter if FFT changes stuff. Only case where it matters would be if the non-uniform trajectory changes along a uniform dimension. But the NUFFT acts along the original k-space uniform dimension so this should be fine. |
For this or another PR: |
@fzimmermann89 I added a test to verify against the analytic solution. Is this what you had in mind? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing with analytical solution is even better!
Final remarks:
I would remove .forward from the operator calls.
It should generally be call that is called on pytorch modules (which all our operator are) as you can in general set global debugging hooks that only work in that case.
I think we should not give a bad example here.
We could either set fast_fourier_op and nufft op always, just with empty dims, or set them to identity op (which we didn't have when we wrote this)
I am wondering why mypy is not complaining about them possibly being None (or I missed something).
""" | ||
super().__init__() | ||
|
||
def get_traj(traj: KTrajectory, dims: Sequence[int]): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now that the NufftOp can be created separately, there are some cases not handled:
What if dim is empty?
What if dim contains invalid axes?
What if dim contains positive axes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say dim is empty, the operator should do nothing.
We should add that dim talks about kx ky kz and not k0 k1 k2 here.
So maybe not dim bit direction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, what about fastfourierop with empty dim?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say dim is empty, the operator should do nothing.
added
also, what about fastfourierop with empty dim?
should be fixed in separate PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if dim contains invalid axes?
What if dim contains positive axes?
We could transform them to negative axes based on the dimensions of traj and then verify the result is within (-3,-2,-1)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we have a similar problem with your FFTOp where we also assume that kz ky kx and k2 k1 k0 align, i.e. if I set dim = -1 then I expect to carry out the FFT along k0 with the parameters of (k)x.
We could either say that FFTOp and NUFFTOp work in k2 k1 k0 space and we have to provide matrix sizes and trajectory and so on in this space. Then we could do the magic of figuring all this out in the FourierOp. This would leave the FFTOp to be more intuitive but would mean that for the NUFFTOp users would have to figure out the traj by themselves.
Other option would be to provide dim_kzkykx and dim_k2k1k0 to both operators which would make FFTOp less intuitive but mean that NUFFTOp could get the original trajectory as input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see basically the same two options here :
-
nuffOp gets data and omega in shape (batch_different_traj, batch_same_traj, samples), all reshaping is done in FourierOp.
-
NufftOp to gets 'x','y','z' as a
direction
argument. We transform it any ways always to x,y,z where we use it.
This would mean a minimal change to the code. Nufft does not need dim_k2k1k0 at all.
(Midterm, it would be nice to support in FourierOp also RPE with read-out in z direction, but saved in k0. For this, FFTOp would need both dim and direction. But as I said, this is IMHO a separate piece of work for the future)
Not really sure which I prefer, I think a bit the second for know, as it is easier to implement and switch to the first one if it required later on without losing work. Am I missing substantial downsides of the second option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Nufft and Fft need k2 k1 k0 because we need to know which dimensions of kdata to combine to samples and which to use as batch. currently we assume this is the same as kz ky kx and hence do the rearrange of kdata in forward/adjoint using nufft_dims which is in kz ky kx space although we are actually rearranging k2 k1 k0 dimensions.
I would prefer it if FftOp and NufftOp used a similar interface. This I think would be much easier to understand by users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so option two would be to provide direction Literal['x', 'y', 'z',-3,-2,-1] and dim Literal[-3,-2,-1,'k0,'k1',k2'] to nufft.
FFTOp would still only get dim:int. Maye at some point we can add direction here as well to support the mixed case.
Option one is still all reshaping in FourierOp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit more work on this topic:
Now nufft_directions:Sequence[Literal['x', 'y', 'z',-3,-2,-1]]
is provided by the user to define along which directions the nufft should be performed. Based on this ky, kx and kz are selected for Nufft. In a second step it is checked which k0, k1, k2 dimensions ky, kx and kz define (nufft_dims
). These are then automatically selected.
In the forward and adjoint this means that the image is permuted/reshaped based on nufft_directions
, the k-space trajectory and k-space data based on nufft_dims
.
This means users don't have to worry about k2-k1-k0-space but can define everything in x-y-z/kx-ky-kz-space.
It also means that
support in FourierOp also RPE with read-out in z direction, but saved in k0
also works now.
The interface is also now more similar to FFT where we either allow SpatialDimension or Sequence[int] for the recon and encoding matrix.
is the misalignment k210 and kzyx still a problem ? regarding review, let me know if i should have another look at this. |
Still to do: