2012-12-06 6 views
1

저는 현재 전기장을 계산하고 3D 공간에서 그라데이션을 계산하는 프로젝트를 진행하고 있습니다. 이것은 수치 적으로 라플라스의 방정식을 풀 필요가 있으며 이것을 수행하는 클래스를 작성했습니다 (아래 참조).하지만 여기서는 배경으로 사용할 수 있습니다.3D numpy 배열에 함수를 맞추는 방법은 무엇입니까?

################################################################################ 
# 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] 

그래서 나는 a를 내 그리드의 각 점에서의 전위 (V)의 값을 가진 3D NumPy와 배열을 얻을

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) 

다음 실행할 때. 그러나이 함께 더 유용한 것들을 할 수 있도록 연속 된 함수 사용하여이 값 배열을 approximate 수 있도록 내 표에없는 지점에서 필드 및 해당 그라디언트를 계산할 수 싶습니다.

A) 가능한가요? B)이 작업에 대해 어떻게 생각하십니까? 나는 기본적인 scipy 피팅 함수를 보았지만이 방법으로 3D 데이터를 처리 할 수는 없었습니다 (또는 실제로 2D 배열에 대한 유사한 함수에 적합 함).

+1

확인 http://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.interpolation.map_coordinates.html – arynaq

+0

안녕하세요, 빠른 답변을 보내 주셔서 감사합니다. 당신이 준 링크 (만약 내가 올바르게 이해했다면, 나는 단지 빠른 플레이를 가졌음)는 내 눈금이 아닌 지점에서 필드의 가치를 찾는 데 정말로 유용합니다. 나는 스플라인 보간에 대한 순서를 정했다. 정확하게 이해했다면 그리드 점 사이의 필드가 선형인지, 2 차 왜곡인지, 3 차 요법인지를 추측해야한다는 것을 알았다. 필자는 이것을 모르기 때문에, 모든 데이터 포인트에 가장 적합한 것을 자동으로 계산하는 유사한 작업을 수행 할 수있는 방법이 있습니까? – user1562862

답변

1

http://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.interpolation.map_coordinates.html 데이터를 보간 스플라인을 사용

감사 누군가가 전에이 작업을 수행하기 위해 노력하고 있지만 어떤 도움이 정말 감사하겠습니다하는 장거리 슛 수 있습니다 당신은 스플라인의 정도를 선택 순서 매개 변수, 기본값 3

스플라인 보간에 익숙한 경우 저차 다항식을 사용하여 데이터 점에 "패치"합니다. 위키 백과에 대한 빠른 읽기 http://en.wikipedia.org/wiki/Spline_interpolation 또는 http://math.tut.fi/~piche/numa2/lecture16.pdf

데이터가 너무 불규칙하지 않은 경우 다항식의 순서는 계산 시간을 소비하면서 오류를 줄입니다. 더 낮은 순위로 시도해 볼 수 있습니다.

+0

아, 이해합니다. 완전성을 위해, 주어진 배열을 넘어선 데이터는 경계에있는 데이터와 상수라고 가정되어 고차 보간에 예기치 않은 결과를 얻는다는 사실로 인해 혼란이있었습니다. 둘 다 감사합니다! – user1562862

0

또 다른 옵션은 FEM (Finite Element Method) 라이브러리를 살펴볼 수 있습니다. 적절한 요소를 사용하면 보간 구배는 일반적으로 유한 차분 기반 방법보다 정확합니다. 예 : Fenics에는 멋진 파이썬 인터페이스가 있습니다. tutorial에서는 포아송 방정식의 좀 더 일반적인 경우가 제시되며, 이는 라플라스 방정식에 쉽게 적용될 수 있습니다.

+0

아마도 매우 유용하게 보입니다. @Dietrich에게 감사드립니다. – user1562862

관련 문제