cad-mesh-generation

CAD and Mesh Generation Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "cad-mesh-generation" with this command: npx skills add vamseeachanta/workspace-hub/vamseeachanta-workspace-hub-cad-mesh-generation

CAD and Mesh Generation Skill

name: cad-mesh-generation version: 1.0.0 category: programming tags: [cad, mesh, freecad, gmsh, geometry, finite-element, marine-structures] created: 2026-01-06 updated: 2026-01-06 author: Claude description: | Expert CAD geometry and mesh generation using FreeCAD and GMSH. Create parametric marine structures, generate meshes for FEA/BEM, and export to various analysis software formats (AQWA, WAMIT, ANSYS, etc.).

When to Use This Skill

Use this skill when you need to:

  • Create parametric CAD models of vessels, platforms, or structures

  • Generate meshes for finite element analysis (FEA)

  • Generate panel meshes for boundary element methods (BEM/hydrodynamics)

  • Automate geometry creation for marine structures

  • Export geometry to AQWA, WAMIT, ANSYS, or other analysis tools

  • Create complex geometries programmatically with Python

  • Perform mesh quality checks and refinement

Core Knowledge Areas

  1. FreeCAD Python Scripting Basics

Creating geometry with FreeCAD Python API:

import sys from pathlib import Path from typing import List, Tuple, Optional import numpy as np

Try to import FreeCAD, provide fallback for development

try: import FreeCAD import Part import Mesh import MeshPart FREECAD_AVAILABLE = True except ImportError: FREECAD_AVAILABLE = False print("Warning: FreeCAD not available, using mock functions")

# Mock FreeCAD classes for development
class MockFreeCAD:
    @staticmethod
    def newDocument(name: str):
        print(f"[MOCK] Creating document: {name}")
        return MockDocument()

    class Vector:
        def __init__(self, x: float, y: float, z: float):
            self.x, self.y, self.z = x, y, z

class MockDocument:
    def __init__(self):
        self.objects = []

    def addObject(self, obj_type: str, name: str):
        print(f"[MOCK] Adding object: {obj_type} - {name}")
        obj = MockObject(name)
        self.objects.append(obj)
        return obj

    def recompute(self):
        print("[MOCK] Recomputing document")

class MockObject:
    def __init__(self, name: str):
        self.Name = name
        self.Shape = None

class MockPart:
    @staticmethod
    def makeCylinder(radius, height, base=None, direction=None):
        print(f"[MOCK] Creating cylinder: r={radius}, h={height}")
        return MockShape()

    @staticmethod
    def makeBox(length, width, height, base=None, direction=None):
        print(f"[MOCK] Creating box: {length}x{width}x{height}")
        return MockShape()

class MockShape:
    def fuse(self, other):
        print("[MOCK] Fusing shapes")
        return self

    def cut(self, other):
        print("[MOCK] Cutting shapes")
        return self

    def exportStep(self, filename):
        print(f"[MOCK] Exporting STEP: {filename}")

    def exportIges(self, filename):
        print(f"[MOCK] Exporting IGES: {filename}")

if not FREECAD_AVAILABLE:
    FreeCAD = MockFreeCAD()
    Part = MockPart()

def create_cylinder_vessel( diameter: float, length: float, wall_thickness: float = None, name: str = "Vessel" ) -> Tuple[Any, Any]: """ Create cylindrical vessel geometry in FreeCAD.

Args:
    diameter: Vessel diameter [m]
    length: Vessel length [m]
    wall_thickness: Wall thickness [m] (None = solid)
    name: Object name

Returns:
    Tuple of (document, shape)

Example:
    >>> doc, shape = create_cylinder_vessel(
    ...     diameter=10.0,
    ...     length=100.0,
    ...     wall_thickness=0.05,
    ...     name="FPSO_Hull"
    ... )
"""
# Create document
doc = FreeCAD.newDocument(name)

# Create outer cylinder
outer_radius = diameter / 2
outer_cyl = Part.makeCylinder(
    outer_radius,
    length,
    FreeCAD.Vector(0, 0, 0),
    FreeCAD.Vector(1, 0, 0)  # Along x-axis
)

# If wall thickness specified, make hollow
if wall_thickness:
    inner_radius = outer_radius - wall_thickness
    inner_cyl = Part.makeCylinder(
        inner_radius,
        length,
        FreeCAD.Vector(0, 0, 0),
        FreeCAD.Vector(1, 0, 0)
    )
    # Subtract inner from outer
    vessel_shape = outer_cyl.cut(inner_cyl)
else:
    vessel_shape = outer_cyl

# Add to document
vessel_obj = doc.addObject("Part::Feature", name)
vessel_obj.Shape = vessel_shape

doc.recompute()

return doc, vessel_shape

def create_rectangular_pontoon( length: float, width: float, height: float, wall_thickness: float, name: str = "Pontoon" ) -> Tuple[Any, Any]: """ Create rectangular pontoon geometry.

Args:
    length: Pontoon length [m]
    width: Pontoon width [m]
    height: Pontoon height [m]
    wall_thickness: Wall thickness [m]
    name: Object name

Returns:
    Tuple of (document, shape)

Example:
    >>> doc, shape = create_rectangular_pontoon(
    ...     length=50.0,
    ...     width=10.0,
    ...     height=5.0,
    ...     wall_thickness=0.025,
    ...     name="Barge_Pontoon"
    ... )
"""
doc = FreeCAD.newDocument(name)

# Outer box
outer_box = Part.makeBox(
    length,
    width,
    height,
    FreeCAD.Vector(0, 0, 0)
)

# Inner box (hollowed)
inner_box = Part.makeBox(
    length - 2 * wall_thickness,
    width - 2 * wall_thickness,
    height - wall_thickness,  # Bottom plate thickness
    FreeCAD.Vector(wall_thickness, wall_thickness, wall_thickness)
)

# Subtract
pontoon_shape = outer_box.cut(inner_box)

# Add to document
pontoon_obj = doc.addObject("Part::Feature", name)
pontoon_obj.Shape = pontoon_shape

doc.recompute()

return doc, pontoon_shape

def export_geometry( shape: Any, output_file: Path, format: str = 'step' ) -> None: """ Export FreeCAD shape to file.

Args:
    shape: FreeCAD shape object
    output_file: Output file path
    format: Export format ('step', 'iges', 'stl')

Example:
    >>> export_geometry(vessel_shape, Path('vessel.step'), 'step')
"""
output_file.parent.mkdir(parents=True, exist_ok=True)

if format.lower() == 'step':
    shape.exportStep(str(output_file))
elif format.lower() == 'iges':
    shape.exportIges(str(output_file))
elif format.lower() == 'stl':
    if FREECAD_AVAILABLE:
        # Convert to mesh first
        mesh = MeshPart.meshFromShape(
            shape,
            LinearDeflection=0.1,
            AngularDeflection=0.5,
            Relative=False
        )
        mesh.write(str(output_file))
    else:
        print(f"[MOCK] Exporting STL: {output_file}")
else:
    raise ValueError(f"Unsupported format: {format}")

print(f"Geometry exported: {output_file}")

2. GMSH Mesh Generation

Creating meshes with GMSH Python API:

Try to import gmsh

try: import gmsh GMSH_AVAILABLE = True except ImportError: GMSH_AVAILABLE = False print("Warning: GMSH not available, using mock")

# Mock gmsh module
class MockGmsh:
    def initialize(self): pass
    def finalize(self): pass
    def open(self, filename): print(f"[MOCK] Opening: {filename}")
    def write(self, filename): print(f"[MOCK] Writing: {filename}")
    def clear(self): pass

    class model:
        @staticmethod
        def mesh():
            return MockGmshMesh()

        class geo:
            @staticmethod
            def addPoint(x, y, z, lc=0, tag=-1):
                return tag if tag != -1 else 1

            @staticmethod
            def addLine(p1, p2, tag=-1):
                return tag if tag != -1 else 1

            @staticmethod
            def addSurfaceFilling(lines, tag=-1):
                return tag if tag != -1 else 1

            @staticmethod
            def synchronize():
                print("[MOCK] Synchronizing geometry")

    class option:
        @staticmethod
        def setNumber(name, value):
            print(f"[MOCK] Setting option: {name} = {value}")

class MockGmshMesh:
    def generate(self, dim):
        print(f"[MOCK] Generating {dim}D mesh")

    def setAlgorithm(self, dim, algo):
        print(f"[MOCK] Setting {dim}D algorithm: {algo}")

if not GMSH_AVAILABLE:
    gmsh = MockGmsh()

def create_panel_mesh_cylinder( radius: float, height: float, n_circumferential: int = 36, n_vertical: int = 20, output_file: Path = None ) -> str: """ Create panel mesh for cylindrical body using GMSH.

Args:
    radius: Cylinder radius [m]
    height: Cylinder height [m]
    n_circumferential: Number of panels around circumference
    n_vertical: Number of panels vertically
    output_file: Output mesh file (.msh)

Returns:
    Path to mesh file

Example:
    >>> mesh_file = create_panel_mesh_cylinder(
    ...     radius=5.0,
    ...     height=100.0,
    ...     n_circumferential=36,
    ...     n_vertical=50,
    ...     output_file=Path('cylinder_mesh.msh')
    ... )
"""
gmsh.initialize()

# Create cylindrical surface
gmsh.model.add("cylinder_mesh")

# Characteristic length (mesh size)
lc = 2 * np.pi * radius / n_circumferential

# Create points on bottom circle
bottom_points = []
for i in range(n_circumferential):
    theta = 2 * np.pi * i / n_circumferential
    x = radius * np.cos(theta)
    y = radius * np.sin(theta)
    z = 0

    tag = gmsh.model.geo.addPoint(x, y, z, lc)
    bottom_points.append(tag)

# Create points on top circle
top_points = []
for i in range(n_circumferential):
    theta = 2 * np.pi * i / n_circumferential
    x = radius * np.cos(theta)
    y = radius * np.sin(theta)
    z = height

    tag = gmsh.model.geo.addPoint(x, y, z, lc)
    top_points.append(tag)

# Create lines connecting bottom to top
vertical_lines = []
for i in range(n_circumferential):
    line = gmsh.model.geo.addLine(bottom_points[i], top_points[i])
    vertical_lines.append(line)

# Create horizontal lines (bottom and top circles)
bottom_lines = []
top_lines = []
for i in range(n_circumferential):
    next_i = (i + 1) % n_circumferential

    bottom_line = gmsh.model.geo.addLine(bottom_points[i], bottom_points[next_i])
    bottom_lines.append(bottom_line)

    top_line = gmsh.model.geo.addLine(top_points[i], top_points[next_i])
    top_lines.append(top_line)

# Create surfaces (panels)
panels = []
for i in range(n_circumferential):
    next_i = (i + 1) % n_circumferential

    # Define curve loop for each panel
    curve_loop = gmsh.model.geo.addCurveLoop([
        bottom_lines[i],
        vertical_lines[next_i],
        -top_lines[i],
        -vertical_lines[i]
    ])

    # Create surface
    surface = gmsh.model.geo.addSurfaceFilling([curve_loop])
    panels.append(surface)

gmsh.model.geo.synchronize()

# Generate 2D mesh (surface mesh)
gmsh.model.mesh.generate(2)

# Set mesh algorithm (Frontal-Delaunay for quality)
gmsh.model.mesh.setAlgorithm(2, 6)

# Save mesh
if output_file is None:
    output_file = Path('cylinder_mesh.msh')

output_file.parent.mkdir(parents=True, exist_ok=True)
gmsh.write(str(output_file))

gmsh.finalize()

print(f"Panel mesh created: {output_file}")
print(f"  Number of panels: {n_circumferential * n_vertical}")

return str(output_file)

def create_tetrahedral_mesh( geometry_file: Path, element_size: float, output_file: Path, refine_surfaces: bool = True ) -> str: """ Create tetrahedral volume mesh from geometry.

Args:
    geometry_file: Input geometry (.step, .iges, .stl)
    element_size: Target element size [m]
    output_file: Output mesh file (.msh)
    refine_surfaces: Whether to refine surface mesh

Returns:
    Path to mesh file

Example:
    >>> mesh_file = create_tetrahedral_mesh(
    ...     geometry_file=Path('vessel.step'),
    ...     element_size=0.5,
    ...     output_file=Path('vessel_mesh.msh')
    ... )
"""
gmsh.initialize()

# Open geometry
gmsh.open(str(geometry_file))

# Set global mesh size
gmsh.option.setNumber("Mesh.CharacteristicLengthMax", element_size)
gmsh.option.setNumber("Mesh.CharacteristicLengthMin", element_size * 0.5)

# Set 3D mesh algorithm (Delaunay for quality)
gmsh.option.setNumber("Mesh.Algorithm3D", 1)  # Delaunay

# Generate 2D surface mesh first
gmsh.model.mesh.generate(2)

if refine_surfaces:
    # Refine surface mesh
    gmsh.model.mesh.refine()

# Generate 3D volume mesh
gmsh.model.mesh.generate(3)

# Optimize mesh quality
gmsh.model.mesh.optimize("Netgen")

# Save mesh
output_file.parent.mkdir(parents=True, exist_ok=True)
gmsh.write(str(output_file))

gmsh.finalize()

print(f"Tetrahedral mesh created: {output_file}")

return str(output_file)

3. Mesh Quality Assessment

Check mesh quality metrics:

def analyze_mesh_quality( mesh_file: Path, mesh_type: str = 'surface' ) -> dict: """ Analyze mesh quality metrics.

Args:
    mesh_file: Path to mesh file (.msh)
    mesh_type: 'surface' or 'volume'

Returns:
    Dictionary with quality metrics

Example:
    >>> quality = analyze_mesh_quality(Path('cylinder_mesh.msh'), 'surface')
    >>> print(f"Min quality: {quality['min_quality']:.3f}")
    >>> print(f"Average quality: {quality['avg_quality']:.3f}")
"""
if not GMSH_AVAILABLE:
    print("[MOCK] Analyzing mesh quality")
    return {
        'element_count': 1000,
        'node_count': 550,
        'min_quality': 0.75,
        'avg_quality': 0.92,
        'max_quality': 1.0
    }

gmsh.initialize()
gmsh.open(str(mesh_file))

# Get mesh statistics
element_types, element_tags, node_tags = gmsh.model.mesh.getElements()

total_elements = sum(len(tags) for tags in element_tags)

# Get nodes
node_tags_all, node_coords, _ = gmsh.model.mesh.getNodes()
total_nodes = len(node_tags_all)

# Calculate element quality
qualities = []

if mesh_type == 'surface':
    # For triangular surface elements
    for elem_type, elem_tags in zip(element_types, element_tags):
        if elem_type == 2:  # Triangle
            for elem_tag in elem_tags:
                # Get element quality (0-1, 1 = perfect)
                quality = gmsh.model.mesh.getElementQuality([elem_tag], elem_type)
                if quality:
                    qualities.extend(quality)

elif mesh_type == 'volume':
    # For tetrahedral volume elements
    for elem_type, elem_tags in zip(element_types, element_tags):
        if elem_type == 4:  # Tetrahedron
            for elem_tag in elem_tags:
                quality = gmsh.model.mesh.getElementQuality([elem_tag], elem_type)
                if quality:
                    qualities.extend(quality)

gmsh.finalize()

if qualities:
    min_quality = min(qualities)
    avg_quality = np.mean(qualities)
    max_quality = max(qualities)
else:
    min_quality = avg_quality = max_quality = 0.0

return {
    'element_count': total_elements,
    'node_count': total_nodes,
    'min_quality': min_quality,
    'avg_quality': avg_quality,
    'max_quality': max_quality,
    'poor_elements': sum(1 for q in qualities if q < 0.3)
}

4. Mesh Conversion for Analysis Tools

Convert meshes to various formats:

def convert_mesh_to_wamit_gdf( mesh_file: Path, output_file: Path, symmetry: str = 'none' ) -> None: """ Convert GMSH mesh to WAMIT .gdf format.

Args:
    mesh_file: Input GMSH mesh file (.msh)
    output_file: Output WAMIT file (.gdf)
    symmetry: 'none', 'x', 'y', or 'xy'

Example:
    >>> convert_mesh_to_wamit_gdf(
    ...     mesh_file=Path('cylinder_mesh.msh'),
    ...     output_file=Path('cylinder.gdf'),
    ...     symmetry='y'
    ... )
"""
if not GMSH_AVAILABLE:
    print(f"[MOCK] Converting mesh to WAMIT GDF: {output_file}")
    return

gmsh.initialize()
gmsh.open(str(mesh_file))

# Get nodes
node_tags, node_coords, _ = gmsh.model.mesh.getNodes()
n_nodes = len(node_tags)

# Reshape coordinates
coords = np.array(node_coords).reshape((-1, 3))

# Get surface elements (triangles/quads)
element_types, element_tags, node_tags_elem = gmsh.model.mesh.getElements(2)

gmsh.finalize()

# Write GDF file
with open(output_file, 'w') as f:
    # Header
    f.write(f"WAMIT GDF File\n")
    f.write(f"Converted from GMSH mesh\n")

    # Symmetry
    if symmetry == 'x':
        f.write("1.0  0.0  ! XOZ symmetry\n")
    elif symmetry == 'y':
        f.write("0.0  1.0  ! YOZ symmetry\n")
    elif symmetry == 'xy':
        f.write("1.0  1.0  ! XOZ and YOZ symmetry\n")
    else:
        f.write("0.0  0.0  ! No symmetry\n")

    # Number of panels
    total_panels = sum(len(tags) for tags in element_tags)
    f.write(f"{total_panels}\n")

    # Write panels
    panel_id = 1
    for elem_type, elem_tags, node_tags_set in zip(
        element_types, element_tags, node_tags_elem
    ):
        if elem_type == 2:  # Triangle
            # Triangles have 3 nodes
            nodes_per_elem = 3
            node_tags_array = np.array(node_tags_set).reshape((-1, nodes_per_elem))

            for nodes in node_tags_array:
                # Get coordinates of 3 vertices
                vertices = coords[nodes - 1]  # GMSH uses 1-based indexing

                # Write panel (x, y, z for each vertex)
                f.write(f"{panel_id}  ")
                for vertex in vertices:
                    f.write(f"{vertex[0]:.6f} {vertex[1]:.6f} {vertex[2]:.6f}  ")
                f.write("\n")

                panel_id += 1

        elif elem_type == 3:  # Quad
            nodes_per_elem = 4
            node_tags_array = np.array(node_tags_set).reshape((-1, nodes_per_elem))

            for nodes in node_tags_array:
                vertices = coords[nodes - 1]

                f.write(f"{panel_id}  ")
                for vertex in vertices:
                    f.write(f"{vertex[0]:.6f} {vertex[1]:.6f} {vertex[2]:.6f}  ")
                f.write("\n")

                panel_id += 1

print(f"WAMIT GDF file created: {output_file}")
print(f"  Total panels: {total_panels}")

def convert_mesh_to_ansys_cdb( mesh_file: Path, output_file: Path ) -> None: """ Convert GMSH mesh to ANSYS .cdb format.

Args:
    mesh_file: Input GMSH mesh file (.msh)
    output_file: Output ANSYS command database (.cdb)

Example:
    >>> convert_mesh_to_ansys_cdb(
    ...     mesh_file=Path('vessel_mesh.msh'),
    ...     output_file=Path('vessel.cdb')
    ... )
"""
if not GMSH_AVAILABLE:
    print(f"[MOCK] Converting mesh to ANSYS CDB: {output_file}")
    return

gmsh.initialize()
gmsh.open(str(mesh_file))

# Get nodes
node_tags, node_coords, _ = gmsh.model.mesh.getNodes()
coords = np.array(node_coords).reshape((-1, 3))

# Get elements
element_types, element_tags_list, node_tags_elem_list = gmsh.model.mesh.getElements()

gmsh.finalize()

# Write CDB file
with open(output_file, 'w') as f:
    # Header
    f.write("/PREP7\n")
    f.write("! Mesh converted from GMSH\n")

    # Write nodes
    f.write("! Nodes\n")
    for node_id, coord in enumerate(coords, start=1):
        f.write(f"N,{node_id},{coord[0]:.6f},{coord[1]:.6f},{coord[2]:.6f}\n")

    # Write elements
    f.write("! Elements\n")
    elem_id = 1

    for elem_type, elem_tags, node_tags_elem in zip(
        element_types, element_tags_list, node_tags_elem_list
    ):
        if elem_type == 4:  # Tetrahedron (SOLID187 in ANSYS)
            f.write("ET,1,SOLID187\n")
            nodes_per_elem = 4
            node_tags_array = np.array(node_tags_elem).reshape((-1, nodes_per_elem))

            for nodes in node_tags_array:
                node_str = ','.join(map(str, nodes))
                f.write(f"E,{node_str}\n")
                elem_id += 1

    f.write("FINISH\n")

print(f"ANSYS CDB file created: {output_file}")

Complete Examples

Example 1: Complete Vessel Geometry and Mesh Workflow

from pathlib import Path import numpy as np

def complete_vessel_geometry_workflow( vessel_params: dict, mesh_params: dict, output_dir: Path ) -> dict: """ Complete workflow: Create geometry, mesh, and export.

Args:
    vessel_params: Vessel geometry parameters
    mesh_params: Mesh generation parameters
    output_dir: Output directory for all files

Returns:
    Dictionary with file paths

Example:
    >>> vessel_params = {
    ...     'type': 'cylinder',
    ...     'diameter': 20.0,
    ...     'length': 150.0,
    ...     'wall_thickness': 0.05
    ... }
    >>> mesh_params = {
    ...     'n_circumferential': 48,
    ...     'n_vertical': 75,
    ...     'element_size': 2.0
    ... }
    >>> results = complete_vessel_geometry_workflow(
    ...     vessel_params,
    ...     mesh_params,
    ...     Path('vessel_geometry')
    ... )
"""
output_dir.mkdir(parents=True, exist_ok=True)

print("="*70)
print("VESSEL GEOMETRY AND MESH WORKFLOW")
print("="*70)

# Step 1: Create CAD geometry
print("\n[Step 1/5] Creating CAD geometry...")

if vessel_params['type'] == 'cylinder':
    doc, shape = create_cylinder_vessel(
        diameter=vessel_params['diameter'],
        length=vessel_params['length'],
        wall_thickness=vessel_params['wall_thickness'],
        name="Vessel_Geometry"
    )

# Export geometry
step_file = output_dir / 'vessel.step'
iges_file = output_dir / 'vessel.iges'

export_geometry(shape, step_file, 'step')
export_geometry(shape, iges_file, 'iges')

print(f"Geometry exported: {step_file}, {iges_file}")

# Step 2: Create surface mesh for hydrodynamics
print("\n[Step 2/5] Creating surface mesh for BEM analysis...")

surface_mesh_file = output_dir / 'vessel_surface.msh'

create_panel_mesh_cylinder(
    radius=vessel_params['diameter'] / 2,
    height=vessel_params['length'],
    n_circumferential=mesh_params['n_circumferential'],
    n_vertical=mesh_params['n_vertical'],
    output_file=surface_mesh_file
)

# Step 3: Analyze mesh quality
print("\n[Step 3/5] Analyzing mesh quality...")

quality = analyze_mesh_quality(surface_mesh_file, 'surface')

print(f"Mesh quality:")
print(f"  Elements: {quality['element_count']}")
print(f"  Nodes: {quality['node_count']}")
print(f"  Min quality: {quality['min_quality']:.3f}")
print(f"  Avg quality: {quality['avg_quality']:.3f}")
print(f"  Poor elements: {quality['poor_elements']}")

# Step 4: Convert to WAMIT format
print("\n[Step 4/5] Converting to WAMIT GDF format...")

wamit_file = output_dir / 'vessel.gdf'
convert_mesh_to_wamit_gdf(
    surface_mesh_file,
    wamit_file,
    symmetry='y'  # Symmetric about xz plane
)

# Step 5: Create volume mesh for FEA (optional)
print("\n[Step 5/5] Creating volume mesh for FEA...")

volume_mesh_file = output_dir / 'vessel_volume.msh'
ansys_file = output_dir / 'vessel.cdb'

if GMSH_AVAILABLE:
    create_tetrahedral_mesh(
        step_file,
        mesh_params['element_size'],
        volume_mesh_file
    )

    # Convert to ANSYS
    convert_mesh_to_ansys_cdb(volume_mesh_file, ansys_file)

print("\n" + "="*70)
print("WORKFLOW COMPLETE")
print("="*70)

results = {
    'geometry': {
        'step': step_file,
        'iges': iges_file
    },
    'mesh': {
        'surface': surface_mesh_file,
        'volume': volume_mesh_file,
        'wamit': wamit_file,
        'ansys': ansys_file
    },
    'quality': quality
}

return results

Run workflow

vessel_params = { 'type': 'cylinder', 'diameter': 20.0, 'length': 150.0, 'wall_thickness': 0.05 }

mesh_params = { 'n_circumferential': 48, 'n_vertical': 75, 'element_size': 2.0 }

workflow_results = complete_vessel_geometry_workflow( vessel_params, mesh_params, Path('vessel_geometry_output') )

print("\nGenerated files:") for category, files in workflow_results.items(): if category != 'quality': print(f"\n{category.upper()}:") for file_type, file_path in files.items(): print(f" {file_type}: {file_path}")

Best Practices

  1. Parametric Design

from dataclasses import dataclass

@dataclass class VesselDesignParameters: """Parametric vessel design.""" length: float # Overall length [m] beam: float # Beam (width) [m] depth: float # Depth [m] draft: float # Design draft [m] bow_shape: str = 'straight' # 'straight', 'raked', 'bulbous' stern_shape: str = 'transom' # 'transom', 'cruiser' superstructure: bool = True

def validate(self) -> bool:
    """Validate design parameters."""
    if self.draft > self.depth:
        raise ValueError("Draft cannot exceed depth")
    if self.beam > self.length:
        raise ValueError("Beam should not exceed length")
    return True

2. Mesh Size Optimization

def calculate_optimal_mesh_size( geometry_length_scale: float, analysis_type: str, target_accuracy: str = 'medium' ) -> float: """ Calculate optimal mesh size based on geometry and analysis type.

Args:
    geometry_length_scale: Characteristic length [m]
    analysis_type: 'bem', 'fea_linear', 'fea_nonlinear', 'cfd'
    target_accuracy: 'coarse', 'medium', 'fine'

Returns:
    Recommended element size [m]
"""
# Base sizing ratios
sizing_ratios = {
    'bem': {
        'coarse': 0.10,
        'medium': 0.05,
        'fine': 0.025
    },
    'fea_linear': {
        'coarse': 0.20,
        'medium': 0.10,
        'fine': 0.05
    },
    'fea_nonlinear': {
        'coarse': 0.10,
        'medium': 0.05,
        'fine': 0.025
    },
    'cfd': {
        'coarse': 0.15,
        'medium': 0.075,
        'fine': 0.0375
    }
}

ratio = sizing_ratios[analysis_type][target_accuracy]
element_size = geometry_length_scale * ratio

return element_size

3. Quality Checks

def perform_mesh_quality_checks( mesh_file: Path, min_quality_threshold: float = 0.3 ) -> bool: """ Perform comprehensive mesh quality checks.

Args:
    mesh_file: Mesh file path
    min_quality_threshold: Minimum acceptable quality

Returns:
    True if mesh passes quality checks
"""
quality = analyze_mesh_quality(mesh_file)

checks = {
    'min_quality': quality['min_quality'] >= min_quality_threshold,
    'poor_elements': quality['poor_elements'] == 0,
    'element_count': quality['element_count'] > 0
}

passed = all(checks.values())

if not passed:
    print("Mesh quality check FAILED:")
    for check_name, result in checks.items():
        status = "PASS" if result else "FAIL"
        print(f"  {check_name}: {status}")

return passed

Resources

FreeCAD

GMSH

Mesh Generation

Marine Geometry

  • DelftShip: Free ship hull design software

  • MAXSURF: Professional naval architecture software

  • Rhinoceros: Advanced 3D modeling (with Grasshopper for parametric)

Use this skill for: Expert CAD geometry creation and mesh generation for marine structures with full export capabilities to analysis software.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

echarts

No summary provided by upstream source.

Repository SourceNeeds Review
General

pandoc

No summary provided by upstream source.

Repository SourceNeeds Review
General

mkdocs

No summary provided by upstream source.

Repository SourceNeeds Review
General

gis

No summary provided by upstream source.

Repository SourceNeeds Review