如何在contourf插值中避免使用零,以绘制CFD速度数据。

huangapple go评论111阅读模式
英文:

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()

以下是输出:
如何在contourf插值中避免使用零,以绘制CFD速度数据。

我已经尝试过多种方法来屏蔽这些值,例如将 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)] # 限制在较小的区域内

这种方法的输出如下所示,它仍然在我打算排除的区域内进行插值。

如何在contourf插值中避免使用零,以绘制CFD速度数据。

英文:

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:

如何在contourf插值中避免使用零,以绘制CFD速度数据。

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(&#39;test2.csv&#39;,names=[&#39;x&#39;,&#39;y&#39;,&#39;z&#39;,&#39;u&#39;])
dfsub = df.loc[(df.x&gt;-Lin/2-Lpad)&amp;(df.x&lt;Lin/2+Lpad)&amp;(df.z&lt;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(&#39;x&#39;,&#39;z&#39;,c=&#39;u&#39;,cmap =&#39;seismic&#39;,vmin=-umax,vmax=umax,ax=ax)
plt.show()

如何在contourf插值中避免使用零,以绘制CFD速度数据。

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=&#39;seismic&#39;,extend=&#39;both&#39;)
plt.colorbar(tcf,ax=ax,label=&#39;$u$ (m/s)&#39;)
ax.set_title(&#39;basic&#39;,size=14)
plt.show()

and here is the output:
如何在contourf插值中避免使用零,以绘制CFD速度数据。

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(&#39;test2.csv&#39;,names=[&#39;x&#39;,&#39;y&#39;,&#39;z&#39;,&#39;u&#39;])
df.replace(0, np.nan, inplace=True)
dfsub = df.loc[(df.x&gt;-Lin/2-Lpad)&amp;(df.x&lt;Lin/2+Lpad)&amp;(df.z&lt;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(&#39;test2.csv&#39;,names=[&#39;x&#39;,&#39;y&#39;,&#39;z&#39;,&#39;u&#39;])
df = df.loc[df.u != 0]
dfsub = df.loc[(df.x&gt;-Lin/2-Lpad)&amp;(df.x&lt;Lin/2+Lpad)&amp;(df.z&lt;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.

如何在contourf插值中避免使用零,以绘制CFD速度数据。

答案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")

如何在contourf插值中避免使用零,以绘制CFD速度数据。

编辑:由于数据是不规则间隔的,使用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")

如何在contourf插值中避免使用零,以绘制CFD速度数据。

英文:

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(&quot;all&quot;)

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 &gt;= -0.25) &amp; (X &lt;= 0) &amp; (Y &gt;= 0) &amp; (Y &lt;= 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=&quot;u&quot;)
ax.set_xlabel(&quot;x&quot;)
ax.set_ylabel(&quot;y&quot;)

如何在contourf插值中避免使用零,以绘制CFD速度数据。


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(&quot;all&quot;)

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 &gt;= -0.25) &amp; (X &lt;= 0) &amp; (Y &gt;= 0) &amp; (Y &lt;= 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=&quot;u&quot;)
ax.set_xlabel(&quot;x&quot;)
ax.set_ylabel(&quot;y&quot;)

如何在contourf插值中避免使用零,以绘制CFD速度数据。

答案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 &gt; -L/2) &amp; (df.x &lt; L/2) &amp; (df.z &lt; hbase)
cond2 = (df.x &gt; -L/2) &amp; (df.x &lt; -Lin/2) &amp; (df.z &lt; H)
cond3 = (df.x &gt; Lin/2) &amp; (df.x &lt; L/2) &amp; (df.z &lt; H)

df.loc[cond1 | cond2 | cond3, &#39;u&#39;] = 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=&#39;seismic&#39;, extend=&#39;both&#39;)
plt.colorbar(tcf, ax=ax, label=&#39;$u$ (m/s)&#39;)
ax.set_ylim(0,0.08)
ax.set_xlim(-0.165,0.165)
plt.xlabel(&#39;x&#39;)
plt.ylabel(&#39;z&#39;)
plt.show()

It does seem to prevent interpolation over the zeros, but the triangulation is very coarse, so the mask isn't great. 如何在contourf插值中避免使用零,以绘制CFD速度数据。

I guess the solution is to refine the grid + interpolate somehow?

huangapple
  • 本文由 发表于 2023年6月6日 05:41:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76410184.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定