Files
Atomizer/tools/analysis/debug_figure_coords.py
Anto01 a3f18dc377 chore: Project cleanup and Canvas UX improvements (Phase 7-9)
## Cleanup (v0.5.0)
- Delete 102+ orphaned MCP session temp files
- Remove build artifacts (htmlcov, dist, __pycache__)
- Archive superseded plan docs (RALPH_LOOP V2/V3, CANVAS V3, etc.)
- Move debug/analysis scripts from tests/ to tools/analysis/
- Archive redundant NX journals to archive/nx_journals/
- Archive monolithic PROTOCOL.md to docs/archive/
- Update .gitignore with missing patterns
- Clean old study files (optimization_log_old.txt, run_optimization_old.py)

## Canvas UX (Phases 7-9)
- Phase 7: Resizable panels with localStorage persistence
  - Left sidebar: 200-400px, Right panel: 280-600px
  - New useResizablePanel hook and ResizeHandle component
- Phase 8: Enable all palette items
  - All 8 node types now draggable
  - Singleton logic for model/solver/algorithm/surrogate
- Phase 9: Solver configuration
  - Add SolverEngine type (nxnastran, mscnastran, python, etc.)
  - Add NastranSolutionType (SOL101-SOL200)
  - Engine/solution dropdowns in config panel
  - Python script path support

## Documentation
- Update CHANGELOG.md with recent versions
- Update docs/00_INDEX.md
- Create examples/README.md
- Add docs/plans/CANVAS_UX_IMPROVEMENTS.md
2026-01-24 15:17:34 -05:00

84 lines
2.7 KiB
Python

"""Debug script to compare figure.dat vs BDF node coordinates."""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
import numpy as np
import logging
logging.disable(logging.WARNING)
study_dir = Path(r"c:\Users\antoi\Atomizer\studies\M1_Mirror\m1_mirror_cost_reduction_V9")
# Load figure.dat
from optimization_engine.extractors.extract_zernike_figure import load_figure_geometry
fig_geo = load_figure_geometry(study_dir / "1_setup/model/figure.dat")
fig_nids = set(fig_geo.keys())
# Find OP2 and BDF
op2_file = list(study_dir.glob("3_results/best_design_archive/**/*.op2"))[0]
bdf_file = op2_file.with_suffix(".dat")
# Load BDF
from pyNastran.bdf.bdf import BDF
bdf = BDF(log=None, debug=False)
bdf.read_bdf(str(bdf_file))
bdf_nids = set(bdf.nodes.keys())
# Load OP2
from pyNastran.op2.op2 import OP2
op2 = OP2(log=None, debug=False)
op2.read_op2(str(op2_file))
disps = op2.displacements
first_key = list(disps.keys())[0]
op2_nids = set(int(n) for n in disps[first_key].node_gridtype[:,0])
print(f"Figure.dat nodes: {len(fig_nids)}")
print(f"BDF nodes: {len(bdf_nids)}")
print(f"OP2 nodes: {len(op2_nids)}")
print()
print(f"Figure ^ BDF: {len(fig_nids & bdf_nids)}")
print(f"Figure ^ OP2: {len(fig_nids & op2_nids)}")
print(f"BDF ^ OP2: {len(bdf_nids & op2_nids)}")
# Sample coords - use a node in all three
common_nids = list(fig_nids & bdf_nids & op2_nids)[:5]
print()
print("Sample common node coords comparison:")
z_diffs = []
for nid in common_nids:
fig_pos = fig_geo[nid]
bdf_pos = bdf.nodes[nid].get_position()
diff = np.array(fig_pos) - bdf_pos
z_diffs.append(diff[2])
print(f" Node {nid}:")
print(f" Figure: ({fig_pos[0]:.6f}, {fig_pos[1]:.6f}, {fig_pos[2]:.9f})")
print(f" BDF: ({bdf_pos[0]:.6f}, {bdf_pos[1]:.6f}, {bdf_pos[2]:.9f})")
print(f" Z diff: {diff[2]*1e6:.3f} nm")
# Statistics on all matching nodes
all_common = fig_nids & bdf_nids
all_z_diffs = []
all_xy_diffs = []
for nid in all_common:
fig_pos = np.array(fig_geo[nid])
bdf_pos = bdf.nodes[nid].get_position()
diff = fig_pos - bdf_pos
all_z_diffs.append(diff[2])
all_xy_diffs.append(np.sqrt(diff[0]**2 + diff[1]**2))
all_z_diffs = np.array(all_z_diffs)
all_xy_diffs = np.array(all_xy_diffs)
print()
print(f"=== ALL {len(all_common)} COMMON NODES ===")
print(f"Z difference (figure - BDF):")
print(f" Min: {all_z_diffs.min()*1e6:.3f} nm")
print(f" Max: {all_z_diffs.max()*1e6:.3f} nm")
print(f" Mean: {all_z_diffs.mean()*1e6:.3f} nm")
print(f" RMS: {np.sqrt(np.mean(all_z_diffs**2))*1e6:.3f} nm")
print()
print(f"XY difference (figure - BDF):")
print(f" Max: {all_xy_diffs.max()*1e3:.6f} um")
print(f" RMS: {np.sqrt(np.mean(all_xy_diffs**2))*1e3:.6f} um")