英文:
How to avoid using zeros in interpolation for contourf, for plotting CFD velocity data
问题
从 Ansys Fluent 中的 CFD 模拟中,我有一个包含 4 列的 CSV 数据帧:x、y、z(不规则网格的节点坐标)和 u(流速的大小)。我想要绘制 u 在 x-z 平面上的等高线图。空气流过的实体的 u=0,我希望在插值时对其进行掩码处理,即我想要创建一个带有不规则边界的等高线图。第一张附图大致是我想要使用 Python 获得的结果,是通过 Ansys CFD-Post 获得的,实体的几何形状用黑色轮廓线标出:
这是数据的样子。请注意,列值不是唯一的,也没有排序。
### 几何参数,单位是米
L = 0.3048
hwall = 0.0095
Lin = L-hwall*2
H = 0.073
Lpad = Lin/10
Hpad = H/10
### 获取数据帧:x、y、z坐标和瞬时流向速度
df = pd.read_csv('test2.csv', names=['x','y','z','u'])
dfsub = df.loc[(df.x > -Lin/2-Lpad) & (df.x < Lin/2+Lpad) & (df.z < H+Hpad)] # 限制在较小的区域内
dfsub
x y z u
2 -0.141747 2.106994e-11 0.010645 0.106242
3 -0.139540 -6.458060e-12 0.010615 0.456511
5 -0.132303 -1.308423e-12 0.010602 1.138072
8 0.141747 -2.106730e-11 0.010650 -0.154759
9 0.139543 1.165080e-11 0.010619 -0.150316
... ... ... ... ...
3597 0.159718 -2.567698e-11 0.027614 -0.532316
3598 0.159934 2.542068e-13 0.027258 -0.544210
3599 0.159501 1.936669e-12 0.027613 -0.520241
3600 0.157081 -6.854833e-12 0.035597 -0.392042
3601 0.156974 1.765435e-11 0.027732 -0.382951
以下是用来展示数据的散点图:
umax = max(np.abs(dfsub.u))
fig, ax = plt.subplots(figsize=(16, 3))
dfsub.plot.scatter('x', 'z', c='u', cmap='seismic', vmin=-umax, vmax=umax, ax=ax)
plt.show()
接下来是用于绘图的基本代码,我不希望它起作用,因为实体区域只是被视为插值的速度 = 0:
### 等高线图
crange = 4
fig, ax = plt.subplots(figsize=(16, 3))
tcf = ax.tricontourf(dfsub.x, dfsub.z, dfsub.u, levels=np.arange(
crange, crange, 0.1), cmap='seismic', extend='both')
plt.colorbar(tcf, ax=ax, label='$u$ (m/s)')
ax.set_title('basic', size=14)
plt.show()
以下是输出:
我已经尝试过多种方法来屏蔽这些值,例如将 0 替换为 NaN,但会导致 "ValueError: z array must not contain non-finite values within the triangulation" 错误:
### 获取数据帧:x、y、z坐标和瞬时流向速度
df = pd.read_csv('test2.csv', names=['x','y','z','u'])
df.replace(0, np.nan, inplace=True)
dfsub = df.loc[(df.x > -Lin/2-Lpad) & (df.x < Lin/2+Lpad) & (df.z < H+Hpad)] # 限制在较小的区域内
或者从数据帧中删除 0:
### 获取数据帧:x、y、z坐标和瞬时流向速度
df = pd.read_csv('test2.csv', names=['x','y','z','u'])
df = df.loc[df.u != 0]
dfsub = df.loc[(df.x > -Lin/2-Lpad) & (df.x < Lin/2+Lpad) & (df.z < H+Hpad)] # 限制在较小的区域内
这种方法的输出如下所示,它仍然在我打算排除的区域内进行插值。
英文:
From a CFD simulation in Ansys Fluent, I have a dataframe from a csv containing 4 columns: x,y,z (nodal coordinates of irregular grid), and u (streamwise velocity magnitude). I want to plot a contour plot of u over the x-z plane. The solid body around which air flows has u=0, and I want this to be masked for the interpolation, i.e. I want to create a contour plot with an irregular boundary. The first attached image is more or less what I'd like to get with Python, obtained with Ansys CFD-Post -- the geometry of the solid body is outlined in black:
This is what the data looks like. Note column values are not unique or sorted.
### geometric parameters, in m
L = 0.3048
hwall = 0.0095
Lin = L-hwall*2
H = 0.073
Lpad = Lin/10
Hpad = H/10
### get df: x,y,z coordinates and instantaneous streamwise velocity
df = pd.read_csv('test2.csv',names=['x','y','z','u'])
dfsub = df.loc[(df.x>-Lin/2-Lpad)&(df.x<Lin/2+Lpad)&(df.z<H+Hpad)] # limit to smaller region
dfsub
x y z u
2 -0.141747 2.106994e-11 0.010645 0.106242
3 -0.139540 -6.458060e-12 0.010615 0.456511
5 -0.132303 -1.308423e-12 0.010602 1.138072
8 0.141747 -2.106730e-11 0.010650 -0.154759
9 0.139543 1.165080e-11 0.010619 -0.150316
... ... ... ... ...
3597 0.159718 -2.567698e-11 0.027614 -0.532316
3598 0.159934 2.542068e-13 0.027258 -0.544210
3599 0.159501 1.936669e-12 0.027613 -0.520241
3600 0.157081 -6.854833e-12 0.035597 -0.392042
3601 0.156974 1.765435e-11 0.027732 -0.382951
Here is a scatterplot to show the data:
umax = max(np.abs(dfsub.u))
fig,ax=plt.subplots(figsize=(16,3))
dfsub.plot.scatter('x','z',c='u',cmap ='seismic',vmin=-umax,vmax=umax,ax=ax)
plt.show()
And here is the basic code for plotting, which I don't expect to work since the solid region is just read as velocity = 0 for interpolation:
### contour plot
crange = 4
fig,ax=plt.subplots(figsize=(16,3))
tcf = ax.tricontourf(dfsub.x,dfsub.z,dfsub.u,levels=np.arange(
crange,crange,0.1),cmap='seismic',extend='both')
plt.colorbar(tcf,ax=ax,label='$u$ (m/s)')
ax.set_title('basic',size=14)
plt.show()
and here is the output:
I've tried to mask these values in several ways, e.g. replace 0s with nans, which gives "ValueError: z array must not contain non-finite values within the triangulation":
### get df: x,y,z coordinates and instantaneous streamwise velocity
df = pd.read_csv('test2.csv',names=['x','y','z','u'])
df.replace(0, np.nan, inplace=True)
dfsub = df.loc[(df.x>-Lin/2-Lpad)&(df.x<Lin/2+Lpad)&(df.z<H+Hpad)] # limit to smaller region
or to remove the 0s from the dataframe:
### get df: x,y,z coordinates and instantaneous streamwise velocity
df = pd.read_csv('test2.csv',names=['x','y','z','u'])
df = df.loc[df.u != 0]
dfsub = df.loc[(df.x>-Lin/2-Lpad)&(df.x<Lin/2+Lpad)&(df.z<H+Hpad)] # limit to smaller region
The output for this is in the attached image. It still interpolates in the regions I mean to exclude.
答案1
得分: 0
如果我理解您的问题正确的话,您想要使用一个遮罩数组。在绘制遮罩数组的轮廓时,遮罩的区域将被忽略。没有实际数据来了解它的格式,我会留给您来想出如何创建您的遮罩数组。
import numpy as np
import matplotlib.pyplot as plt
plt.close("all")
x = np.linspace(-1, 1, 100)
y = np.linspace(0, 1, 100)
X, Y = np.meshgrid(x, y)
U = X + 2*Y
# 创建一个不希望轮廓存在的区域
solid = (X >= -0.25) & (X <= 0) & (Y >= 0) & (Y <= 0.75)
# mask参数接受一个布尔数组,指示哪些元素被遮罩
U_masked = np.ma.array(U, mask=solid)
fig, ax = plt.subplots()
# contourf不会绘制被遮罩的区域
p = ax.contourf(X, Y, U_masked, corner_mask=False)
fig.colorbar(p, ax=ax, label="u")
ax.set_xlabel("x")
ax.set_ylabel("y")
编辑:由于数据是不规则间隔的,使用tricontourf
可能会更合适。这种方法的唯一问题是角落可能会被截断(或者我不确定如何处理它)。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as tri
plt.close("all")
x = np.linspace(-1, 1, 100)
y = np.linspace(0, 1, 100)
X, Y = np.meshgrid(x, y)
U = X + 2*Y
# 创建一个不希望轮廓存在的区域
solid = (X >= -0.25) & (X <= 0) & (Y >= 0) & (Y <= 0.75)
# 创建三角形;我使用了之前的扁平化X和Y,但我认为使用数据的x和y值也可以
triang = tri.Triangulation(X.flatten(), Y.flatten())
# 基于`solid`布尔矩阵遮罩三角形
triang.set_mask(np.any(solid.flatten()[triang.triangles], axis=1))
fig, ax = plt.subplots()
p = ax.tricontourf(triang, U.flatten())
fig.colorbar(p, ax=ax, label="u")
ax.set_xlabel("x")
ax.set_ylabel("y")
英文:
If I understand your question correctly, you want to use a masked array. When plotting the contours of masked arrays, the masked regions are ignored. Without the actual data to understand how it is formatted, I leave it to you to figure out how to create your masking array.
import numpy as np
import matplotlib.pyplot as plt
plt.close("all")
x = np.linspace(-1, 1, 100)
y = np.linspace(0, 1, 100)
X, Y = np.meshgrid(x, y)
U = X + 2*Y
# create a region where we do not want the contour to exist
solid = (X >= -0.25) & (X <= 0) & (Y >= 0) & (Y <= 0.75)
# the mask argument takes a boolean array that says which elements are masked
U_masked = np.ma.array(U, mask=solid)
fig, ax = plt.subplots()
# contourf will not plot the masked regions
p = ax.contourf(X, Y, U_masked, corner_mask=False)
fig.colorbar(p, ax=ax, label="u")
ax.set_xlabel("x")
ax.set_ylabel("y")
Edit: Since the data is irregularly spaced, using tricontourf
might work instead. The only issue with this method is that corners will be cut off (or at least I am not sure how to deal with that).
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as tri
plt.close("all")
x = np.linspace(-1, 1, 100)
y = np.linspace(0, 1, 100)
X, Y = np.meshgrid(x, y)
U = X + 2*Y
# create a region where we do not want the contour to exist
solid = (X >= -0.25) & (X <= 0) & (Y >= 0) & (Y <= 0.75)
# create the triangles; I used the flattened X and Y from before,
# but I think using the x and y values from the data will work
triang = tri.Triangulation(X.flatten(), Y.flatten())
# masking triangles based on the `solid` boolean matrix
triang.set_mask(np.any(solid.flatten()[triang.triangles], axis=1))
fig, ax = plt.subplots()
p = ax.tricontourf(triang, U.flatten())
fig.colorbar(p, ax=ax, label="u")
ax.set_xlabel("x")
ax.set_ylabel("y")
答案2
得分: 0
以下是您要翻译的内容:
@jared的解决方案似乎有点效果,但我还按照this解决方案创建了一个用于这些数据的掩码。
用于掩码的3个几何条件
cond1 = (df.x > -L/2) & (df.x < L/2) & (df.z < hbase)
cond2 = (df.x > -L/2) & (df.x < -Lin/2) & (df.z < H)
cond3 = (df.x > Lin/2) & (df.x < L/2) & (df.z < H)
df.loc[cond1 | cond2 | cond3, 'u'] = 0 # 在这些区域将列u设置为0
从DataFrame列中提取值
x = df.x.values
z = df.z.values
u = df.u.values
基于u数组中的零值设置掩码
isbad = u == 0
进行三角剖分,并计算三角形的索引
triang = tri.Triangulation(x, z)
mask = np.all(np.where(isbad[triang.triangles], True, False), axis=1)
triang.set_mask(mask)
使用带有掩码的tricontourf绘制轮廓
crange = 4
fig, ax = plt.subplots(figsize=(16, 3))
tcf = ax.tricontourf(triang, u, levels=np.arange(-crange, crange, 0.005), cmap='seismic', extend='both')
plt.colorbar(tcf, ax=ax, label='$u$ (m/s)')
ax.set_ylim(0,0.08)
ax.set_xlim(-0.165,0.165)
plt.xlabel('x')
plt.ylabel('z')
plt.show()
似乎可以防止在零值上进行插值,但是三角剖分非常粗糙,所以掩码效果不佳。
我猜解决方案是优化网格并进行某种插值?
英文:
The solution from @jared somewhat works, but I also followed this solution to create a mask for this data.
# 3 geometric conditions for mask
cond1 = (df.x > -L/2) & (df.x < L/2) & (df.z < hbase)
cond2 = (df.x > -L/2) & (df.x < -Lin/2) & (df.z < H)
cond3 = (df.x > Lin/2) & (df.x < L/2) & (df.z < H)
df.loc[cond1 | cond2 | cond3, 'u'] = 0 # set column u = 0 in those regions
# Extract the values from the DataFrame columns
x = df.x.values
z = df.z.values
u = df.u.values
# Set up the mask based on zero values in the u array
isbad = u == 0
# triangulate, and evaluate indices of triangles
triang = tri.Triangulation(x, z)
mask = np.all(np.where(isbad[triang.triangles], True, False), axis=1)
triang.set_mask(mask)
# Plot the contour using tricontourf with a mask
crange = 4
fig, ax = plt.subplots(figsize=(16, 3))
tcf = ax.tricontourf(triang, u, levels=np.arange(-crange, crange, 0.005), cmap='seismic', extend='both')
plt.colorbar(tcf, ax=ax, label='$u$ (m/s)')
ax.set_ylim(0,0.08)
ax.set_xlim(-0.165,0.165)
plt.xlabel('x')
plt.ylabel('z')
plt.show()
It does seem to prevent interpolation over the zeros, but the triangulation is very coarse, so the mask isn't great.
I guess the solution is to refine the grid + interpolate somehow?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论