1use crate::inversion::admm::{fansi_magnitude_weight, fansi_ppm_to_rad, fansi_unit_ee2, prepare_fansi_kernel, FansiKernel};
82use crate::utils::gradient::{bdiv_inplace, fgrad_inplace};
83use crate::utils::{apply_mask_zero, shrink};
84use crate::{EchoTime, Grid};
85use num_complex::Complex64;
86use std::f64::consts::PI;
87
88#[cfg_attr(feature = "introspection", derive(serde::Serialize))]
90#[derive(Clone, Debug)]
91pub struct FansiParams {
92 pub alpha1: f64,
94 pub mu1: Option<f64>,
96 pub mu2: f64,
98 pub alpha0: Option<f64>,
101 pub mu0: Option<f64>,
103 pub max_iter: usize,
105 pub tol_update: f64,
107 pub tol_delta: f64,
109 pub b0: f64,
111 pub echo_times: Vec<f64>,
114 pub te: EchoTime,
129 pub is_tgv: bool,
131 pub kernel: FansiKernel,
135}
136
137impl Default for FansiParams {
138 fn default() -> Self {
139 Self {
140 alpha1: 2e-4,
141 mu1: None,
142 mu2: 1.0,
143 alpha0: None,
144 mu0: None,
145 max_iter: 150,
146 tol_update: 0.1,
147 tol_delta: 1e-6,
148 b0: 3.0,
149 echo_times: vec![0.02],
150 te: EchoTime::Spacing,
151 is_tgv: false,
152 kernel: FansiKernel::Discrete,
153 }
154 }
155}
156
157impl FansiParams {
158 fn mu1(&self) -> f64 {
159 self.mu1.unwrap_or(100.0 * self.alpha1)
160 }
161}
162
163fn phase_and_weight(
165 local_field: &[f64],
166 mask: &[u8],
167 magnitude: &[f64],
168 params: &FansiParams,
169) -> (f64, Vec<f64>, Vec<f64>) {
170 let ppm_to_rad = fansi_ppm_to_rad(params.b0, params.te.seconds(¶ms.echo_times, "FANSI"));
171 let phase = local_field.iter().map(|&f| f * ppm_to_rad).collect();
172 let w = fansi_magnitude_weight(mask, magnitude).into_iter().map(|v| v * v).collect();
173 (ppm_to_rad, phase, w)
174}
175
176fn norm2(v: &[f64]) -> f64 {
178 v.iter().map(|&a| a * a).sum::<f64>().sqrt()
179}
180
181pub fn fansi(
195 local_field: &[f64],
196 mask: &[u8],
197 magnitude: &[f64],
198 grid: &Grid,
199 bdir: (f64, f64, f64),
200 params: &FansiParams,
201 progress: impl FnMut(usize, usize),
202) -> Vec<f64> {
203 if params.is_tgv {
204 nltgv(local_field, mask, magnitude, grid, bdir, params, progress)
205 } else {
206 nltv(local_field, mask, magnitude, grid, bdir, params, progress)
207 }
208}
209
210fn nltv(
212 local_field: &[f64],
213 mask: &[u8],
214 magnitude: &[f64],
215 grid: &Grid,
216 bdir: (f64, f64, f64),
217 params: &FansiParams,
218 mut progress: impl FnMut(usize, usize),
219) -> Vec<f64> {
220 let n = grid.n_total();
221
222 let (mut fft_ws, k) = prepare_fansi_kernel(grid, bdir, params.kernel);
223 let ee2 = fansi_unit_ee2(grid.dims);
225 let ugrid = Grid::new(grid.nx(), grid.ny(), grid.nz(), 1.0, 1.0, 1.0);
226 let grid = &ugrid;
227
228 let (ppm_to_rad, phase, w) = phase_and_weight(local_field, mask, magnitude, params);
229
230 let mu1 = params.mu1();
231 let mu2 = params.mu2;
232 let alpha_over_mu = params.alpha1 / mu1;
233
234 let mut x = vec![0.0f64; n];
236 let mut x_prev = vec![0.0f64; n];
237
238 let mut z_dx = vec![0.0f64; n];
240 let mut z_dy = vec![0.0f64; n];
241 let mut z_dz = vec![0.0f64; n];
242 let mut s_dx = vec![0.0f64; n];
243 let mut s_dy = vec![0.0f64; n];
244 let mut s_dz = vec![0.0f64; n];
245
246 let mut z2 = vec![0.0f64; n];
248 for i in 0..n {
249 let den = w[i] + mu2;
250 z2[i] = if den != 0.0 { w[i] * phase[i] / den } else { 0.0 };
251 }
252 let mut s2 = vec![0.0f64; n];
253
254 let mut fdiv = vec![Complex64::new(0.0, 0.0); n];
256 let mut fd2 = vec![Complex64::new(0.0, 0.0); n];
257 let mut xhat = vec![Complex64::new(0.0, 0.0); n];
258 let mut fx = vec![Complex64::new(0.0, 0.0); n];
259
260 let mut gxc = vec![0.0f64; n];
261 let mut gyc = vec![0.0f64; n];
262 let mut gzc = vec![0.0f64; n];
263 let mut x_dx = vec![0.0f64; n];
264 let mut x_dy = vec![0.0f64; n];
265 let mut x_dz = vec![0.0f64; n];
266 let mut div = vec![0.0f64; n];
267 let mut dx = vec![0.0f64; n]; let mut rhs_z2 = vec![0.0f64; n];
269 let mut diff = vec![0.0f64; n];
270 let mut update = vec![0.0f64; n];
271
272 for t in 0..params.max_iter {
273 progress(t + 1, params.max_iter);
274
275 for i in 0..n {
278 gxc[i] = z_dx[i] - s_dx[i];
279 gyc[i] = z_dy[i] - s_dy[i];
280 gzc[i] = z_dz[i] - s_dz[i];
281 }
282 bdiv_inplace(&mut div, &gxc, &gyc, &gzc, grid);
283 for i in 0..n {
284 fdiv[i] = Complex64::new(div[i], 0.0);
285 }
286 fft_ws.fft3d(&mut fdiv);
287
288 for i in 0..n {
290 fd2[i] = Complex64::new(z2[i] - s2[i], 0.0);
291 }
292 fft_ws.fft3d(&mut fd2);
293
294 for i in 0..n {
295 let num = -mu1 * fdiv[i] + mu2 * k[i] * fd2[i];
302 let den = mu2 * k[i] * k[i] + mu1 * ee2[i];
303 xhat[i] = if den > 1e-20 { num / den } else { Complex64::new(0.0, 0.0) };
308 }
309 fft_ws.ifft3d(&mut xhat);
310 x_prev.copy_from_slice(&x);
311 for i in 0..n {
312 x[i] = xhat[i].re;
313 }
314
315 for i in 0..n {
318 diff[i] = x[i] - x_prev[i];
319 }
320 let x_update = 100.0 * norm2(&diff) / norm2(&x);
321 if x_update < params.tol_update || x_update.is_nan() {
322 progress(t + 1, t + 1);
323 break;
324 }
325
326 if t + 1 >= params.max_iter {
327 break;
328 }
329
330 for i in 0..n {
333 fx[i] = Complex64::new(x[i], 0.0);
334 }
335 fft_ws.fft3d(&mut fx);
336
337 fgrad_inplace(&mut x_dx, &mut x_dy, &mut x_dz, &x, grid);
338 for i in 0..n {
339 z_dx[i] = shrink(x_dx[i] + s_dx[i], alpha_over_mu);
340 z_dy[i] = shrink(x_dy[i] + s_dy[i], alpha_over_mu);
341 z_dz[i] = shrink(x_dz[i] + s_dz[i], alpha_over_mu);
342 s_dx[i] += x_dx[i] - z_dx[i];
343 s_dy[i] += x_dy[i] - z_dy[i];
344 s_dz[i] += x_dz[i] - z_dz[i];
345 }
346
347 for i in 0..n {
350 xhat[i] = fx[i] * k[i];
351 }
352 fft_ws.ifft3d(&mut xhat);
353 for i in 0..n {
354 dx[i] = xhat[i].re;
355 rhs_z2[i] = mu2 * (dx[i] + s2[i]);
356 z2[i] = rhs_z2[i] / mu2;
357 }
358
359 let mut delta = f64::INFINITY;
360 let mut inn = 0usize;
361 while delta > params.tol_delta && inn < 10 {
362 inn += 1;
363 let norm_old = norm2(&z2);
364 for i in 0..n {
365 let a = z2[i] - phase[i];
366 let numer = w[i] * a.sin() + mu2 * z2[i] - rhs_z2[i];
367 let denom = w[i] * a.cos() + mu2;
368 update[i] = numer / denom;
369 z2[i] -= update[i];
370 }
371 delta = if norm_old > 0.0 {
372 norm2(&update) / norm_old
373 } else {
374 0.0
375 };
376 }
377
378 for i in 0..n {
381 s2[i] += dx[i] - z2[i];
382 }
383 }
384
385 for v in &mut x {
387 *v /= ppm_to_rad;
388 }
389
390 apply_mask_zero(&mut x, mask);
391 x
392}
393
394#[inline]
396fn spectral_mul_assign(dst: &mut [Complex64], m: &[Complex64]) {
397 for (d, &mm) in dst.iter_mut().zip(m.iter()) {
398 *d *= mm;
399 }
400}
401
402#[allow(clippy::too_many_lines)]
408fn nltgv(
409 local_field: &[f64],
410 mask: &[u8],
411 magnitude: &[f64],
412 grid: &Grid,
413 bdir: (f64, f64, f64),
414 params: &FansiParams,
415 mut progress: impl FnMut(usize, usize),
416) -> Vec<f64> {
417 let n = grid.n_total();
418 let (nx, ny, nz) = (grid.nx(), grid.ny(), grid.nz());
419
420 let (mut fft_ws, k) = prepare_fansi_kernel(grid, bdir, params.kernel);
421
422 let mut e1 = vec![Complex64::new(0.0, 0.0); n];
424 let mut e2 = vec![Complex64::new(0.0, 0.0); n];
425 let mut e3 = vec![Complex64::new(0.0, 0.0); n];
426 let two_pi = 2.0 * PI;
427 for kk in 0..nz {
428 let ez = Complex64::new(0.0, 1.0) * (two_pi * (kk as f64) / (nz as f64));
429 let e3v = Complex64::new(1.0, 0.0) - ez.exp();
430 for jj in 0..ny {
431 let ey = Complex64::new(0.0, 1.0) * (two_pi * (jj as f64) / (ny as f64));
432 let e2v = Complex64::new(1.0, 0.0) - ey.exp();
433 for ii in 0..nx {
434 let ex = Complex64::new(0.0, 1.0) * (two_pi * (ii as f64) / (nx as f64));
435 let e1v = Complex64::new(1.0, 0.0) - ex.exp();
436 let idx = ii + jj * nx + kk * nx * ny;
437 e1[idx] = e1v;
438 e2[idx] = e2v;
439 e3[idx] = e3v;
440 }
441 }
442 }
443
444 let (ppm_to_rad, phase, w) = phase_and_weight(local_field, mask, magnitude, params);
445
446 let mu1 = params.mu1();
447 let mu0 = params.mu0.unwrap_or(2.0 * mu1);
448 let alpha0 = params.alpha0.unwrap_or(2.0 * params.alpha1);
449 let mu2 = params.mu2;
450
451 let mut d11 = vec![Complex64::new(0.0, 0.0); n];
453 let mut d21 = d11.clone();
454 let mut d31 = d11.clone();
455 let mut d41 = d11.clone();
456 let mut d12 = d11.clone();
457 let mut d22 = d11.clone();
458 let mut d32 = d11.clone();
459 let mut d42 = d11.clone();
460 let mut d13 = d11.clone();
461 let mut d23 = d11.clone();
462 let mut d33 = d11.clone();
463 let mut d43 = d11.clone();
464 let mut d14 = d11.clone();
465 let mut d24 = d11.clone();
466 let mut d34 = d11.clone();
467 let mut d44 = d11.clone();
468 let mut det_ainv = d11.clone();
469
470 let half = 0.5;
471 for i in 0..n {
472 let e1i = e1[i];
473 let e2i = e2[i];
474 let e3i = e3[i];
475 let et1 = e1i.conj();
476 let et2 = e2i.conj();
477 let et3 = e3i.conj();
478
479 let e1te1 = et1 * e1i;
480 let e2te2 = et2 * e2i;
481 let e3te3 = et3 * e3i;
482 let mu0h_e1te2 = (mu0 * half) * et1 * e2i;
483 let mu0h_e1te3 = (mu0 * half) * et1 * e3i;
484 let mu0h_e2te3 = (mu0 * half) * et2 * e3i;
485
486 let a0 = Complex64::new(mu2 * k[i] * k[i], 0.0);
488 let a1 = a0 + mu1 * (e1te1 + e2te2 + e3te3);
489 let a2 = Complex64::new(mu1, 0.0) + mu0 * (e1te1 + (e2te2 + e3te3) * half);
490 let a3 = Complex64::new(mu1, 0.0) + mu0 * (e1te1 * half + e2te2 + e3te3 * half);
491 let a4 = Complex64::new(mu1, 0.0) + mu0 * ((e1te1 + e2te2) * half + e3te3);
492 let a5 = -mu1 * e1i;
493 let a6 = -mu1 * e2i;
494 let a7 = mu0h_e1te2;
495 let a8 = -mu1 * e3i;
496 let a9 = mu0h_e1te3;
497 let a10 = mu0h_e2te3;
498 let a5t = a5.conj();
499 let a6t = a6.conj();
500 let a7t = a7.conj();
501 let a8t = a8.conj();
502 let a9t = a9.conj();
503 let a10t = a10.conj();
504
505 let c11 = a2 * a3 * a4 + a7t * a9 * a10t + a7 * a9t * a10
506 - a3 * a9 * a9t
507 - a2 * a10 * a10t
508 - a4 * a7 * a7t;
509 let c21 = a3 * a4 * a5t + a6t * a9 * a10t + a7 * a8t * a10
510 - a3 * a8t * a9
511 - a5t * a10 * a10t
512 - a4 * a6t * a7;
513 let c31 = a4 * a5t * a7t + a6t * a9 * a9t + a2 * a8t * a10
514 - a7t * a8t * a9
515 - a5t * a9t * a10
516 - a2 * a4 * a6t;
517 let c41 = a5t * a7t * a10t + a6t * a7 * a9t + a2 * a3 * a8t
518 - a7 * a7t * a8t
519 - a3 * a5t * a9t
520 - a2 * a6t * a10t;
521 let c12 = a3 * a4 * a5 + a7t * a8 * a10t + a6 * a9t * a10
522 - a3 * a8 * a9t
523 - a5 * a10 * a10t
524 - a4 * a6 * a7t;
525 let c22 = a1 * a3 * a4 + a6t * a8 * a10t + a6 * a8t * a10
526 - a3 * a8 * a8t
527 - a1 * a10 * a10t
528 - a4 * a6 * a6t;
529 let c32 = a1 * a4 * a7t + a6t * a8 * a9t + a5 * a8t * a10
530 - a7t * a8 * a8t
531 - a1 * a9t * a10
532 - a4 * a5 * a6t;
533 let c42 = a1 * a7t * a10t + a6 * a6t * a9t + a3 * a5 * a8t
534 - a6 * a7t * a8t
535 - a1 * a3 * a9t
536 - a5 * a6t * a10t;
537 let c13 = a4 * a5 * a7 + a2 * a8 * a10t + a6 * a9 * a9t
538 - a7 * a8 * a9t
539 - a5 * a9 * a10t
540 - a2 * a4 * a6;
541 let c23 = a1 * a4 * a7 + a5t * a8 * a10t + a6 * a8t * a9
542 - a7 * a8 * a8t
543 - a1 * a9 * a10t
544 - a4 * a5t * a6;
545 let c33 = a1 * a2 * a4 + a5t * a8 * a9t + a5 * a8t * a9
546 - a2 * a8 * a8t
547 - a1 * a9 * a9t
548 - a4 * a5 * a5t;
549 let c43 = a1 * a2 * a10t + a5t * a6 * a9t + a5 * a7 * a8t
550 - a2 * a6 * a8t
551 - a1 * a7 * a9t
552 - a5 * a5t * a10t;
553 let c14 = a5 * a7 * a10 + a2 * a3 * a8 + a6 * a7t * a9
554 - a7 * a7t * a8
555 - a3 * a5 * a9
556 - a2 * a6 * a10;
557 let c24 = a1 * a7 * a10 + a3 * a5t * a8 + a6 * a6t * a9
558 - a6t * a7 * a8
559 - a1 * a3 * a9
560 - a5t * a6 * a10;
561 let c34 = a1 * a2 * a10 + a5t * a7t * a8 + a5 * a6t * a9
562 - a2 * a6t * a8
563 - a1 * a7t * a9
564 - a5 * a5t * a10;
565 let c44 = a1 * a2 * a3 + a5t * a6 * a7t + a5 * a6t * a7
566 - a2 * a6 * a6t
567 - a1 * a7 * a7t
568 - a3 * a5 * a5t;
569
570 let det_a = a1 * c11 - a5 * c21 + a6 * c31 - a8 * c41;
571
572 d11[i] = c11;
573 d21[i] = c21;
574 d31[i] = c31;
575 d41[i] = c41;
576 d12[i] = c12;
577 d22[i] = c22;
578 d32[i] = c32;
579 d42[i] = c42;
580 d13[i] = c13;
581 d23[i] = c23;
582 d33[i] = c33;
583 d43[i] = c43;
584 d14[i] = c14;
585 d24[i] = c24;
586 d34[i] = c34;
587 d44[i] = c44;
588 det_ainv[i] = if det_a.norm() > 1e-20 {
592 Complex64::new(1.0, 0.0) / det_a
593 } else {
594 Complex64::new(0.0, 0.0)
595 };
596 }
597
598 let et1: Vec<Complex64> = e1.iter().map(|c| c.conj()).collect();
600 let et2: Vec<Complex64> = e2.iter().map(|c| c.conj()).collect();
601 let et3: Vec<Complex64> = e3.iter().map(|c| c.conj()).collect();
602
603 let mut x = vec![0.0f64; n];
605 let mut x_prev = vec![0.0f64; n];
606 let mut v1 = vec![0.0f64; n];
607 let mut v2 = vec![0.0f64; n];
608 let mut v3 = vec![0.0f64; n];
609
610 let mut z1_1 = vec![0.0f64; n];
612 let mut z1_2 = vec![0.0f64; n];
613 let mut z1_3 = vec![0.0f64; n];
614 let mut s1_1 = vec![0.0f64; n];
615 let mut s1_2 = vec![0.0f64; n];
616 let mut s1_3 = vec![0.0f64; n];
617
618 let mut z0_1 = vec![0.0f64; n];
620 let mut z0_2 = vec![0.0f64; n];
621 let mut z0_3 = vec![0.0f64; n];
622 let mut z0_4 = vec![0.0f64; n];
623 let mut z0_5 = vec![0.0f64; n];
624 let mut z0_6 = vec![0.0f64; n];
625 let mut s0_1 = vec![0.0f64; n];
626 let mut s0_2 = vec![0.0f64; n];
627 let mut s0_3 = vec![0.0f64; n];
628 let mut s0_4 = vec![0.0f64; n];
629 let mut s0_5 = vec![0.0f64; n];
630 let mut s0_6 = vec![0.0f64; n];
631
632 let mut z2 = vec![0.0f64; n];
634 for i in 0..n {
635 let den = w[i] + mu2;
636 z2[i] = if den != 0.0 { w[i] * phase[i] / den } else { 0.0 };
637 }
638 let mut s2 = vec![0.0f64; n];
639
640 let alpha1_over_mu1 = params.alpha1 / mu1;
641 let alpha0_over_mu0 = alpha0 / mu0;
642
643 let mut rhs1 = vec![Complex64::new(0.0, 0.0); n];
645 let mut rhs2 = rhs1.clone();
646 let mut rhs3 = rhs1.clone();
647 let mut rhs4 = rhs1.clone();
648 let mut t1 = rhs1.clone();
649 let mut t2 = rhs1.clone();
650 let mut t3 = rhs1.clone();
651 let mut fx = rhs1.clone();
652 let mut fv1 = rhs1.clone();
653 let mut fv2 = rhs1.clone();
654 let mut fv3 = rhs1.clone();
655 let mut cbuf = rhs1.clone();
656
657 let mut dx1 = vec![0.0f64; n];
658 let mut dx2 = vec![0.0f64; n];
659 let mut dx3 = vec![0.0f64; n];
660 let mut ev1 = vec![0.0f64; n];
661 let mut ev2 = vec![0.0f64; n];
662 let mut ev3 = vec![0.0f64; n];
663 let mut ev4 = vec![0.0f64; n];
664 let mut ev5 = vec![0.0f64; n];
665 let mut ev6 = vec![0.0f64; n];
666 let mut dx = vec![0.0f64; n];
667 let mut rhs_z2 = vec![0.0f64; n];
668 let mut diff = vec![0.0f64; n];
669 let mut update = vec![0.0f64; n];
670
671 let mut rbuf = vec![0.0f64; n];
673
674 macro_rules! fft_real {
676 ($dst:expr, $src:expr) => {{
677 for i in 0..n {
678 $dst[i] = Complex64::new($src[i], 0.0);
679 }
680 fft_ws.fft3d(&mut $dst);
681 }};
682 }
683 macro_rules! fft_real_diff {
685 ($dst:expr, $a:expr, $b:expr) => {{
686 for i in 0..n {
687 rbuf[i] = $a[i] - $b[i];
688 }
689 fft_real!($dst, rbuf);
690 }};
691 }
692
693 for t in 0..params.max_iter {
694 progress(t + 1, params.max_iter);
695
696 for i in 0..n {
699 cbuf[i] = Complex64::new(z2[i] - s2[i], 0.0);
700 }
701 fft_ws.fft3d(&mut cbuf);
702 for i in 0..n {
703 rhs1[i] = mu2 * k[i] * cbuf[i];
704 }
705 fft_real_diff!(t1, z1_1, s1_1);
706 fft_real_diff!(t2, z1_2, s1_2);
707 fft_real_diff!(t3, z1_3, s1_3);
708 for i in 0..n {
709 rhs1[i] += mu1 * (et1[i] * t1[i] + et2[i] * t2[i] + et3[i] * t3[i]);
710 }
711
712 for i in 0..n {
715 rhs2[i] = -mu1 * t1[i];
716 rhs3[i] = -mu1 * t2[i];
717 rhs4[i] = -mu1 * t3[i];
718 }
719 fft_real_diff!(t1, z0_1, s0_1);
721 fft_real_diff!(t2, z0_4, s0_4);
722 fft_real_diff!(t3, z0_5, s0_5);
723 for i in 0..n {
724 rhs2[i] += mu0 * (et1[i] * t1[i] + et2[i] * t2[i] + et3[i] * t3[i]);
725 }
726 fft_real_diff!(t1, z0_2, s0_2);
728 fft_real_diff!(t2, z0_4, s0_4);
729 fft_real_diff!(t3, z0_6, s0_6);
730 for i in 0..n {
731 rhs3[i] += mu0 * (et2[i] * t1[i] + et1[i] * t2[i] + et3[i] * t3[i]);
732 }
733 fft_real_diff!(t1, z0_3, s0_3);
735 fft_real_diff!(t2, z0_5, s0_5);
736 fft_real_diff!(t3, z0_6, s0_6);
737 for i in 0..n {
738 rhs4[i] += mu0 * (et3[i] * t1[i] + et1[i] * t2[i] + et2[i] * t3[i]);
739 }
740
741 for i in 0..n {
743 let r1 = rhs1[i];
744 let r2 = rhs2[i];
745 let r3 = rhs3[i];
746 let r4 = rhs4[i];
747 let da = det_ainv[i];
748 fx[i] = (r1 * d11[i] - r2 * d21[i] + r3 * d31[i] - r4 * d41[i]) * da;
749 fv1[i] = (-r1 * d12[i] + r2 * d22[i] - r3 * d32[i] + r4 * d42[i]) * da;
750 fv2[i] = (r1 * d13[i] - r2 * d23[i] + r3 * d33[i] - r4 * d43[i]) * da;
751 fv3[i] = (-r1 * d14[i] + r2 * d24[i] - r3 * d34[i] + r4 * d44[i]) * da;
752 }
753 t1.copy_from_slice(&fx);
756 fft_ws.ifft3d(&mut t1);
757 x_prev.copy_from_slice(&x);
758 for i in 0..n {
759 x[i] = t1[i].re;
760 }
761 t1.copy_from_slice(&fv1);
762 fft_ws.ifft3d(&mut t1);
763 for i in 0..n {
764 v1[i] = t1[i].re;
765 }
766 t1.copy_from_slice(&fv2);
767 fft_ws.ifft3d(&mut t1);
768 for i in 0..n {
769 v2[i] = t1[i].re;
770 }
771 t1.copy_from_slice(&fv3);
772 fft_ws.ifft3d(&mut t1);
773 for i in 0..n {
774 v3[i] = t1[i].re;
775 }
776
777 let xnorm = norm2(&x);
779 if xnorm > 0.0 {
780 for i in 0..n {
781 diff[i] = x[i] - x_prev[i];
782 }
783 let x_update = 100.0 * norm2(&diff) / xnorm;
784 if x_update < params.tol_update || x_update.is_nan() {
785 progress(t + 1, t + 1);
786 break;
787 }
788 }
789
790 if t + 1 >= params.max_iter {
791 break;
792 }
793
794 fft_real!(fx, x);
796 fft_real!(fv1, v1);
797 fft_real!(fv2, v2);
798 fft_real!(fv3, v3);
799
800 cbuf.copy_from_slice(&fx);
802 spectral_mul_assign(&mut cbuf, &e1);
803 fft_ws.ifft3d(&mut cbuf);
804 for i in 0..n {
805 dx1[i] = cbuf[i].re;
806 }
807 cbuf.copy_from_slice(&fx);
808 spectral_mul_assign(&mut cbuf, &e2);
809 fft_ws.ifft3d(&mut cbuf);
810 for i in 0..n {
811 dx2[i] = cbuf[i].re;
812 }
813 cbuf.copy_from_slice(&fx);
814 spectral_mul_assign(&mut cbuf, &e3);
815 fft_ws.ifft3d(&mut cbuf);
816 for i in 0..n {
817 dx3[i] = cbuf[i].re;
818 }
819
820 cbuf.copy_from_slice(&fv1);
822 spectral_mul_assign(&mut cbuf, &e1);
823 fft_ws.ifft3d(&mut cbuf);
824 for i in 0..n {
825 ev1[i] = cbuf[i].re;
826 }
827 cbuf.copy_from_slice(&fv2);
828 spectral_mul_assign(&mut cbuf, &e2);
829 fft_ws.ifft3d(&mut cbuf);
830 for i in 0..n {
831 ev2[i] = cbuf[i].re;
832 }
833 cbuf.copy_from_slice(&fv3);
834 spectral_mul_assign(&mut cbuf, &e3);
835 fft_ws.ifft3d(&mut cbuf);
836 for i in 0..n {
837 ev3[i] = cbuf[i].re;
838 }
839
840 for i in 0..n {
842 cbuf[i] = e1[i] * fv2[i] + e2[i] * fv1[i];
843 }
844 fft_ws.ifft3d(&mut cbuf);
845 for i in 0..n {
846 ev4[i] = cbuf[i].re * 0.5;
847 }
848 for i in 0..n {
849 cbuf[i] = e1[i] * fv3[i] + e3[i] * fv1[i];
850 }
851 fft_ws.ifft3d(&mut cbuf);
852 for i in 0..n {
853 ev5[i] = cbuf[i].re * 0.5;
854 }
855 for i in 0..n {
856 cbuf[i] = e2[i] * fv3[i] + e3[i] * fv2[i];
857 }
858 fft_ws.ifft3d(&mut cbuf);
859 for i in 0..n {
860 ev6[i] = cbuf[i].re * 0.5;
861 }
862
863 for i in 0..n {
865 z0_1[i] = shrink(ev1[i] + s0_1[i], alpha0_over_mu0);
866 z0_2[i] = shrink(ev2[i] + s0_2[i], alpha0_over_mu0);
867 z0_3[i] = shrink(ev3[i] + s0_3[i], alpha0_over_mu0);
868 z0_4[i] = shrink(ev4[i] + s0_4[i], alpha0_over_mu0);
869 z0_5[i] = shrink(ev5[i] + s0_5[i], alpha0_over_mu0);
870 z0_6[i] = shrink(ev6[i] + s0_6[i], alpha0_over_mu0);
871 }
872
873 for i in 0..n {
875 z1_1[i] = shrink(dx1[i] - v1[i] + s1_1[i], alpha1_over_mu1);
876 z1_2[i] = shrink(dx2[i] - v2[i] + s1_2[i], alpha1_over_mu1);
877 z1_3[i] = shrink(dx3[i] - v3[i] + s1_3[i], alpha1_over_mu1);
878 }
879
880 for i in 0..n {
883 cbuf[i] = fx[i] * k[i];
884 }
885 fft_ws.ifft3d(&mut cbuf);
886 for i in 0..n {
887 dx[i] = cbuf[i].re;
888 rhs_z2[i] = mu2 * (dx[i] + s2[i]);
889 z2[i] = rhs_z2[i] / mu2;
890 }
891 let mut delta = f64::INFINITY;
892 let mut inn = 0usize;
893 while delta > params.tol_delta && inn < 50 {
894 inn += 1;
895 let norm_old = norm2(&z2);
896 for i in 0..n {
897 let a = z2[i] - phase[i];
898 let numer = w[i] * a.sin() + mu2 * z2[i] - rhs_z2[i];
899 let denom = w[i] * a.cos() + mu2;
900 update[i] = numer / denom;
901 z2[i] -= update[i];
902 }
903 delta = if norm_old > 0.0 {
904 norm2(&update) / norm_old
905 } else {
906 0.0
907 };
908 }
909
910 for i in 0..n {
912 s0_1[i] += ev1[i] - z0_1[i];
913 s0_2[i] += ev2[i] - z0_2[i];
914 s0_3[i] += ev3[i] - z0_3[i];
915 s0_4[i] += ev4[i] - z0_4[i];
916 s0_5[i] += ev5[i] - z0_5[i];
917 s0_6[i] += ev6[i] - z0_6[i];
918 s1_1[i] += dx1[i] - v1[i] - z1_1[i];
919 s1_2[i] += dx2[i] - v2[i] - z1_2[i];
920 s1_3[i] += dx3[i] - v3[i] - z1_3[i];
921 s2[i] += dx[i] - z2[i];
922 }
923 }
924
925 for v in &mut x {
927 *v /= ppm_to_rad;
928 }
929
930 apply_mask_zero(&mut x, mask);
931 x
932}
933
934#[cfg(test)]
935mod tests {
936 use super::*;
937
938 #[test]
939 fn test_fansi_nltv_zero_field() {
940 let n = 8;
942 let field = vec![0.0; n * n * n];
943 let mask = vec![1u8; n * n * n];
944 let grid = Grid::new(n, n, n, 1.0, 1.0, 1.0);
945 let params = FansiParams {
946 max_iter: 10,
947 is_tgv: false,
948 ..FansiParams::default()
949 };
950
951 let chi = fansi(&field, &mask, &mask.iter().map(|_| 1.0).collect::<Vec<f64>>(), &grid, (0.0, 0.0, 1.0), ¶ms, |_, _| {});
952
953 for &val in chi.iter() {
954 assert!(val.abs() < 1e-6, "Zero field should give ~zero chi, got {}", val);
955 }
956 }
957
958 #[test]
959 fn test_fansi_nltv_finite() {
960 let n = 8;
962 let field: Vec<f64> = (0..n * n * n).map(|i| (i as f64) * 0.001).collect();
963 let mask = vec![1u8; n * n * n];
964 let grid = Grid::new(n, n, n, 1.0, 1.0, 1.0);
965 let params = FansiParams {
966 max_iter: 10,
967 is_tgv: false,
968 ..FansiParams::default()
969 };
970
971 let chi = fansi(&field, &mask, &mask.iter().map(|_| 1.0).collect::<Vec<f64>>(), &grid, (0.0, 0.0, 1.0), ¶ms, |_, _| {});
972
973 for (i, &val) in chi.iter().enumerate() {
974 assert!(val.is_finite(), "Chi should be finite at index {}", i);
975 }
976 }
977
978 #[test]
979 fn test_fansi_nltgv_zero_field() {
980 let n = 8;
982 let field = vec![0.0; n * n * n];
983 let mask = vec![1u8; n * n * n];
984 let grid = Grid::new(n, n, n, 1.0, 1.0, 1.0);
985 let params = FansiParams {
986 max_iter: 10,
987 is_tgv: true,
988 ..FansiParams::default()
989 };
990
991 let chi = fansi(&field, &mask, &mask.iter().map(|_| 1.0).collect::<Vec<f64>>(), &grid, (0.0, 0.0, 1.0), ¶ms, |_, _| {});
992
993 for &val in chi.iter() {
994 assert!(val.abs() < 1e-6, "Zero field should give ~zero chi, got {}", val);
995 }
996 }
997
998 #[test]
999 fn test_fansi_nltgv_finite() {
1000 let n = 8;
1002 let field: Vec<f64> = (0..n * n * n).map(|i| (i as f64) * 0.001).collect();
1003 let mask = vec![1u8; n * n * n];
1004 let grid = Grid::new(n, n, n, 1.0, 1.0, 1.0);
1005 let params = FansiParams {
1006 max_iter: 10,
1007 is_tgv: true,
1008 ..FansiParams::default()
1009 };
1010
1011 let chi = fansi(&field, &mask, &mask.iter().map(|_| 1.0).collect::<Vec<f64>>(), &grid, (0.0, 0.0, 1.0), ¶ms, |_, _| {});
1012
1013 for (i, &val) in chi.iter().enumerate() {
1014 assert!(val.is_finite(), "Chi should be finite at index {}", i);
1015 }
1016 }
1017}