Closed remy-abergel closed 4 months ago
Hi, thank you for your outstanding bug report!
ASPIRE recently underwent several changes intended to better match Relion. These were specifically in our projection/backprojection/rotation conventions and it is very possible that we overlooked this while attempting to match that test case.
I think both your cases are resolved by this line in backproject:
diff --git a/src/aspire/image/image.py b/src/aspire/image/image.py
index 81589b14..b0f45543 100644
--- a/src/aspire/image/image.py
+++ b/src/aspire/image/image.py
@@ -548,7 +548,7 @@ class Image:
)
pts_rot = pts_rot.reshape((3, -1))
- vol += anufft(im_f, pts_rot[::-1], (L, L, L), real=True)
+ vol += anufft(im_f, pts_rot, (L, L, L), real=True)
vol /= L
However, I'm going to pass this along to my colleague Josh who recently made the Relion convention updates. He may prefer that this change occurs in a different method or have preference as to how we should update the unit tests. We will follow up more next week.
Thank you again for your report; this was one of the best bug reports I've ever seen 🙏 .
Thank you for your reply and for these kind words.
From my side, fixing this bug solved many problems of non-converging optimization schemes (proximal algorithms, conjugate gradient,...).
I may have found another bug related to Image.backproject
(probably less critical though). I am going to report it in another thread.
Closed by #1110
Hi,
First of all, thank you very much for sharing and maintaining this library.
Bug description:
I am posting here because some numerical experiments have led me to check whether
Volume.project
andImage.backproject
are adjoint operations or not.To make short, I found out that the answer is no. Actually axis permutation is needed after calling
Image.backproject
in order to perform the adjoint operation of theVolume.project
operation.I provide below two different ways to check this statement. My apologies for the long post, I tried to be as precise and complete as possible.
To Reproduce:
In the following script, I considered a small 3D volume (
vol
) with shape(10,10,10)
and I simulated 15 projections from this volume, leading to a measurement vector (y
) with shape(15,10,10)
. Because of the small dimensions of the system, we are able to numerically evaluate a matrix representation (M
) with shape(1500,1000)
of the direct operator. Then, we can perform the back-projection using two different methods :1) using
y.backproject
;2) performing the matrix-vector multiplication of
M.transpose()
with a flattened representation ofy
(with shape(1500,)
).Comparing those two outputs yields significant differences.
Expected behavior:
If the
Volume.project
andImage.backproject
are adjoint operators, thenv1
should be the same asv2
(up to the machine epsilon), which is not the case here (we display below one slice of the back-projected volumes computed using the two methods 1) and 2) mentioned above) :On my laptop, I get 59% of relative difference between
v1
andv2
.When reverting the axes order of the back-projected volume
v1
(axis order(0,1,2)
is changed into(2,1,0)
) we obtain a back-projected volumev3
identical (up to machine epsilon) tov2
:On my laptop, the relative difference between
v2
andv3
is only $2.7\cdot 10^{-7}$ (and thus, close to the float32 machine epsilon).Numerical validation of the adjoint relation:
With the script below, we can check that the identity
is satisfied up to the float32 machine epsilon when axis permutation is performed after the back-projection operation (denoting by $A$ the direct projection operator and by $A^*$ its adjoint).
The above script yields relative errors close to the float32 machine epsilon. When replacing above
ADJOP
bywe can observe much larger relative errors (close to 1%).
Environment (please complete the following information):