pyvista-visualization について
pyvista-visualizationは、PyVistaでCFDメッシュや計算結果のインタラクティブな3D表示を作成するためのガイドスキルです。場データ、形状、流線を確認したいCFD技術者向けで、表示やメッシュの出力方法も扱います。
主な機能
- 01構造格子・非構造格子の表示
- 02スカラー場の等値線とボリュームレンダリング
- 03速度ベクトルと流線
- 04メッシュのスライスとクリップ
- 05インタラクティブなカメラと複数ビューポート
- 06画像とメッシュのエクスポート
活用シーン
- 01圧力や温度分布の確認
- 02速度場と流線の追跡
- 03複数ビューポートでのCFD条件比較
- 04ParaViewでの後処理に向けた結果保存
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ soljourner/ claude-engineering-skills --skill pyvista-visualizationインストール後、Claude Code で/pyvista-visualizationを入力して読み込まれたか確認します。
同梱ファイルexamples.pyreference.md
詳細
CFD 向け PyVista 3D 可視化
VTK を基盤とする高水準の 3D 可視化ライブラリ PyVista を使用して、速度場、圧力コンター、流線、ポンプ形状など、数値流体力学の結果をインタラクティブな 3D 表示で作成します。
インストールとセットアップ
pip install pyvista numpy
機能を拡張するためのオプションの依存関係:
# For mesh processing and additional features
pip install meshio vtk
# For Jupyter notebook support
pip install trame jupyter-server-proxy ipywidgets
基本的なインポートパターン:
import pyvista as pv
import numpy as np
# Set plotting theme
pv.set_plot_theme('document') # or 'default', 'dark', 'paraview'
# Enable off-screen rendering (for scripts without display)
# pv.OFF_SCREEN = True
CFD 可視化の主要機能
3D メッシュ可視化
PyVista は、CFD に欠かせないさまざまなメッシュタイプをサポートしています。
- 構造格子:曲線座標を持つ規則格子
- 非構造格子:任意のセルタイプ(三角錐、六面体など)
- PolyData:サーフェスメッシュと点群
- 一様格子:規則的なデカルト格子(ボクセル)
import pyvista as pv
import numpy as np
# Create structured grid (e.g., pump volute domain)
x = np.linspace(0, 1, 20)
y = np.linspace(0, 1, 15)
z = np.linspace(0, 0.5, 10)
X, Y, Z = np.meshgrid(x, y, z, indexing='ij')
# Create mesh
grid = pv.StructuredGrid(X, Y, Z)
# Visualize
grid.plot(show_edges=True)
スカラー場の可視化
圧力、温度、乱流強度などのスカラー量を表示します。
# Add scalar field to mesh (e.g., pressure distribution)
pressure = 101325 + 50000 * np.exp(-((X-0.5)**2 + (Y-0.5)**2 + (Z-0.25)**2) / 0.1)
grid['pressure'] = pressure.flatten(order='F')
# Create plotter with contours
plotter = pv.Plotter()
plotter.add_mesh(grid.contour(isosurfaces=10, scalars='pressure'),
cmap='coolwarm',
show_scalar_bar=True,
scalar_bar_args={'title': 'Pressure [Pa]'})
plotter.show()
ベクトル場の可視化(グリフ)
矢印やその他のグリフを使用して速度ベクトルを可視化します。
# Define velocity field
U = -0.5 * (Y - 0.5)
V = 0.5 * (X - 0.5)
W = 0.2 * np.sin(2 * np.pi * Z)
vectors = np.column_stack([U.flatten(order='F'),
V.flatten(order='F'),
W.flatten(order='F')])
grid['velocity'] = vectors
# Create arrow glyphs
arrows = grid.glyph(orient='velocity', scale='velocity', factor=0.1)
plotter = pv.Plotter()
plotter.add_mesh(arrows, cmap='viridis', show_scalar_bar=True,
scalar_bar_args={'title': 'Velocity [m/s]'})
plotter.show()
流線
速度場を通る流跡線を描画します。
# Create seed points for streamlines
seed_points = pv.Disc(center=(0.5, 0.5, 0), inner=0.05, outer=0.3, normal=(0, 0, 1), r_res=6, c_res=12)
# Generate streamlines
streamlines = grid.streamlines(
vectors='velocity',
source_center=(0.5, 0.5, 0),
source_radius=0.3,
n_points=50,
max_time=10.0
)
plotter = pv.Plotter()
plotter.add_mesh(streamlines.tube(radius=0.005), cmap='jet',
scalar_bar_args={'title': 'Velocity Magnitude [m/s]'})
plotter.add_mesh(seed_points, color='red', point_size=10)
plotter.show()
ボリュームレンダリング
透明度を使って 3D スカラー場を表示します。
# Volume rendering for density or temperature fields
plotter = pv.Plotter()
plotter.add_volume(grid, scalars='pressure',
cmap='coolwarm',
opacity='sigmoid', # or 'linear', custom array
scalar_bar_args={'title': 'Pressure [Pa]'})
plotter.show()
スライスとクリッピング
3D 領域から 2D スライスを抽出するか、領域をクリッピングします。
# Create multiple slices through domain
slices = grid.slice_orthogonal(x=0.5, y=0.5, z=0.25)
plotter = pv.Plotter()
plotter.add_mesh(slices, scalars='pressure', cmap='RdBu_r',
show_scalar_bar=True,
scalar_bar_args={'title': 'Pressure [Pa]'})
plotter.show()
# Clip half of domain to see internal flow
clipped = grid.clip(normal='x', value=0.5)
plotter = pv.Plotter()
plotter.add_mesh(clipped, scalars='velocity', cmap='jet',
show_edges=True, show_scalar_bar=True)
plotter.show()
CFD の活用例
速度場の可視化
import pyvista as pv
import numpy as np
# Load or create CFD mesh
grid = pv.ImageData(dimensions=(50, 40, 30))
grid.spacing = (0.02, 0.02, 0.02)
grid.origin = (0, 0, 0)
# Simulate velocity field (e.g., pipe flow with swirl)
x, y, z = grid.points.T
r = np.sqrt((x-0.5)**2 + (y-0.4)**2)
theta = np.arctan2(y-0.4, x-0.5)
u = 2.0 * (1 - (r/0.3)**2) * (r < 0.3) # Axial velocity
v = 0.5 * r * np.cos(theta) * (r < 0.3) # Tangential component
w = -0.5 * r * np.sin(theta) * (r < 0.3)
grid['velocity'] = np.column_stack([u, v, w])
grid['speed'] = np.linalg.norm(grid['velocity'], axis=1)
# Visualize with streamlines and contours
plotter = pv.Plotter()
# Add velocity magnitude contours on slices
slice_y = grid.slice(normal='y', origin=(0.5, 0.4, 0.3))
plotter.add_mesh(slice_y, scalars='speed', cmap='jet',
opacity=0.8, show_scalar_bar=True,
scalar_bar_args={'title': 'Velocity [m/s]', 'height': 0.7})
# Add streamlines
streamlines = grid.streamlines(
vectors='velocity',
source_center=(0.5, 0.4, 0),
source_radius=0.25,
n_points=30
)
plotter.add_mesh(streamlines.tube(radius=0.003), color='white')
plotter.show()
圧力コンター
# Add pressure field (example: stagnation and wake regions)
x_norm = (x - 0.5) / 0.5
y_norm = (y - 0.4) / 0.4
z_norm = (z - 0.3) / 0.3
# Pressure distribution around obstacle
pressure = 101325 + 5000 * (1 - np.sqrt(x_norm**2 + y_norm**2 + z_norm**2))
grid['pressure'] = pressure
# Create pressure isosurfaces
plotter = pv.Plotter()
contours = grid.contour(isosurfaces=10, scalars='pressure')
plotter.add_mesh(contours, cmap='coolwarm', opacity=0.7,
show_scalar_bar=True,
scalar_bar_args={'title': 'Pressure [Pa]'})
plotter.show()
乱流の可視化
# Turbulent kinetic energy (TKE) visualization
k_turb = 0.01 * grid['speed']**2 * np.random.rand(len(grid['speed']))
grid['TKE'] = k_turb
plotter = pv.Plotter()
# Volume rendering for turbulence
plotter.add_volume(grid, scalars='TKE', cmap='hot',
opacity='linear',
scalar_bar_args={'title': 'Turbulent Kinetic Energy [m²/s²]'})
# Add outline
plotter.add_mesh(grid.outline(), color='black', line_width=2)
plotter.show()
ポンプ形状の表示
# Load pump impeller geometry (assuming STL file)
# impeller = pv.read('pump_impeller.stl')
# Or create simple impeller geometry
def create_simple_impeller():
"""Create simplified pump impeller for demonstration."""
# Hub (cylinder)
hub = pv.Cylinder(radius=0.02, height=0.05, center=(0, 0, 0),
direction=(0, 0, 1), resolution=30)
# Blades (create 6 blades)
blades = pv.PolyData()
for i in range(6):
angle = i * 60
blade = pv.Plane(center=(0.04, 0, 0.025), direction=(0, 0, 1),
i_size=0.04, j_size=0.05)
blade.rotate_z(angle, point=(0, 0, 0.025))
blades += blade
impeller = hub + blades
return impeller
impeller = create_simple_impeller()
# Visualize with lighting
plotter = pv.Plotter()
plotter.add_mesh(impeller, color='lightblue', metallic=0.5,
roughness=0.5, show_edges=True)
plotter.add_light(pv.Light(position=(1, 1, 1), light_type='scene light'))
plotter.show()
複合可視化
# Comprehensive CFD visualization combining multiple techniques
plotter = pv.Plotter()
# Background mesh with velocity magnitude
plotter.add_mesh(grid.outline(), color='black', line_width=2)
# Slice through center showing velocity contours
center_slice = grid.slice(normal='z', origin=(0.5, 0.4, 0.3))
plotter.add_mesh(center_slice, scalars='speed', cmap='jet',
opacity=0.9, show_scalar_bar=True,
scalar_bar_args={'title': 'Velocity [m/s]',
'vertical': True,
'height': 0.7})
# Streamlines showing flow patterns
streamlines = grid.streamlines(
vectors='velocity',
source_center=(0.5, 0.4, 0.1),
source_radius=0.2,
n_points=25,
max_time=5.0
)
plotter.add_mesh(streamlines.tube(radius=0.002), color='white', opacity=0.8)
# Pressure isosurface highlighting high-pressure region
high_pressure = grid.threshold(value=103000, scalars='pressure')
plotter.add_mesh(high_pressure, color='red', opacity=0.3)
# Set camera and view
plotter.camera_position = 'xy'
plotter.show()
インタラクティブ機能
カメラ制御
plotter = pv.Plotter()
plotter.add_mesh(grid, scalars='pressure')
# Set camera position
plotter.camera_position = [
(2, 2, 2), # Camera position
(0.5, 0.4, 0.3), # Focal point
(0, 0, 1) # View up vector
]
# Or use preset views
# plotter.camera_position = 'xy' # Top view
# plotter.camera_position = 'xz' # Front view
# plotter.camera_position = 'yz' # Side view
# plotter.camera_position = 'iso' # Isometric
plotter.show()
複数のビューポート
# Create side-by-side comparison
plotter = pv.Plotter(shape=(1, 2))
# Left: velocity magnitude
plotter.subplot(0, 0)
plotter.add_mesh(grid, scalars='speed', cmap='jet')
plotter.add_text('Velocity Magnitude', font_size=12)
# Right: pressure
plotter.subplot(0, 1)
plotter.add_mesh(grid, scalars='pressure', cmap='coolwarm')
plotter.add_text('Pressure', font_size=12)
plotter.link_views() # Synchronize camera movements
plotter.show()
アニメーション
# Animate rotating view
plotter = pv.Plotter()
plotter.add_mesh(grid, scalars='speed', cmap='jet')
# Save as GIF or MP4
# plotter.open_gif('rotation.gif')
# plotter.open_movie('rotation.mp4')
# Create rotation animation
path = plotter.generate_orbital_path(n_points=36, shift=0)
plotter.orbit_on_path(path, write_frames=False)
エクスポートと保存
静止画像の保存
plotter = pv.Plotter(off_screen=True)
plotter.add_mesh(grid, scalars='pressure', cmap='coolwarm')
plotter.camera_position = 'iso'
# Save high-resolution image
plotter.screenshot('cfd_pressure.png', transparent_background=False,
window_size=[1920, 1080])
メッシュのエクスポート
# Save mesh with data for later use
grid.save('cfd_results.vtk')
# Export to other formats
grid.save('cfd_results.vtu') # VTK Unstructured Grid
grid.save('cfd_results.vtp') # VTK PolyData
ParaView へのエクスポート
PyVista のメッシュは VTK 互換であり、高度な後処理を行うため ParaView で直接開くことができます。
CFD 可視化のベストプラクティス
-
適切なカラーマップを選択します:
- 速度:
'jet'、'viridis'、'plasma' - 圧力/温度:
'coolwarm'、'RdBu_r' - 乱流:
'hot'、'inferno'
- 速度:
-
スケールを統一します:複数のケースを比較する際は、
clim(色の範囲)を設定します。 -
コンテキストを追加します:形状の輪郭、座標軸、スケールバーを含めます。
-
大規模なデータセット向けに最適化します:
- 間引きを使用します:
mesh.decimate(0.5)で点を減らします。 - LOD(詳細度)を有効にします:
plotter.enable_eye_dome_lighting()
- 間引きを使用します:
-
効果的にラベルを付けます:タイトルや、単位付きのスカラー凡例ラベルを追加します。
-
ライティングを検討します:3D の立体感を高めるため、カスタムライトを追加します。
-
透明度を適切に使用します:不透明なサーフェスと透明なボリュームを組み合わせます。
クイックリファレンス
import pyvista as pv
import numpy as np
# Create mesh
grid = pv.ImageData(dimensions=(50, 40, 30))
grid.spacing = (0.02, 0.02, 0.02)
# Add scalar field
grid['pressure'] = np.random.rand(grid.n_points)
# Add vector field
grid['velocity'] = np.random.rand(grid.n_points, 3)
# Create plotter
plotter = pv.Plotter()
# Add mesh with options
plotter.add_mesh(grid,
scalars='pressure', # Scalar field name
cmap='coolwarm', # Colormap
opacity=0.8, # Transparency
show_edges=True, # Show cell edges
show_scalar_bar=True, # Show colorbar
clim=[0, 1]) # Color limits
# Add streamlines
streamlines = grid.streamlines(vectors='velocity', n_points=20)
plotter.add_mesh(streamlines.tube(radius=0.001), color='white')
# Slice
slice_z = grid.slice(normal='z')
plotter.add_mesh(slice_z, scalars='pressure')
# Contour isosurfaces
contours = grid.contour(isosurfaces=10, scalars='pressure')
plotter.add_mesh(contours, opacity=0.5)
# Camera and view
plotter.camera_position = 'iso'
plotter.add_axes()
plotter.show_grid()
# Display
plotter.show()
# Save
plotter.screenshot('output.png')
関連項目
examples.py- CFD 可視化の完全な実用例reference.md- PyVista API とオプションの詳細リファレンス- PyVista ドキュメント
- PyVista サンプルギャラリー
- VTK ファイル形式