Skip to main content
Glama

Physics MCP Server

by BlinkZer0
acceptance_phase5.py10.1 kB
#!/usr/bin/env python3 """ Acceptance tests for Phase 5: Advanced Visualization Runs scenario-based tests as specified in the requirements. """ import json import os import sys import tempfile import subprocess from pathlib import Path # Add the python-worker to the path sys.path.insert(0, str(Path(__file__).parent.parent / "packages" / "python-worker")) from worker import handle_request def test_wavepacket_scenario(): """ Scenario: Evolve a 1D Gaussian wavepacket, render as MP4 with CSV data. Re-invoke with same params → cache hit. """ print("🌊 Testing wavepacket evolution scenario...") request = { "method": "plot_animation", "params": { "frame_expr": "exp(-(x-t)**2/2) * cos(5*x - 2*t)", "x_range": [-5, 5, 100], "t_range": [0, 5, 30], "renderer": "line", "fps": 10, "format": "mp4", "emit_csv": True } } # First call print(" 📊 First call...") result1 = handle_request(request) assert "animation_path" in result1, "Animation path missing" assert "csv_data" in result1, "CSV data missing" assert os.path.exists(result1["animation_path"]), "Animation file not created" assert result1["meta"]["format"] == "mp4", "Wrong format" file_size1 = os.path.getsize(result1["animation_path"]) assert file_size1 > 1000, "Animation file too small" print(f" ✅ Animation created: {result1['animation_path']} ({file_size1} bytes)") print(f" ✅ CSV data: {len(result1['csv_data'].split())} lines") print(f" ✅ Device used: {result1['meta']['device']}") # Second call (should be same or cached) print(" 🔄 Second call (cache test)...") result2 = handle_request(request) assert "animation_path" in result2, "Second call failed" print(f" ✅ Second call successful") return True def test_phase_portrait_sweep(): """ Scenario: plot_interactive thumbnail grid over damping parameter with sliders spec. """ print("🎛️ Testing phase portrait parameter sweep...") request = { "method": "plot_interactive", "params": { "expr": "exp(-gamma*t) * sin(omega*t)", "x_range": [0, 10, 100], # Using x_range as time for this example "controls": [ {"name": "gamma", "min": 0.1, "max": 2.0, "step": 0.3, "default": 0.5}, {"name": "omega", "min": 1.0, "max": 5.0, "step": 1.0, "default": 2.0} ], "renderer": "line", "grid_limit": 12 } } result = handle_request(request) assert "thumbnails" in result, "Thumbnails missing" assert "ui_spec" in result, "UI spec missing" assert len(result["thumbnails"]) > 0, "No thumbnails generated" assert len(result["thumbnails"]) <= 12, "Too many thumbnails" # Check UI spec structure ui_spec = result["ui_spec"] assert ui_spec["type"] == "sliders", "Wrong UI type" assert len(ui_spec["controls"]) == 2, "Wrong number of controls" # Check thumbnail structure for i, thumb in enumerate(result["thumbnails"]): assert "control_values" in thumb, f"Thumbnail {i} missing control values" assert "png_b64" in thumb, f"Thumbnail {i} missing image" assert "gamma" in thumb["control_values"], f"Thumbnail {i} missing gamma" assert "omega" in thumb["control_values"], f"Thumbnail {i} missing omega" # Verify base64 PNG png_data = thumb["png_b64"] assert len(png_data) > 100, f"Thumbnail {i} image too small" print(f" ✅ Generated {len(result['thumbnails'])} thumbnails") print(f" ✅ UI spec with {len(ui_spec['controls'])} controls") print(f" ✅ Grid size: {result['meta']['grid_size']}") return True def test_vr_export_scenario(): """ Scenario: Sample a 3D scalar field isosurface and export GLB + PLY. Files should open in standard viewers. """ print("🥽 Testing VR export scenario...") # First, create a simple geometric mesh (icosahedron approximation) import math # Golden ratio phi = (1 + math.sqrt(5)) / 2 # Icosahedron vertices vertices = [ [-1, phi, 0], [1, phi, 0], [-1, -phi, 0], [1, -phi, 0], [0, -1, phi], [0, 1, phi], [0, -1, -phi], [0, 1, -phi], [phi, 0, -1], [phi, 0, 1], [-phi, 0, -1], [-phi, 0, 1] ] # Icosahedron faces (triangular) faces = [ [0, 11, 5], [0, 5, 1], [0, 1, 7], [0, 7, 10], [0, 10, 11], [1, 5, 9], [5, 11, 4], [11, 10, 2], [10, 7, 6], [7, 1, 8], [3, 9, 4], [3, 4, 2], [3, 2, 6], [3, 6, 8], [3, 8, 9], [4, 9, 5], [2, 4, 11], [6, 2, 10], [8, 6, 7], [9, 8, 1] ] # Test GLB export print(" 📦 Testing GLB export...") glb_request = { "method": "plot_vr_export", "params": { "geometry": { "vertices": vertices, "faces": faces }, "format": "glb", "extras": {"name": "test_icosahedron", "description": "Phase 5 test"} } } glb_result = handle_request(glb_request) if "error" in glb_result: print(f" ⚠️ GLB export skipped: {glb_result['error']}") return True # Skip if trimesh not available assert "path" in glb_result, "GLB path missing" assert glb_result["path"].endswith(".glb"), "Wrong GLB extension" assert os.path.exists(glb_result["path"]), "GLB file not created" glb_size = os.path.getsize(glb_result["path"]) assert glb_size > 100, "GLB file too small" print(f" ✅ GLB exported: {glb_result['path']} ({glb_size} bytes)") print(f" ✅ Vertices: {glb_result['meta']['vertices']}") print(f" ✅ Faces: {glb_result['meta']['faces']}") # Test PLY export print(" 📦 Testing PLY export...") ply_request = { "method": "plot_vr_export", "params": { "geometry": { "vertices": vertices, "faces": faces }, "format": "ply" } } ply_result = handle_request(ply_request) assert "path" in ply_result, "PLY path missing" assert ply_result["path"].endswith(".ply"), "Wrong PLY extension" assert os.path.exists(ply_result["path"]), "PLY file not created" ply_size = os.path.getsize(ply_result["path"]) assert ply_size > 50, "PLY file too small" print(f" ✅ PLY exported: {ply_result['path']} ({ply_size} bytes)") # Basic file format validation with open(ply_result["path"], 'r') as f: ply_header = f.read(100) assert "ply" in ply_header.lower(), "Invalid PLY header" print(f" ✅ PLY format validated") return True def test_volume_3d_scenario(): """ Scenario: Create 3D volume visualization with GPU acceleration. """ print("📦 Testing 3D volume visualization...") request = { "method": "plot_volume_3d", "params": { "f": "exp(-(x**2 + y**2 + z**2)/4) * sin(2*sqrt(x**2 + y**2 + z**2))", "x": [-3, 3, 30], "y": [-3, 3, 30], "z": [-3, 3, 30], "mode": "slices" } } result = handle_request(request) assert "png_contact_sheet_b64" in result, "Contact sheet missing" assert "csv_data" in result, "CSV data missing" assert "meta" in result, "Metadata missing" # Check metadata meta = result["meta"] assert "device" in meta, "Device info missing" assert "duration_ms" in meta, "Duration missing" assert "mesh" in meta, "Mesh info missing" assert meta["mode"] == "slices", "Wrong mode" # Validate CSV structure csv_lines = result["csv_data"].split('\n') assert len(csv_lines) > 1, "CSV too short" assert csv_lines[0] == "x,y,z,f", "Wrong CSV header" # Check that we have actual data data_lines = [line for line in csv_lines[1:] if line.strip()] assert len(data_lines) > 10, "Not enough CSV data" print(f" ✅ Volume rendered on: {meta['device']}") print(f" ✅ Mesh size: {meta['mesh']}") print(f" ✅ Duration: {meta['duration_ms']}ms") print(f" ✅ CSV data: {len(data_lines)} points") return True def test_acceleration_detection(): """ Test that acceleration detection works properly. """ print("⚡ Testing acceleration detection...") request = { "method": "accel_caps", "params": {} } result = handle_request(request) assert "active" in result, "Active flag missing" assert "device" in result, "Device missing" assert "mode" in result, "Mode missing" assert "has_torch" in result, "PyTorch flag missing" print(f" ✅ Acceleration active: {result['active']}") print(f" ✅ Device: {result['device']}") print(f" ✅ Mode: {result['mode']}") print(f" ✅ Has PyTorch: {result['has_torch']}") return True def main(): """Run all acceptance tests.""" print("🚀 Phase 5 Acceptance Tests") print("=" * 50) tests = [ test_acceleration_detection, test_volume_3d_scenario, test_wavepacket_scenario, test_phase_portrait_sweep, test_vr_export_scenario, ] passed = 0 failed = 0 for test in tests: try: if test(): passed += 1 print("✅ PASSED\n") else: failed += 1 print("❌ FAILED\n") except Exception as e: failed += 1 print(f"❌ FAILED: {e}\n") print("=" * 50) print(f"📊 Results: {passed} passed, {failed} failed") if failed == 0: print("🎉 All Phase 5 acceptance tests passed!") return 0 else: print("⚠️ Some tests failed. Check the output above.") return 1 if __name__ == "__main__": exit(main())

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/BlinkZer0/Phys-MCP'

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