April 16, 2025

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