在Python中创建和更新3个索引矩阵
我试图创建一个三索引矩阵,其中包含数值空间网格(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,但我想可能我只是在数组的概念和基本方面有一个严重的差距,因为似乎什么都做不到。如果我没有正确地解释自己,我将非常感激和抱歉任何介绍。下面是我尝试过的一些代码:在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
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 )