|
|
|
|
|
import numpy as np |
|
|
from scipy import sparse |
|
|
from scipy.sparse.linalg import spsolve |
|
|
from concurrent.futures import ProcessPoolExecutor |
|
|
import time |
|
|
|
|
|
def solver(a): |
|
|
"""Solve the Darcy equation. |
|
|
|
|
|
Args: |
|
|
a (np.ndarray): Shape [batch_size, N, N], the coefficient of the Darcy equation, |
|
|
where N denotes the number of spatial grid points in each direction. |
|
|
|
|
|
Returns: |
|
|
solutions (np.ndarray): Shape [batch_size, N, N]. |
|
|
""" |
|
|
start_time = time.time() |
|
|
batch_size, N, _ = a.shape |
|
|
|
|
|
|
|
|
solutions = np.zeros((batch_size, N, N), dtype=np.float64) |
|
|
|
|
|
|
|
|
if batch_size > 1: |
|
|
print(f"Solving {batch_size} PDE problems with grid size {N}x{N}") |
|
|
|
|
|
with ProcessPoolExecutor() as executor: |
|
|
|
|
|
futures = [executor.submit(solve_single_problem, a[i], N) for i in range(batch_size)] |
|
|
|
|
|
|
|
|
for i, future in enumerate(futures): |
|
|
solutions[i] = future.result() |
|
|
else: |
|
|
|
|
|
solutions[0] = solve_single_problem(a[0], N) |
|
|
|
|
|
elapsed_time = time.time() - start_time |
|
|
print(f"Total solving time: {elapsed_time:.4f} seconds") |
|
|
|
|
|
return solutions |
|
|
|
|
|
def solve_single_problem(a_coeff, N): |
|
|
"""Solve a single Darcy flow problem. |
|
|
|
|
|
Args: |
|
|
a_coeff (np.ndarray): Shape [N, N], coefficient function |
|
|
N (int): Number of grid points in each direction |
|
|
|
|
|
Returns: |
|
|
u (np.ndarray): Shape [N, N], solution |
|
|
""" |
|
|
|
|
|
h = 1.0 / (N - 1) |
|
|
|
|
|
|
|
|
|
|
|
main_diag = np.zeros(N*N) |
|
|
upper_diag = np.zeros(N*N-1) |
|
|
lower_diag = np.zeros(N*N-1) |
|
|
upper_N_diag = np.zeros(N*N-N) |
|
|
lower_N_diag = np.zeros(N*N-N) |
|
|
|
|
|
|
|
|
rhs = np.ones(N*N) |
|
|
|
|
|
|
|
|
for i in range(N): |
|
|
for j in range(N): |
|
|
idx = i*N + j |
|
|
|
|
|
|
|
|
if i == 0 or i == N-1 or j == 0 or j == N-1: |
|
|
main_diag[idx] = 1.0 |
|
|
rhs[idx] = 0.0 |
|
|
else: |
|
|
|
|
|
a_center = a_coeff[i, j] |
|
|
a_west = a_coeff[i, j-1] |
|
|
a_east = a_coeff[i, j+1] |
|
|
a_north = a_coeff[i-1, j] |
|
|
a_south = a_coeff[i+1, j] |
|
|
|
|
|
|
|
|
a_w = 0.5 * (a_center + a_west) |
|
|
a_e = 0.5 * (a_center + a_east) |
|
|
a_n = 0.5 * (a_center + a_north) |
|
|
a_s = 0.5 * (a_center + a_south) |
|
|
|
|
|
|
|
|
main_diag[idx] = (a_w + a_e + a_n + a_s) / (h*h) |
|
|
|
|
|
|
|
|
if j > 0: |
|
|
lower_diag[idx-1] = -a_w / (h*h) |
|
|
if j < N-1: |
|
|
upper_diag[idx] = -a_e / (h*h) |
|
|
if i > 0: |
|
|
lower_N_diag[idx-N] = -a_n / (h*h) |
|
|
if i < N-1: |
|
|
upper_N_diag[idx] = -a_s / (h*h) |
|
|
|
|
|
|
|
|
diagonals = [main_diag, upper_diag, lower_diag, upper_N_diag, lower_N_diag] |
|
|
offsets = [0, 1, -1, N, -N] |
|
|
A = sparse.diags(diagonals, offsets, shape=(N*N, N*N), format='csr') |
|
|
|
|
|
|
|
|
u_flat = spsolve(A, rhs) |
|
|
|
|
|
|
|
|
u = u_flat.reshape((N, N)) |
|
|
|
|
|
return u |
|
|
|