在Python中创建和更新3个索引矩阵

在Python中创建和更新3个索引矩阵,python,numpy,multidimensional-array,physics,numerical-methods,Python,Numpy,Multidimensional Array,Physics,Numerical Methods,我试图创建一个三索引矩阵,其中包含数值空间网格(xyz)每个节点的1个值(V)(现实问题:空间点上有限平行板产生的静电势)。该矩阵最初必须用零填充,但某些特定点除外(板和空间限制为零),然后根据以下7点模板法(分别为x y z坐标的j k和l指数)迭代更新每个节点处的值: V[j,k,l]=(V[j+1,k,l]+V[j-1,k,l]+V[j,k+1,l]+V[j,k-1,l]+V[j,k,l+1]+V[j,k,l-1])/6 (即,用其他6个相邻节点的平均值替换一个节点的值) 我试过np.ze

我试图创建一个三索引矩阵,其中包含数值空间网格(xyz)每个节点的1个值(V)(现实问题:空间点上有限平行板产生的静电势)。该矩阵最初必须用零填充,但某些特定点除外(板和空间限制为零),然后根据以下7点模板法(分别为x y z坐标的j k和l指数)迭代更新每个节点处的值:

V[j,k,l]=(V[j+1,k,l]+V[j-1,k,l]+V[j,k+1,l]+V[j,k-1,l]+V[j,k,l+1]+V[j,k,l-1])/6 (即,用其他6个相邻节点的平均值替换一个节点的值)

我试过np.zero和np.meshgrid,但我想可能我只是在数组的概念和基本方面有一个严重的差距,因为似乎什么都做不到。如果我没有正确地解释自己,我将非常感激和抱歉任何介绍。下面是我尝试过的一些代码:

V1 = 10
V2 = -5
Mx = 101
My = 151
Mz = 301

V = np.zeros([Mx, My, Mz]).astype(int)
V[46, 51:101, 101:201] = V1   #the values of these nodes should stay fixed throughout iteration
V[56, 51:101, 101:201] = V2   #the values of these nodes should stay fixed throughout iteration
V[1,:,:] =V[100,:,:] =V[:,1,:] =V[:,150,:] =V[:,:,1] =V[:,:,300] = 0     #the values of these nodes should stay fixed throughout iteration

for j  in V:
    for k in j:
        for l in k:
            V[j, k, l] = (V[j+1, k, l] + V[j-1, k, l] + V[j, k+1, l] + V[j, k-1, l] + V[j, k, l+1] +V[j, k, l-1])/6
(在用户kcw78提供帮助后更新)

实现建议的代码并尝试实现一个while循环,该循环将一直运行,直到错误降至公差以下或两个连续周期中的错误相同。任务声明更具体地说:

“这些循环中的许多将根据需要完成,以使误差降至某个规定的公差rtol以下。这里什么是误差的良好测量方法?我们将使用局部残差的最大值,定义为(误差的绝对值)中心节点的电位值与模具中其他值的算术平均值之间的差值。作为额外的保护措施,我们还将比较任意两个连续循环的误差,如果误差相等,则停止松弛。不再可能有更好的解决方案。”

现在尝试下面的代码,但不确定它是否被困在无限while循环中,或者只是花费了很多时间,因为我必须在20分钟后停止它而不产生任何输出(也不确定是否应该使用.all()而不是.any()):

将numpy导入为np
V1=10
V2=-5
Mx=101
My=151
Mz=301
rtol=10**-2
V1_集={(46,k,l)对于范围(51101,1)中的k,对于范围(101201,1)中的l}
V2_集={(56,k,l)对于范围(51101,1)中的k,对于范围(101201,1)中的l}
V=np.零((Mx,My,Mz))
Vnew=np.copy(V)
V[46,51:101,101:201]=V1
V[56,51:101,101:201]=V2
V[1,:,:]=V[100,:,:]=V[:,1,:]=V[:,150,:]=V[:,:,1]=V[:,:,:,300]=0
检查集合=集合().union(V1集合,V2集合)
错误=np.零((Mx,My,Mz))
errornew=np.Zero((Mx,My,Mz))
而float(errornew.any())
如果我理解您的问题,您需要进行两项更改:

  • 首先,您需要额外的变量来检查通过迭代固定的位置。为此,我添加了带有
    (j,k,l)
    元组的集合。所以你可以按照我的逻辑,我最初创造了3套;1.这些索引的每一个:1)固定V1(
    V1\u集
    ),2)固定V2(
    V2\u集
    )和3)边界(
    zero\u集
    ),然后将所有3个集合并为一个集(称为
    检查集
    )。您可以从单个集合开始,并在添加时进行更新。旁注:您的代码具有
    V[1,:,:]=0
    ,但我认为您确实需要
    V[0,:,:]=0
    。如果我解释错误,请告诉我
  • 其次,您需要在每个方向的轴长度上循环(属性为
    V.shape[0]、V.shape[1]、V.shape[2]
    )。在循环内部,我对照
    检查集
    检查每个
    (I,j,k)
    ,如果不在集中,则仅重新计算
    V1[j,k,l]
  • 见下面的代码:

    V1 = 10
    V2 = -5
    Mx = 101
    My = 151
    Mz = 301
    
    V1_set = { (46,k,l) for k in range(51,101,1) for l in range(101,201,1) }
    V2_set = { (56,k,l) for k in range(51,101,1) for l in range(101,201,1) }
    
    zero_set = set()
    zero_set.update( { (0,k,l) for k in range(My) for l in range(Mz) } )
    zero_set.update( { (100,k,l) for k in range(My) for l in range(Mz) } )
    zero_set.update( { (j,0,l) for j in range(Mx) for l in range(Mz) } )
    zero_set.update( { (j,150,l) for j in range(Mx) for l in range(Mz) } )
    zero_set.update( { (j,k,0) for j in range(Mx) for k in range(My) } )
    zero_set.update( { (j,k,300) for j in range(Mx) for k in range(My) } )
    
    check_set = set().union(V1_set,V2_set,zero_set)
    
    V = np.zeros((Mx, My, Mz)).astype(int)
    V[46, 51:101, 101:201] = V1   #the values of these nodes should stay fixed throughout iteration
    V[56, 51:101, 101:201] = V2   #the values of these nodes should stay fixed throughout iteration
    V[1,:,:] =V[100,:,:] =V[:,1,:] =V[:,150,:] =V[:,:,1] =V[:,:,300] = 0     #the values of these nodes should stay fixed throughout iteration
    
    for j in range(V.shape[0]):
        for k in range(V.shape[1]):
            for l in range(V.shape[2]):
                if (j,k,l) not in check_set:
                    V[j, k, l] = (V[j+1, k, l] + V[j-1, k, l] + V[j, k+1, l] + V[j, k-1, l] + V[j, k, l+1] +V[j, k, l-1])/6
    
    发布上述解决方案后,我突然想到
    zero\u set
    中使用的范围旨在避免第一个/最后一个(数组边界)索引。如果是这样,则无需设置
    零位
    。您可以通过修改范围参数来处理此问题,如下所示:

    check_set = set().union(V1_set,V2_set)
    for j in range(1,V.shape[0]-1):
        for k in range(1,V.shape[1]-1):
            for l in range(1,V.shape[2]-1):
                if (j,k,l) not in check_set:
                    V[j, k, l] = (V[j+1, k, l] + V[j-1, k, l] + V[j, k+1, l] + V[j, k-1, l] + V[j, k, l+1] +V[j, k, l-1])/6
    
    需要考虑的其他意见:

    • 我注意到您使用
      .astype(int)
      创建了数组
      V
      。你确定吗? 这就是你想要的(而不是浮动)?通常,您的计算不会返回整数值
    • 您编写代码的方式就是更改
      V[j,k,l]
      。因此,您使用的是更新后的
      V[j,k,l]
      对于小于当前
      j,k,l
      j,k,l
      ,以及大于当前
      j,k,l
      的先前
      V[j,k,l]
    • 最后,我假设您将迭代此计算,直到两个周期之间的变化“可接受的小”。如果是这样,您需要有两个数组副本(“旧”和“新”)来获取差异。复制以创建新的/不同的np.array对象时,请注意使用
      .copy()

    这是一个更新的答案,它基于添加到初始帖子中的新信息和代码。您的逻辑至少有一个问题。
    如果(j,k,l)不在check\u set:
    块跳过要保持恒定的(j,k,l)值。因此,在这些点上不计算
    Vnew
    。这将导致每次迭代计算更改时出现问题(并将给出错误的结果)。 另外,我认为您需要
    V=Vnew.copy()
    。否则,
    V
    Vnew
    引用同一对象

    下面是我使用硬编码容错进行迭代的简单方法

    check_set = set().union(V1_set,V2_set)
    Vi = V.copy()
    Vn = np.zeros((Mx, My, Mz))
    diff = max(abs(V1), abs(V2))
    i = 1
    print('Start Cycle#',i,'; diff =',diff)
    while diff > 0.25:
        for j in range(1,V.shape[0]-1):
            for k in range(1,V.shape[1]-1):
                for l in range(1,V.shape[2]-1):
                    if (j,k,l) in check_set:
                        Vn[j, k, l] = Vi[j, k, l]
                    else:
                        Vn[j, k, l] = (Vi[j+1, k, l] + Vi[j-1, k, l] + Vi[j, k+1, l] + Vi[j, k-1, l] + Vi[j, k, l+1] +Vi[j, k, l-1])/6      
          
        diff = max(abs(np.amax(Vn-Vi)), abs(np.amin(Vn-Vi)))
        print('Cycle#',i,'completed; diff =',diff)
        i += 1
        Vi = Vn.copy()
    
    此实现将在10次迭代中“收敛”。H
    check_set = set().union(V1_set,V2_set)
    Vi = V.copy()
    Vn = np.zeros((Mx, My, Mz))
    diff = max(abs(V1), abs(V2))
    i = 1
    print('Start Cycle#',i,'; diff =',diff)
    while diff > 0.25:
        for j in range(1,V.shape[0]-1):
            for k in range(1,V.shape[1]-1):
                for l in range(1,V.shape[2]-1):
                    if (j,k,l) in check_set:
                        Vn[j, k, l] = Vi[j, k, l]
                    else:
                        Vn[j, k, l] = (Vi[j+1, k, l] + Vi[j-1, k, l] + Vi[j, k+1, l] + Vi[j, k-1, l] + Vi[j, k, l+1] +Vi[j, k, l-1])/6      
          
        diff = max(abs(np.amax(Vn-Vi)), abs(np.amin(Vn-Vi)))
        print('Cycle#',i,'completed; diff =',diff)
        i += 1
        Vi = Vn.copy()
    
    error[j, k, l] = abs(Vn[j, k, l] - (Vn[j+1, k, l] + Vn[j-1, k, l] + Vn[j, k+1, l] + Vn[j, k-1, l] + Vn[j, k, l+1] +Vn[j, k, l-1])/6 )