Skip to main content
Glama

Hardware MCP Server

run_heat_transfer.py9.43 kB
from fipy import Grid3D, CellVariable, TransientTerm, DiffusionTerm, Viewer import numpy as np from stl import mesh as stl_mesh import tqdm import pyvista as pv import matplotlib.pyplot as plt from matplotlib.colors import LinearSegmentedColormap from scipy.interpolate import griddata def visualize_3d_temperature(mesh, temperature, title="3D Temperature Distribution"): """ Create comprehensive 3D visualization of temperature field using PyVista """ # Extract mesh coordinates and temperature values x, y, z = mesh.cellCenters temp_values = temperature.value # Create PyVista structured grid nx, ny, nz = mesh.nx, mesh.ny, mesh.nz # Create coordinate arrays for structured grid x_coords = np.linspace(x.min(), x.max(), nx + 1) y_coords = np.linspace(y.min(), y.max(), ny + 1) z_coords = np.linspace(z.min(), z.max(), nz + 1) # Create structured grid grid = pv.StructuredGrid(*np.meshgrid(x_coords, y_coords, z_coords, indexing="ij")) # Add temperature data (need to reshape for cell data) temp_reshaped = temp_values.reshape((nx, ny, nz), order="F") grid.cell_data["Temperature"] = temp_reshaped.flatten(order="F") # Create plotter plotter = pv.Plotter(window_size=(1200, 800)) # Add volume rendering opacity = [0, 0.2, 0.5, 0.8, 1.0] plotter.add_volume( grid, scalars="Temperature", opacity=opacity, cmap="coolwarm", show_scalar_bar=True, ) # Add outline plotter.add_mesh(grid.outline(), color="black", line_width=2) # Add cross-sectional slices slices = grid.slice_orthogonal() plotter.add_mesh( slices, scalars="Temperature", cmap="coolwarm", opacity=0.7, show_scalar_bar=False, ) # Set up the scene plotter.set_background("white") plotter.add_text(title, position="upper_left", font_size=14) plotter.add_text( f"Min: {temp_values.min():.1f}K, Max: {temp_values.max():.1f}K", position="lower_left", font_size=12, ) # Add coordinate axes plotter.add_axes() # Show the plot plotter.show() def create_temperature_slices(mesh, temperature, output_file=None): """ Create 2D slice visualizations showing temperature distribution """ x, y, z = mesh.cellCenters temp_values = temperature.value nx, ny, nz = mesh.nx, mesh.ny, mesh.nz print(f"Debug: mesh dimensions nx={nx}, ny={ny}, nz={nz}") print(f"Debug: temp_values shape: {temp_values.shape}") print(f"Debug: temp range: {temp_values.min():.2f} - {temp_values.max():.2f} K") # FiPy stores data in C order, need to reshape correctly # Create coordinate grids for proper indexing x_coords = np.linspace(x.min(), x.max(), nx) y_coords = np.linspace(y.min(), y.max(), ny) z_coords = np.linspace(z.min(), z.max(), nz) # Create meshgrid for interpolation X, Y, Z = np.meshgrid(x_coords, y_coords, z_coords, indexing="ij") # Interpolate temperature values on regular grid points = np.column_stack([x.flatten(), y.flatten(), z.flatten()]) # Reshape to 3D grid temp_3d = griddata( points, temp_values, (X, Y, Z), method="linear", fill_value=temp_values.mean() ) # Create figure with subplots fig, axes = plt.subplots(2, 2, figsize=(12, 10)) fig.suptitle("Temperature Distribution - Cross Sections", fontsize=16) # X-Y slice (middle Z) z_mid = nz // 2 slice_xy = temp_3d[:, :, z_mid] im1 = axes[0, 0].imshow( slice_xy.T, extent=[x.min(), x.max(), y.min(), y.max()], origin="lower", cmap="coolwarm", aspect="auto", vmin=temp_values.min(), vmax=temp_values.max(), ) axes[0, 0].set_title(f"X-Y Slice (Z = {z_coords[z_mid]:.2f})") axes[0, 0].set_xlabel("X (m)") axes[0, 0].set_ylabel("Y (m)") plt.colorbar(im1, ax=axes[0, 0], label="Temperature (K)") # X-Z slice (middle Y) y_mid = ny // 2 slice_xz = temp_3d[:, y_mid, :] im2 = axes[0, 1].imshow( slice_xz.T, extent=[x.min(), x.max(), z.min(), z.max()], origin="lower", cmap="coolwarm", aspect="auto", vmin=temp_values.min(), vmax=temp_values.max(), ) axes[0, 1].set_title(f"X-Z Slice (Y = {y_coords[y_mid]:.2f})") axes[0, 1].set_xlabel("X (m)") axes[0, 1].set_ylabel("Z (m)") plt.colorbar(im2, ax=axes[0, 1], label="Temperature (K)") # Y-Z slice (middle X) x_mid = nx // 2 slice_yz = temp_3d[x_mid, :, :] im3 = axes[1, 0].imshow( slice_yz.T, extent=[y.min(), y.max(), z.min(), z.max()], origin="lower", cmap="coolwarm", aspect="auto", vmin=temp_values.min(), vmax=temp_values.max(), ) axes[1, 0].set_title(f"Y-Z Slice (X = {x_coords[x_mid]:.2f})") axes[1, 0].set_xlabel("Y (m)") axes[1, 0].set_ylabel("Z (m)") plt.colorbar(im3, ax=axes[1, 0], label="Temperature (K)") # Temperature histogram axes[1, 1].hist( temp_values, bins=50, alpha=0.7, color="steelblue", edgecolor="black" ) axes[1, 1].set_title("Temperature Distribution") axes[1, 1].set_xlabel("Temperature (K)") axes[1, 1].set_ylabel("Frequency") axes[1, 1].grid(True, alpha=0.3) axes[1, 1].axvline( temp_values.mean(), color="red", linestyle="--", label=f"Mean: {temp_values.mean():.1f}K", ) axes[1, 1].legend() plt.tight_layout() if output_file: plt.savefig(output_file, dpi=300, bbox_inches="tight") print(f"Temperature slices saved to {output_file}") plt.show() def run_single_heat_transfer(): # --- Step 1: Load STL and create approximate mesh --- # Load the STL file stl_data = stl_mesh.Mesh.from_file("part.stl") # Get bounds from STL vertices = stl_data.vectors.reshape(-1, 3) x_min, x_max = vertices[:, 0].min(), vertices[:, 0].max() y_min, y_max = vertices[:, 1].min(), vertices[:, 1].max() z_min, z_max = vertices[:, 2].min(), vertices[:, 2].max() print( f"STL bounds: x=[{x_min:.2f}, {x_max:.2f}], y=[{y_min:.2f}, {y_max:.2f}], z=[{z_min:.2f}, {z_max:.2f}]" ) # Create a uniform grid that covers the STL bounds nx, ny, nz = 20, 20, 20 # mesh resolution dx = (x_max - x_min) / nx dy = (y_max - y_min) / ny dz = (z_max - z_min) / nz mesh = Grid3D(nx=nx, ny=ny, nz=nz, dx=dx, dy=dy, dz=dz) mesh = mesh + [[x_min], [y_min], [z_min]] # --- Step 2: Define material properties (example: aluminum) --- rho = 2700.0 # kg/m³ cp = 900.0 # J/kgK k = 205.0 # W/mK alpha = k / (rho * cp) # thermal diffusivity # --- Step 3: Define heat transfer coefficient and ambient temp --- h = 30.0 # W/m²K (for ~3 m/s air around small cube) T_inf = 300.0 # K # --- Step 4: Initialize temperature field --- # Create non-uniform initial temperature (hot spot in center) x, y, z = mesh.cellCenters center_x, center_y, center_z = 0.0, 0.0, 0.0 initial_temp = 300.0 + 50.0 * np.exp( -((x - center_x) ** 2 + (y - center_y) ** 2 + (z - center_z) ** 2) / 25.0 ) temperature = CellVariable(name="T", mesh=mesh, value=initial_temp) # --- Step 5: Define PDE (diffusion inside, convection at boundaries) --- eq = TransientTerm(coeff=rho * cp) == DiffusionTerm(coeff=k) # Boundary convection (Robin condition): # FiPy doesn't directly handle Robin, so we fake it by adding a surface source term. # Cells near boundary get extra sink term ~ h*(T - T_inf). # Simple boundary mask: all boundary cells (close to min/max x,y,z) tol = 1e-6 boundary_mask = ( (np.abs(x - np.min(x)) < tol) | (np.abs(x - np.max(x)) < tol) | (np.abs(y - np.min(y)) < tol) | (np.abs(y - np.max(y)) < tol) | (np.abs(z - np.min(z)) < tol) | (np.abs(z - np.max(z)) < tol) ) # --- Step 6: Time stepping (3 minutes = 180 s) --- dt = 0.5 # s steps = int(180 / dt) # 3 minutes = 180 seconds # Create equation with implicit convection boundary condition eq = TransientTerm(coeff=rho * cp) == DiffusionTerm(coeff=k) - h * ( temperature - T_inf ) * boundary_mask.astype(float) for step in tqdm.trange(steps): # Update boundary convection term each iteration eq = TransientTerm(coeff=rho * cp) == DiffusionTerm(coeff=k) - h * ( temperature - T_inf ) * boundary_mask.astype(float) eq.solve(var=temperature, dt=dt) # --- Step 7: Extract results --- core_temp = temperature((0, 0, 0)) # approximate core at cube center surface_temp = np.mean(temperature.value[boundary_mask]) print(f"Final surface temperature ~ {surface_temp:.2f} K") print(f"Final core temperature ~ {core_temp:.2f} K") # 3D Visualization print("\nGenerating 3D temperature visualization...") visualize_3d_temperature(mesh, temperature, "Heat Transfer - 3D Temperature Field") # 2D Cross-section visualization print("Creating temperature cross-sections...") create_temperature_slices(mesh, temperature, "temperature_analysis.png") return f"Final surface temperature ~ {surface_temp:.2f} K\nFinal core temperature ~ {core_temp:.2f} K" if __name__ == "__main__": result = run_single_heat_transfer() print(result)

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TheFloatingString/mcp-for-hardware'

If you have feedback or need assistance with the MCP directory API, please join our Discord server