Skip to content
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

Fix trajectory scaling in KTrajectoryPulseq #551

Merged
merged 5 commits into from
Dec 9, 2024
Merged

Conversation

schuenke
Copy link
Collaborator

I came across a bug in the reshape_pulseq_traj function in our KTrajectoryPulseq class.

In KTrajectoryPulseq, we use seq.calculate_kspace() to get our k-space trajectory from the seq-file. Due to some rounding errors etc it happens that we get different kz values even for single 2D acquisitions. These values are usually about 10 orders of magnitude smaller compared to typical kx and ky values.

However, in the reshape_pulseq_traj function we rescale the values with encoding_size / (2 * torch.max(torch.abs(k_traj))), which can be in the order of 1e8 for very small kz values (caused by mentioned rounding errors). For encoding_size = 1, the resulting max value of kz after rescaling was always 0.5 and thus 2 orders of magnitude larger than our repeat_detection_tolerance, which is meant to compensate for the small rounding errors.

I actually don't understand why this hasn't been a problem in the past, but @fzimmermann89 and I are sure that the scaling for encoding_size = 1 is a bug, which should be fixed by this PR.

@schuenke schuenke requested a review from ckolbPTB November 20, 2024 16:45
Copy link
Contributor

github-actions bot commented Nov 20, 2024

Coverage

Coverage Report
FileStmtsMissCoverMissing
src/mrpro/algorithms/csm
   inati.py24196%44
   walsh.py16194%34
src/mrpro/algorithms/dcf
   dcf_voronoi.py53492%15, 48–49, 76
src/mrpro/algorithms/optimizers
   adam.py20195%69
src/mrpro/algorithms/reconstruction
   DirectReconstruction.py281643%51–71, 85
   IterativeSENSEReconstruction.py13192%76
   Reconstruction.py502256%42, 54–56, 80–87, 104–113
   RegularizedIterativeSENSEReconstruction.py411759%96–100, 114–139
src/mrpro/data
   AcqInfo.py128398%26, 169, 207
   CsmData.py29390%15, 82–84
   DcfData.py45882%18, 66, 78–83
   IData.py67987%119, 125, 129, 159–167
   IHeader.py75791%75, 109, 127–131
   KHeader.py1531789%25, 119–123, 150, 199, 210, 217–218, 221, 228, 260–271
   KNoise.py311552%39–52, 56–61
   KTrajectory.py69593%178–182
   MoveDataMixin.py1401887%15, 113, 129, 143–145, 207, 323–325, 338, 417, 437–438, 440, 455–456, 458
   QData.py39782%42, 65–73
   Rotation.py6743595%100, 198, 335, 433, 477, 495, 581, 583, 592, 626, 628, 691, 768, 773, 776, 791, 808, 813, 889, 1077, 1082, 1085, 1109, 1113, 1240, 1242, 1250–1251, 1315, 1397, 1690, 1846, 1881, 1885, 1996
   SpatialDimension.py2322191%34, 104, 141, 148, 154, 274–276, 289–291, 325, 343, 356, 369, 382, 395, 404–405, 420, 429
   acq_filters.py12192%47
src/mrpro/data/_kdata
   KData.py1341887%109–110, 125, 132, 142, 150, 204–205, 243, 248–249, 268–279
   KDataRemoveOsMixin.py29293%44, 46
   KDataSelectMixin.py19289%48, 63
   KDataSplitMixin.py48394%53, 84, 93
src/mrpro/data/traj_calculators
   KTrajectoryCalculator.py25292%23, 45
   KTrajectoryIsmrmrd.py13285%41, 50
   KTrajectoryPulseq.py31197%54
src/mrpro/operators
   CartesianSamplingOp.py89397%118, 157, 280
   ConstraintsOp.py60297%46, 48
   EndomorphOperator.py65297%228, 234
   FiniteDifferenceOp.py27293%40, 105
   FourierOp.py158398%263, 381, 386
   Functional.py71593%20–22, 117, 119
   GridSamplingOp.py136993%72–73, 82–83, 90–91, 94, 96, 98
   LinearOperator.py1681094%55, 91, 190, 220, 261, 270, 278, 287, 295, 320
   LinearOperatorMatrix.py1581690%82, 119, 152, 161, 166, 175–178, 191–194, 203, 215, 304, 331, 359
   MultiIdentityOp.py13285%43, 48
   Operator.py78297%25, 74
   ProximableFunctionalSeparableSum.py39392%50, 103, 110
   SliceProjectionOp.py173895%44, 61, 63, 69, 206, 227, 260, 300
   WaveletOp.py120596%152, 170, 205, 210, 233
   ZeroPadOp.py16194%30
src/mrpro/utils
   filters.py62297%44, 49
   slice_profiles.py46687%20, 36, 113–116, 149
   sliding_window.py34197%34
   split_idx.py10280%43, 47
   summarize_tensorvalues.py11918%20–29
   typing.py181139%8–23
   zero_pad_or_crop.py31681%26, 30, 54, 57, 60, 63
TOTAL487135293% 

Tests Skipped Failures Errors Time
2257 0 💤 0 ❌ 0 🔥 2m 7s ⏱️

Copy link
Contributor

github-actions bot commented Nov 20, 2024

📚 Documentation

📁 Download as zip
🔍 View online

@ckolbPTB
Copy link
Collaborator

I actually don't understand why this hasn't been a problem in the past

I guess for 2D trajectories it does not matter because the k2 dimension would then be singleton and we simply ignore it in the FourierOp. The only one using 3D pulseq-trajectories is probably @JoHa0811 - not sure if he encountered any problems.

@fzimmermann89
Copy link
Member

Patrick noticed the bug because the reconstruction did not work.
The kz points were not singleton, but some noise, scaled to -.5 ... .5.
So they are only considered singleton if you increase the detection tolerance to 0.5.
(which could also be a sensible default, if the biggest difference between k space points is less than 1, it surely is singleton)

The reconstruction should still have worked, in theory, but, we also have #553 , the fourier op does not work with recon matrix smaller 6.

@ckolbPTB
Copy link
Collaborator

Patrick noticed the bug because the reconstruction did not work.

For 2D acquisitions? Strange, because we also have pulseq reconstructions in our examples

@schuenke
Copy link
Collaborator Author

I actually don't understand why this hasn't been a problem in the past

I guess for 2D trajectories it does not matter because the k2 dimension would then be singleton and we simply ignore it in the FourierOp. The only one using 3D pulseq-trajectories is probably @JoHa0811 - not sure if he encountered any problems.

It was a 2D trajectory in my case, but the kz values after rescaling differed in the range [-0.3, 0.5] and thus much more than the default repeat_detection_tolerance resulting in final kdata.traj dimensions

kz=[  1,   1, 402,   1]
ky=[  1,   1, 402, 256]
kx=[  1,   1, 402, 256]

insted of kz = [1, 1, 1, 1].

This actually lead to errors in the reco.

@fzimmermann89
Copy link
Member

Patrick noticed the bug because the reconstruction did not work.

For 2D acquisitions? Strange, because we also have pulseq reconstructions in our examples

Indeed. I think it depends on the sequence if pypulseq returns 0 or something close to zero.
We should ask a pypulseq maintainer for input ;)

@fzimmermann89
Copy link
Member

Patrick noticed the bug because the reconstruction did not work.

For 2D acquisitions? Strange, because we also have pulseq reconstructions in our examples

Indeed. I think it depends on the sequence if pypulseq returns 0 or something close to zero. We should ask a pypulseq maintainer for input ;)

Ok, in the pulseq example, kz is constant (but not 0). This avoids the possible division by zero bug and results in a singleton dimension as all kz after scaling are -0.5 ...

@schuenke
Copy link
Collaborator Author

schuenke commented Dec 3, 2024

We still want to merge this? Or is it superseeded by #560?
IMHO it's not a good idea to combine a major refactoring like #560 with a bugfix like this...

@fzimmermann89 fzimmermann89 enabled auto-merge (squash) December 9, 2024 08:28
@fzimmermann89 fzimmermann89 merged commit b80141f into main Dec 9, 2024
20 checks passed
@fzimmermann89 fzimmermann89 deleted the fix_traj_pulseq branch December 9, 2024 08:31
@schuenke schuenke mentioned this pull request Dec 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants