import numpy as np
import gmsh
def create_box(x_len, y_len, z_len, mesh_size, fpath):
print("generate mesh")
gmsh.initialize()
gmsh.model.add('plate')
gmsh.model.occ.addBox(0, 0, 0, x_len, y_len, z_len)
gmsh.model.occ.synchronize()
gmsh.model.mesh.setSize(gmsh.model.getEntities(0), mesh_size)
gmsh.model.mesh.setOrder(1)
gmsh.model.mesh.generate(3)
gmsh.write(fpath)
gmsh.finalize()
def create_box_transfinite(x_len, y_len, z_len, nx, ny, nz, fpath):
gmsh.initialize()
gmsh.model.add("box")
# Create the box
box = gmsh.model.occ.addBox(0, 0, 0, x_len, y_len, z_len)
gmsh.model.occ.synchronize()
# Get all edges and set transfinite lines (structured control)
edges = gmsh.model.getEntities(dim=1)
for edge in edges:
gmsh.model.mesh.setTransfiniteCurve(edge[1], max(nx, ny, nz))
# Set transfinite surfaces
surfaces = gmsh.model.getEntities(dim=2)
for surface in surfaces:
gmsh.model.mesh.setTransfiniteSurface(surface[1])
gmsh.model.mesh.setRecombine(2, surface[1]) # Optional: quadrangles
# Set transfinite volume
volumes = gmsh.model.getEntities(dim=3)
for volume in volumes:
gmsh.model.mesh.setTransfiniteVolume(volume[1])
gmsh.model.mesh.setOrder(1)
gmsh.model.mesh.generate(3)
gmsh.write(fpath)
gmsh.finalize()
def create_box_with_field(x_len, y_len, z_len,
fine_region_bounds,
fine_size, coarse_size,
fpath):
"""
Create a mesh with finer mesh in a specified region using Fields.
Parameters:
x_len, y_len, z_len: Size of the box
fine_region_bounds: (xmin, xmax, ymin, ymax, zmin, zmax) for fine mesh zone
fine_size: Mesh size in the fine region
coarse_size: Mesh size outside the fine region
fpath: Output file path
"""
gmsh.initialize()
gmsh.model.add("box_with_field")
# Create the box geometry
gmsh.model.occ.addBox(0, 0, 0, x_len, y_len, z_len)
gmsh.model.occ.synchronize()
# Define the field (Box field)
field_id = 1
gmsh.model.mesh.field.add("Box", field_id)
xmin, xmax, ymin, ymax, zmin, zmax = fine_region_bounds
gmsh.model.mesh.field.setNumber(field_id, "VIn", fine_size)
gmsh.model.mesh.field.setNumber(field_id, "VOut", coarse_size)
gmsh.model.mesh.field.setNumber(field_id, "XMin", xmin)
gmsh.model.mesh.field.setNumber(field_id, "XMax", xmax)
gmsh.model.mesh.field.setNumber(field_id, "YMin", ymin)
gmsh.model.mesh.field.setNumber(field_id, "YMax", ymax)
gmsh.model.mesh.field.setNumber(field_id, "ZMin", zmin)
gmsh.model.mesh.field.setNumber(field_id, "ZMax", zmax)
# Activate the field
gmsh.model.mesh.field.setAsBackgroundMesh(field_id)
# Mesh settings
gmsh.model.mesh.setOrder(1)
gmsh.model.mesh.generate(3)
gmsh.write(fpath)
gmsh.finalize()
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(
description=''
)
parser.add_argument(
'--mesh_size', '-MS', type=float, default=0.2, help=''
)
parser.add_argument(
'--mesh_path', '-MP', type=str, default="plate.msh", help=''
)
args = parser.parse_args()
x_len = 8.0
y_len = 6.0
# z_len = 4.0
z_len = 2.0
mesh_size = args.mesh_size
create_box(x_len, y_len, z_len, mesh_size, args.mesh_path)
# create_box_transfinite(x_len, y_len, z_len, mesh_size, args.mesh_path)
import gmsh
import sys
gmsh.initialize()
gmsh.model.add("refined_y_le_0.1")
# 1. ジオメトリ:立方体ドメイン(0 ≤ x,y,z ≤ 1)
gmsh.model.occ.addBox(0, 0, 0, 1, 1, 1, tag=1)
gmsh.model.occ.synchronize()
# 2. 仮想的な y=0.1 の平面を追加(距離フィールドの参照に使うだけ)
# 面は xz平面上に作成し、y=0.1 に配置
rectangle = gmsh.model.occ.addRectangle(0, 0, 0, 1, 1) # x=0〜1, y=0, z=0〜1
plane = gmsh.model.occ.addPlaneSurface([rectangle])
gmsh.model.occ.translate([(2, plane)], 0, 0.1, 0) # y=0.1 に移動
gmsh.model.occ.synchronize()
# 3. 距離フィールドを作成(y=0.1面からの距離)
gmsh.model.mesh.field.add("Distance", 1)
gmsh.model.mesh.field.setNumbers(1, "FacesList", [plane])
# 4. 距離に基づきサイズを変化させるフィールドを作成
gmsh.model.mesh.field.add("Threshold", 2)
gmsh.model.mesh.field.setNumber(2, "InField", 1)
gmsh.model.mesh.field.setNumber(2, "SizeMin", 0.05) # y ≤ 0.1:細かい
gmsh.model.mesh.field.setNumber(2, "SizeMax", 0.3) # y > 0.1:粗い
gmsh.model.mesh.field.setNumber(2, "DistMin", 0.0) # y = 0.1 に対応
gmsh.model.mesh.field.setNumber(2, "DistMax", 0.0) # それ以外には即 SizeMax
# (DistMax > 0 にすればスムーズに遷移できます)
# 5. フィールドをバックグラウンドメッシュとして使用
gmsh.model.mesh.field.setAsBackgroundMesh(2)
# 6. 3Dメッシュ生成
gmsh.model.mesh.generate(3)
gmsh.write("refined_y_le_0.1.msh")
# オプション:GUIで確認
# gmsh.fltk.run()
gmsh.finalize()
def nodes_and_elements_stats(self, dst_path: str):
# ノードの座標
node_points = self.mesh.p.T # shape = (n_points, 3)
tree_nodes = cKDTree(node_points)
dists_node, _ = tree_nodes.query(node_points, k=2)
node_nearest_dists = dists_node[:, 1] # 最近傍ノード距離
# 要素の重心
element_centers = np.mean(self.mesh.p[:, self.mesh.t], axis=1).T
tree_elems = cKDTree(element_centers)
dists_elem, _ = tree_elems.query(element_centers, k=2)
element_nearest_dists = dists_elem[:, 1] # 最近傍要素距離
# 統計表示
print("=== ノード間距離 ===")
print(f"min: {np.min(node_nearest_dists):.4f}")
print(f"max: {np.max(node_nearest_dists):.4f}")
print(f"mean: {np.mean(node_nearest_dists):.4f}")
print(f"median: {np.median(node_nearest_dists):.4f}")
print(f"std: {np.std(node_nearest_dists):.4f}")
print("\n=== 要素間距離(重心間) ===")
print(f"min: {np.min(element_nearest_dists):.4f}")
print(f"max: {np.max(element_nearest_dists):.4f}")
print(f"mean: {np.mean(element_nearest_dists):.4f}")
print(f"median: {np.median(element_nearest_dists):.4f}")
print(f"std: {np.std(element_nearest_dists):.4f}")
# ヒストグラム描画
plt.clf()
fig, axs = plt.subplots(1, 2, figsize=(14, 6))
axs[0].hist(node_nearest_dists, bins=30, edgecolor='black')
axs[0].set_title("Nearest Neighbor Distance (Nodes)")
axs[0].set_xlabel("Distance")
axs[0].set_ylabel("Count")
axs[0].grid(True)
axs[1].hist(element_nearest_dists, bins=30, edgecolor='black')
axs[1].set_title("Nearest Neighbor Distance (Element Centers)")
axs[1].set_xlabel("Distance")
axs[1].set_ylabel("Count")
axs[1].grid(True)
fig.tight_layout()
fig.savefig(f"{dst_path}/node_and_element_distance_histogram.jpg")
plt.close("all")