From 0d30e38f33ce46cef9c1ad0182e369c1001cb924 Mon Sep 17 00:00:00 2001 From: Zichen LI Date: Wed, 17 Sep 2025 18:55:50 +0200 Subject: [PATCH] Add Moulinec-Suquet complete filed --- moulinec_suquet.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 moulinec_suquet.py diff --git a/moulinec_suquet.py b/moulinec_suquet.py new file mode 100644 index 0000000..5fa57da --- /dev/null +++ b/moulinec_suquet.py @@ -0,0 +1,52 @@ +import numpy as np + +def complete_field(G, G_0, f, + epsilon=1e-6, + max_iter=5000): + N = G.shape[0] + M = G.shape[1] + q_x_macro = 2*np.pi*np.fft.fftfreq(N, d=1/N) + q_y_macro = 2*np.pi*np.fft.fftfreq(M, d=1/M) + Qx, Qy = np.meshgrid(q_x_macro, q_y_macro) + + + + # Step 0: Initial guess using the simpler Poisson solution + # ∇²u = -f / G_0 -> u = solve_poisson_fft(f) if we interpret as (∆u + f=0) or similar. + u_n = solve_poisson_fft(f) + u_n_tilde = np.fft.fft2(u_n) + + # Pre-transform for efficiency + f_tilde = np.fft.fft2(f) + + for _ in range(max_iter): + # Step 1: gradient of u_n in Fourier space + grad_u_n_tilde = (1j * Qx * u_n_tilde, 1j * Qy * u_n_tilde) + + # Step 2: transform back to real space to get grad(u_n) + grad_u_n_x = np.fft.ifft2(grad_u_n_tilde[0]).real + grad_u_n_y = np.fft.ifft2(grad_u_n_tilde[1]).real + + # Multiply (G - G_0) with grad(u_n) in real space, then transform to frequency space + temp_x = np.fft.fft2((G - G_0) * grad_u_n_x) + temp_y = np.fft.fft2((G - G_0) * grad_u_n_y) + + # Step 3: compute divergence in Fourier space + # div(...) -> iQx * temp_x + iQy * temp_y + f_n_tilde = 1j * Qx * temp_x + 1j * Qy * temp_y + + # Step 4: solve Poisson in Fourier space + # G_0 ∆ u = -(f_n + f) => ∆ u = -(f_n + f)/G_0 + u_next_tilde = foh.solve_poisson_fft_tilde(-(f_n_tilde + f_tilde) / G_0, Qx, Qy) + u_next = np.fft.ifft2(u_next_tilde).real + + # Step 5: check for convergence + if np.linalg.norm(u_next - np.fft.ifft2(u_n_tilde).real) < epsilon: + u_n_tilde = u_next_tilde + break + + # Step 6: update solution + u_n_tilde = u_next_tilde + + # Return final solution in real space + return np.fft.ifft2(u_n_tilde).real