1

我目前正在从事一个涉及计算电场和 3D 空间中的梯度的项目。这需要对拉普拉斯方程进行数值求解,我已经编写了一个类来执行此操作(如下),它有效,但这里仅用于背景;

################################################################################
#  class:  ThreeDRectLaplaceSolver                                             #
#                                                                              #
#  A class to solve the Laplace equation given the potential on the boundaries.#                                                         
################################################################################
class ThreeDCuboidLaplaceSolver:

#############################################################################
# Store the init variables as class varibales, calculate the grid spacing to#
# solve Laplace's equation on and create arrays to store the iterations and #
# results in.                                                               #   
############################################################################
def __init__(self, xmin, xmax, ymin, ymax, zmin, zmax, gridstep):

    self.xmin, self.xmax = xmin, xmax
    self.ymin, self.ymax = ymin, ymax
    self.zmin, self.zmax = zmin, zmax

    self.xpoints  = int((xmax-xmin)/gridstep) + 1
    self.ypoints  = int((ymax-ymin)/gridstep) + 1
    self.zpoints  = int((zmax-zmin)/gridstep) + 1

    self.dx = (xmax-xmin)/self.xpoints
    self.dy = (ymax-ymin)/self.ypoints
    self.dz = (zmax-zmin)/self.zpoints

    self.v     = np.zeros((self.xpoints, self.ypoints, self.zpoints))
    self.old_v = self.v.copy()

    self.timeStep = 0

############################################################################
# Set constant values along the boundaries                                 #
#                                                                          #
# Top(bottom) is +ive(-ive) end of z-axis                                  #
# Right(left) is +ive(-ive) end of y-axis                                  #
# Front(back) is +ive(-ive) end of x-axis                                  #
############################################################################   
def setBC(self, frontBC, backBC, rightBC, leftBC, topBC, bottomBC):

    self.v[-1, :, :] = frontBC
    self.v[0 , :, :] = backBC
    self.v[: ,-1, :] = rightBC
    self.v[: , 0, :] = leftBC
    self.v[: , :,-1] = topBC
    self.v[: , :, 0] = bottomBC

    self.old_v = self.v.copy()

def solve_slow(self, PercentageTolerance = 5):

    PercentageError = PercentageTolerance + 1

    while PercentageError > PercentageTolerance:

        self.Iterate()
        PercentageError = self.Get_LargestPercentageError()
        print "Completed iteration number %s \n Percentage Error is %s\n" % (str(self.timeStep), str(PercentageError))

    return self.v

def solve_quick(self, Tolerance = 2):

    AbsError = Tolerance + 1

    while AbsError > Tolerance:

        self.Iterate()
        AbsError = self.Get_LargestAbsError()
        print "Completed iteration number %s \nAbsolute Error is %s\n" % (str(self.timeStep), str(AbsError))

    return self.v 

def Get_LargestAbsError(self):

    return np.sqrt((self.v - self.old_v)**2).max()

def Get_LargestPercentageError(self):

    AbsDiff = (np.sqrt((self.v - self.old_v)**2)).flatten()

    v = self.v.flatten()

    vLength = len(v)

    Errors = []

    i=0
    while i < vLength:

        if v[i]==0 and AbsDiff[i]==0:
            Errors.append(0)

        elif v[i]==0 and AbsDiff[i]!=0:
            Errors.append(np.infty)

        else:    
            Errors.append(AbsDiff[i]/v[i])

        i+=1

    return max(Errors)*100

# Perform one round of iteration (ie the value at each point is iterated by one timestep)    
def Iterate(self):

    self.old_v = self.v.copy()

    print self.Get_vAt(0,5,0)

    self.v[1:-1,1:-1,1:-1] = (1/26)*(self.v[0:-2, 2:, 2:  ] + self.v[0:-2, 1:-1, 2:  ] + self.v[0:-2, 0:-2, 2:  ] +\
                                     self.v[1:-1, 2:, 2:  ] + self.v[1:-1, 1:-1, 2:  ] + self.v[1:-1, 0:-2, 2:  ] +\
                                     self.v[2:  , 2:, 2:  ] + self.v[2:  , 1:-1, 2:  ] + self.v[2:  , 0:-2, 2:  ] +\

                                     self.v[0:-2, 2:, 1:-1] + self.v[0:-2, 1:-1, 1:-1] + self.v[0:-2, 0:-2, 1:-1] +\
                                     self.v[1:-1, 2:, 1:-1] +                            self.v[1:-1, 0:-2, 1:-1] +\
                                     self.v[2:  , 2:, 1:-1] + self.v[2:  , 1:-1, 1:-1] + self.v[2:  , 0:-2, 1:-1] +\

                                     self.v[0:-2, 2:, 0:-2] + self.v[0:-2, 1:-1, 0:-2] + self.v[0:-2, 0:-2, 0:-2] +\
                                     self.v[1:-1, 2:, 0:-2] + self.v[1:-1, 1:-1, 0:-2] + self.v[1:-1, 0:-2, 0:-2] +\
                                     self.v[2:  , 2:, 0:-2] + self.v[2:  , 1:-1, 0:-2] + self.v[2:  , 0:-2, 0:-2])

    self.timeStep += 1

# Iterate through a certain number of time steps    
def IterateSteps(self, timeSteps):

    i = 0
    while i < timeSteps:

        self.Iterate()

        i+=1

# Get the value of v at a point (entered as coordinates, NOT indices)        
def Get_vAt(self, xPoint, yPoint, zPoint):

    # Find the indices nearest to the coordinates entered

    diff = [np.sqrt((x-xPoint)**2) for x in np.linspace(self.xmin,self.xmax,self.xpoints)]
    xIndex = diff.index(min(diff))

    diff = [np.sqrt((y-yPoint)**2) for y in np.linspace(self.ymin,self.ymax,self.ypoints)]
    yIndex = diff.index(min(diff))

    diff = [np.sqrt((z-zPoint)**2) for z in np.linspace(self.zmin,self.zmax,self.zpoints)]
    zIndex = diff.index(min(diff))

    # retun the value from of v at this point
    return self.v[xIndex, yIndex, zIndex]

所以当我运行以下

    solver = ThreeDCuboidLaplaceSolver(0, 20, 0, 10, 0, 20, 1)

TwoDsolver = TwoDRectLaplaceSolver(0,20,0,10,1)
TwoDsolver.setBC(1000,0,0,0)

v_0 = np.zeros((21,11))
v_0[4:6,4:6] = 1000
v_0[14:15, 9:10] = 2000

solver.setBC(0,0,0,0,0,v_0)
v = solver.solve_quick(0.00001)

我得到一个 3D numpy 数组,其中包含网格上每个点的电位 (V) 值。然而,为了用这个做更多有用的事情,我希望能够用一个连续函数来近似这个值数组,这样我就可以计算不在我的网格上的点的场及其梯度。

A)这可能吗?B) 你会怎么做?我见过基本的 scipy 拟合函数,但没有任何东西可以以这种方式处理 3D 数据(或者确实适合 2D 数组的类似函数)。

以前有人尝试过这样做可能是一个很长的机会,但任何帮助将不胜感激,

谢谢

4

2 回答 2

1

http://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.interpolation.map_coordinates.html使用样条线插值数据,您可以使用顺序参数选​​择样条线的度数,默认为 3。

如果您熟悉样条插值,它会使用低次多项式“修补”数据点。快速阅读维基百科http://en.wikipedia.org/wiki/Spline_interpolationhttp://math.tut.fi/~piche/numa2/lecture16.pdf

多项式的阶数以计算时间为代价减少了误差,如果您的数据不是那么不规则,您可以继续尝试使用较低阶数。

于 2012-12-06T14:50:50.000 回答
0

另一种选择可能是查看有限元方法 (FEM) 库。使用适当的元素,插值梯度通常比基于有限差分的方法更准确。例如Fenics有一个不错的 python 界面。在本教程中,介绍了泊松方程的更一般的情况,它可以很容易地适应拉普拉斯方程。

于 2012-12-06T19:00:09.717 回答