felix-framework / tests /validation /validate_openscad.py
jkbennitt
Clean hf-space branch and prepare for HuggingFace Spaces deployment
fb867c3
#!/usr/bin/env python3
"""
Validation script to compare Python implementation against OpenSCAD model.
This script recreates key calculations from thefelix.md to ensure
our Python implementation matches the geometric prototype.
"""
import math
from src.core.helix_geometry import HelixGeometry
def openscad_get_position(step, turns, segments_per_turn, height, top_radius, bottom_radius):
"""
Recreate the OpenSCAD get_position function for comparison.
From thefelix.md:
function get_position(step, p_turns, p_segs, p_h, p_t_rad, p_b_rad) = let(
total_steps = p_turns * p_segs,
angle = step / total_steps * p_turns * 360,
z = step / total_steps * p_h,
r = p_b_rad * pow(p_t_rad / p_b_rad, z / p_h),
x = r * cos(angle),
y = r * sin(angle)
) [x, y, z];
"""
total_steps = turns * segments_per_turn
angle = step / total_steps * turns * 360 # degrees
z = step / total_steps * height
r = bottom_radius * pow(top_radius / bottom_radius, z / height)
x = r * math.cos(math.radians(angle))
y = r * math.sin(math.radians(angle))
return (x, y, z)
def validate_implementation():
"""Compare Python implementation against OpenSCAD calculations."""
# Parameters from thefelix.md
top_radius = 33.0
bottom_radius = 0.001
height = 33.0
turns = 33
segments_per_turn = 33
# Create Python helix
helix = HelixGeometry(top_radius, bottom_radius, height, turns)
print("=== OpenSCAD vs Python Implementation Validation ===\n")
# Test specific positions
total_steps = turns * segments_per_turn
test_steps = [0, total_steps // 4, total_steps // 2, 3 * total_steps // 4, total_steps - 1]
print("Comparing positions at key points:")
print("Step | t | OpenSCAD (x, y, z) | Python (x, y, z) | Max Diff | Debug")
print("-" * 90)
max_overall_diff = 0.0
for step in test_steps:
# OpenSCAD calculation
openscad_pos = openscad_get_position(
step, turns, segments_per_turn, height, top_radius, bottom_radius
)
# Python calculation - match the exact OpenSCAD conversion
# OpenSCAD: t = step / total_steps, but we need step / (total_steps - 1) for discrete steps
t_openscad = step / total_steps # This is what OpenSCAD actually uses
python_pos = helix.get_position(t_openscad)
# Calculate differences
diff_x = abs(openscad_pos[0] - python_pos[0])
diff_y = abs(openscad_pos[1] - python_pos[1])
diff_z = abs(openscad_pos[2] - python_pos[2])
max_diff = max(diff_x, diff_y, diff_z)
max_overall_diff = max(max_overall_diff, max_diff)
# Debug info
angle_openscad = step / total_steps * turns * 360
angle_python = t_openscad * turns * 360
print(f"{step:4d} | {t_openscad:.3f} | ({openscad_pos[0]:8.3f}, {openscad_pos[1]:8.3f}, {openscad_pos[2]:8.3f}) | "
f"({python_pos[0]:8.3f}, {python_pos[1]:8.3f}, {python_pos[2]:8.3f}) | {max_diff:.2e} | "
f"ang={angle_openscad:.1f}")
print(f"\nMaximum overall difference: {max_overall_diff:.2e}")
# Validation threshold - allow for floating point precision
if max_overall_diff < 1e-6:
print("✅ VALIDATION PASSED: Python implementation matches OpenSCAD model")
return True
else:
print("❌ VALIDATION FAILED: Significant differences detected")
return False
def performance_baseline():
"""Establish performance baseline for helix calculations."""
import time
helix = HelixGeometry(33.0, 0.001, 33.0, 33)
print("\n=== Performance Baseline ===")
# Time single position calculation
start_time = time.perf_counter()
for i in range(10000):
t = i / 9999.0
pos = helix.get_position(t)
end_time = time.perf_counter()
time_per_calc = (end_time - start_time) / 10000
print(f"Position calculation: {time_per_calc:.2e} seconds per call")
print(f"Throughput: {1.0/time_per_calc:.0f} calculations per second")
# Time arc length approximation
start_time = time.perf_counter()
arc_length = helix.approximate_arc_length(segments=1000)
end_time = time.perf_counter()
print(f"Arc length calculation (1000 segments): {end_time - start_time:.3f} seconds")
print(f"Total helix arc length: {arc_length:.1f} units")
if __name__ == "__main__":
# Run validation
validation_passed = validate_implementation()
# Run performance baseline
performance_baseline()
# Summary
print(f"\n=== Validation Summary ===")
if validation_passed:
print("Core helix mathematics implementation is VALIDATED ✅")
print("Ready to proceed with agent system implementation.")
else:
print("Validation FAILED - implementation needs correction ❌")