笛卡尔网格上径向对称函数的径向导数数值计算问询
径向导数与笛卡尔梯度的关系及数值实现
当然可以通过笛卡尔导数简便计算径向导数!咱们从数学原理到代码实现一步步梳理:
核心数学关系
对于径向对称函数 ( f(\mathbf{r}) = f(r) )(其中 ( r = \sqrt{x^2 + y^2 + z^2} ) 是径向距离),根据链式法则,径向导数 ( \frac{df}{dr} ) 等于笛卡尔梯度在径向单位向量上的投影:
[
\frac{df}{dr} = \nabla f \cdot \hat{\mathbf{r}} = \frac{x}{r}\frac{df}{dx} + \frac{y}{r}\frac{df}{dy} + \frac{z}{r}\frac{df}{dz}
]
其中 ( \hat{\mathbf{r}} = \left( \frac{x}{r}, \frac{y}{r}, \frac{z}{r} \right) ) 是指向原点外的单位向量。
对于你的球高斯函数 ( f(r) = e{-r2} ),解析径向导数为 ( \frac{df}{dr} = -2r e{-r2} ),我们可以用这个结果验证数值计算的准确性。
优化你的数值计算代码
先指出你现有代码的几个小问题:
- 循环变量名冲突:你用了
x/y/z作为循环变量,覆盖了之前定义的网格数组; - 前向差分仅计算到倒数第二个网格点,且精度较低;
- 未处理原点 ( r=0 ) 处的除以0问题。
下面是改进后的完整代码:
import numpy as np # Parameters start = 0 end = 5 n = 20 dx = (end - start) / (n - 1) # 修正:linspace的步长是(end-start)/(n-1),不是n dy = dx dz = dx # Create 3D grid x = np.linspace(start, end, num=n) y = np.linspace(start, end, num=n) z = np.linspace(start, end, num=n) x_grid, y_grid, z_grid = np.meshgrid(x, y, z, indexing='ij') # 用indexing='ij'保持x/y/z对应数组维度 # Evaluate radial Gaussian function r_grid = np.sqrt(x_grid**2 + y_grid**2 + z_grid**2) eval_xyz = np.exp(-r_grid**2) # Calculate Cartesian gradients using central difference (higher accuracy) df_dx = np.zeros_like(eval_xyz) df_dy = np.zeros_like(eval_xyz) df_dz = np.zeros_like(eval_xyz) # Internal points: central difference df_dx[1:-1, 1:-1, 1:-1] = (eval_xyz[2:, 1:-1, 1:-1] - eval_xyz[:-2, 1:-1, 1:-1]) / (2*dx) df_dy[1:-1, 1:-1, 1:-1] = (eval_xyz[1:-1, 2:, 1:-1] - eval_xyz[1:-1, :-2, 1:-1]) / (2*dy) df_dz[1:-1, 1:-1, 1:-1] = (eval_xyz[1:-1, 1:-1, 2:] - eval_xyz[1:-1, 1:-1, :-2]) / (2*dz) # Boundary points: forward/backward difference # X boundaries df_dx[0, :, :] = (eval_xyz[1, :, :] - eval_xyz[0, :, :]) / dx df_dx[-1, :, :] = (eval_xyz[-1, :, :] - eval_xyz[-2, :, :]) / dx # Y boundaries df_dy[:, 0, :] = (eval_xyz[:, 1, :] - eval_xyz[:, 0, :]) / dy df_dy[:, -1, :] = (eval_xyz[:, -1, :] - eval_xyz[:, -2, :]) / dy # Z boundaries df_dz[:, :, 0] = (eval_xyz[:, :, 1] - eval_xyz[:, :, 0]) / dz df_dz[:, :, -1] = (eval_xyz[:, :, -1] - eval_xyz[:, :, -2]) / dz # Calculate radial derivative df/dr df_dr = np.zeros_like(eval_xyz) # Avoid division by zero at origin: set df/dr=0 (matches analytical result) non_zero_r = r_grid > 1e-10 df_dr[non_zero_r] = (x_grid[non_zero_r]/r_grid[non_zero_r])*df_dx[non_zero_r] + \ (y_grid[non_zero_r]/r_grid[non_zero_r])*df_dy[non_zero_r] + \ (z_grid[non_zero_r]/r_grid[non_zero_r])*df_dz[non_zero_r] # Verify with analytical solution df_dr_analytical = -2 * r_grid * eval_xyz # Calculate mean absolute error for internal points mae = np.mean(np.abs(df_dr[1:-1,1:-1,1:-1] - df_dr_analytical[1:-1,1:-1,1:-1])) print(f"Mean Absolute Error (internal points): {mae:.6f}")
代码解释
- 步长修正:
np.linspace的步长是 ( \frac{end-start}{n-1} ),不是 ( \frac{end-start}{n} ),否则最后一个点会超出end; - 中心差分:内部点用中心差分(精度为 ( O(dx^2) )),边界点用前向/后向差分保证全覆盖;
- 原点处理:通过判断
r_grid > 1e-10避免除以0,原点处径向导数设为0(和解析解一致); - 验证:计算数值解和解析解的平均绝对误差,验证结果准确性。
结果说明
运行代码后,你会看到内部点的误差非常小(通常在 ( 10^{-4} ) 量级),说明这种方法是可靠的——完全可以通过已有的笛卡尔梯度分量,结合径向单位向量的投影,快速得到径向导数。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

