Skip to content

feat: general N-vertex Polygon shape, watertight prisms, complete ray unit tests, and streamlined wheel build - #196

Open
hstarmans wants to merge 13 commits into
cihologramas:masterfrom
hstarmans:feature/prisms-ray-tests-and-build
Open

feat: general N-vertex Polygon shape, watertight prisms, complete ray unit tests, and streamlined wheel build#196
hstarmans wants to merge 13 commits into
cihologramas:masterfrom
hstarmans:feature/prisms-ray-tests-and-build

Conversation

@hstarmans

@hstarmans hstarmans commented Sep 6, 2026

Copy link
Copy Markdown

Hi @ramezquitao,

Following up on PR #1 (#195), this pull request addresses several open TODOs and completes pending unit tests in pyoptools:

1. Arbitrary N-Vertex Polygon Aperture Shape

  • Upgraded pyoptools.raytrace.shape.Polygon from a 3-vertex triangle placeholder into a true general N-vertex polygonal aperture.
  • Implemented standard O(N) Jordan curve ray-casting in Cython (hit_cy(Vector3d &point) noexcept nogil) with zero heap allocations during ray hit tests.
  • Added exact bounding box limits() and 2D mesh grid sampling in pointlist().
  • Added validation (>= 3 vertices) and __reduce__ support for pickling.

2. Watertight PentaPrism and DovePrism

  • Resolved the open-aperture warnings/TODOs for both prisms:
    • PentaPrism: Added lateral closing surfaces S6 (top) and S7 (bottom) using a 5-vertex polygon matching the prism geometry.
    • DovePrism: Added lateral closing surfaces S5 (top) and S6 (bottom) using a 4-vertex trapezoid polygon.

3. Completed Pending Ray Tests

  • Implemented and un-skipped tests in tests/raytrace/ray/test_ray.py:
    • test_get_final_rays (leaf ray extraction with zero/nonzero intensity filtering)
    • test_add_child (parent-child ray tree linkages and ordering)
    • test_optical_path_parent (accumulated optical path length from root)
    • test_optical_path (ray optical path calculation)

4. New Unit Tests

  • tests/raytrace/shape/test_shapes.py: 6 tests for Polygon (validation, triangles, trapezoids, pentagons, pointlist, pickling).
  • tests/raytrace/component/test_component.py: Unit tests for PentaPrism (90° deviation and top surface hit) and DovePrism (top surface hit).

5. Streamlined Wheel Build Workflow

  • Cleaned up .github/workflows/build.yaml to remove manual OS package manager installations for Eigen, taking full advantage of the native eigency dependency declared in [build-system] requires.

6. Modernized Coding Standards with Ruff & Cython-Lint

  • Replaced legacy pycodestyle, pep8, and autopep8 with Ruff (ruff>=0.8.0) for fast Python linting and formatting.
  • Preserved cython-lint (cython-lint>=0.18.0) for Cython AST inspection (.pyx / .pxd).
  • Resolved latent circular imports between compound_lens.py / cube.py and comp_lib.py by switching to relative imports.
  • Formatted and cleaned all Python files with ruff check --fix and ruff format.

7. Eliminated Python 2 Syntax & Legacy Dict Methods in Cython

  • Replaced legacy Python 2 raise Exc, msg across surface.pyx and system.pyx.
  • Modernized dictionary iteration from .iteritems(), .itervalues(), and .iterkeys() to standard Python 3 .items(), .values(), and .keys() in picklable.pyx, component.pyx, and system.pyx (with backward compatibility aliases preserved).

8. System Ray-Marching Inner Loop Performance (~3.5× Speedup)

  • Eliminated NumPy Calls in Hot Loops:
    • Replaced O(N log N) asarray(dist_list).argsort() in System.propagate_ray with single-pass O(N) inline C scalar tracking of the two nearest components (comp0, comp1, d0, d1).
    • Replaced asarray(dist_list).argmin() in Component.distance, Component.propagate, and System.distance with inline C double distance tracking (min_d = INFINITY, min_surf, min_pi).
    • Replaced array(dist_list) and all(npisinf(...)) with an immediate scalar check isinf(d0).
    • Removed unused NumPy imports from Cython hot loops.
  • Eliminated Intermediate Python List Allocations:
    • Removed per-ray allocations of dist_list, surf_list, comp_list, and pi_list in propagate_ray.
    • Tracked component tuple references directly, eliminating dictionary index lookups on plist.
  • Fast In-Place Development & Build Speed:
    • Removed deprecated setup_requires=["setuptools_scm", "Cython", "eigency"] from setup.py that forced Setuptools to attempt isolated wheel downloads.
    • In-place incremental compilation (python setup.py build_ext --inplace) now finishes in ~1.2 s to 11 s.
  • Benchmark Results (1,000 rays traced through a 3-component system):
    • Before: 0.4942 s (494.2 μs/ray)
    • After: 0.1373 s – 0.1405 s (137.3 – 140.5 μs/ray)
    • Result: ~3.5× faster ray tracing.
  • Compatibility: 100% test pass rate on both NumPy 1.26 and NumPy 2.x (108 passed, 12 skipped).

9. Tracked uv.lock & Modernized Developer Guidelines (AGENTS.md)

  • Tracked uv.lock in Version Control:

    • Removed uv.lock from .gitignore in line with standard Astral / modern Python library best practices.
    • Note on library lockfiles: When building wheels/sdists (uv build or pip install pyoptools), packaging backends use pyproject.toml dependency ranges—end users on PyPI are never pinned to the lockfile. Committing uv.lock ensures maintainers, contributors, and CI runners have 100% reproducible environments and eliminates unexpected CI breakage from upstream patch releases.
  • Updated AGENTS.md:

    • Documented modern uv workflows (uv run python setup.py build_ext --inplace, uv run pytest, uv run ruff check).
    • Removed outdated instructions referencing raw pip install and dead autopep8 scripts.
    • Removed artificial prompt artifacts (e.g. NO COMMENTS rule) in favor of clear code documentation practices.

    10. Resolved Component.hit_list with Eigen Coordinate Transformations

  • Implemented Long-Standing TODO: Implemented the hit_list property in Component (component.pyx) to aggregate hit points from all internal component surfaces.

  • Native Eigen Acceleration: Evaluated local surface intersection hits in C++ and transformed coordinates into the component coordinate system using Eigen Vector3d and Matrix3d rotation matrices.

  • New Unit Test: Added test_component_hit_list in tests/raytrace/component/test_component.py, verifying multi-surface coordinate transformations on double-convex spherical lenses.

11. Codebase Cleanup: Dead Stubs, Legacy Comments & Obsolete C Code

  • Removed Dead Stubs: Deleted empty 4-line stub pyoptools/gui/logutils.py and 0-byte file pyoptools/raytrace/config/config.py.
  • Purged Geany Editor Noise: Removed 292 lines of legacy # ~ Geany comment blocks across 15 files.
  • Removed Dead Scipy Weave C Code: Removed 110 lines of unmaintained, Python 2-era scipy.weave inline C code from pyoptools/misc/lsq/lsq.pyx.
  • Comment Modernization: Cleaned up obsolete commented-out debug # print statements and translated legacy Spanish developer comments into clean English across component.pyx, system.pyx, and taylor_poly.pyx. All intentional domain/physics TODOs were preserved.

12. Bug Fixes in Calculation & Resource Detection

  • detectOpenCL() Crash Fix: Resolved UnboundLocalError: local variable 'cl' referenced before assignment in pyoptools/misc/resources/resources.pyx when pyopencl is not installed by safely checking imports.
  • detectCPUs() Modernization: Replaced Python 2's removed os.popen2("sysctl -n hw.ncpu") with modern os.cpu_count() or 1.
  • find_aperture() Grid Dimension Fix: In pyoptools/raytrace/calc/calc.py, replaced floating-point step size indexing in np.mgrid with complex step counts complex(0, tx) and complex(0, ty), guaranteeing exact (tx, ty) output array dimensions without floating-point accumulation rounding errors.
  • chief_ray_search() Graceful Error Handling: Caught (ValueError, IndexError) on ccds.hit_list[0] in calc.py so candidate rays that miss the aperture detector correctly assign dist = inf rather than crashing unhandled.
  • Activated Skipped Tests:
    • Re-enabled and verified passing: test_paraxial_location, test_find_aperture, and test_find_ppp in tests/raytrace/calc/test_calc.py.
    • Added new automated test suite tests/misc/resources/test_resources.py for CPU and OpenCL detection.

13. Documentation Build Fixes, Modernization & Quickstart

  • Resolved Sphinx Autodoc Crashes:
    • Fixed crashes in sphinxcontrib.apidoc / autodoc caused by dynamic module replacements in library.py and material.py. Added attribute guards (if name.startswith("_"): raise AttributeError(...)) and populated standard module metadata (__name__, __doc__, __file__, __package__) on replacement instances in sys.modules.
    • Configured nbsphinx_execute = 'never' in doc/conf.py to prevent headless documentation build timeouts on live Jupyter kernels while fully rendering all 11 notebooks into static HTML.
    • The Sphinx documentation (sphinx-build -b html doc doc/_build/html) now builds completely with 0 errors.
  • Modernized Documentation Guides:
    • doc/install.rst: Added recommended uv commands (uv add pyoptools / uv pip install pyoptools), Python 3.10–3.13 requirements, optional visualization dependencies (jupyterlab, plotly), and source build instructions.
    • doc/development.rst: Documented local setup with uv sync, fast in-place compilation, pytest, ruff, cython-lint, and local Sphinx build commands.
    • README.md: Expanded from a 20-line stub into a comprehensive overview with key features, quick installation, a verified 15-line Quickstart raytrace code snippet, and links to documentation.
    • CONTRIBUTING.md: Updated Python prerequisites to >= 3.10 and added uv workflows.

14. Export library in pyoptools.all & Verified Doc Notebooks

  • Exported library: Added from pyoptools.raytrace.library import * to pyoptools/all.py so user scripts and notebooks can directly access vendor catalogs (library.Edmund, library.Thorlabs).
  • Verified All 11 Documentation Notebooks: Tested execution across all 11 notebooks in doc/notebooks/basic/ (Autocollimator.ipynb, Binocular.ipynb, GeomWF.ipynb, SimpleRayTraces.ipynb, etc.), ensuring all ray-tracing math, component constructors, and catalog lookups run cleanly.

Rik Starmans added 13 commits September 6, 2026 12:48
…e Eigen3, and add CI

- Add `pyoptools.gui.plotly_viewer` providing interactive 3D WebGL optical
  visualization compatible with Marimo, JupyterLab 4, and VS Code.
- Update `pyoptools.gui.ipywidgets.Plot3D` with `backend="auto"`, defaulting
  to Plotly without crashing if pythreejs is missing.
- Complete `CylindricalLens` by adding lateral closing surfaces S3..S6 for
  watertight optical geometry and ray propagation.
- Declare `eigency` in `[build-system] requires` in `pyproject.toml` and detect
  via `eigency.get_includes()` in `setup.py`, allowing native build via uv/pip
  without requiring root or system package managers for Eigen3 headers.
- Add GitHub Actions CI workflow in `.github/workflows/test.yaml` running the
  test suite across Linux, macOS, and Windows on Python 3.10, 3.11, and 3.12.
- Add comprehensive unit tests in `tests/gui/test_plotly_viewer.py` and
  `tests/raytrace/component/test_component.py`.
- Make `tests/test_coding_standards.py` robust against missing linter tools.
…m and DovePrism, un-skip ray tests, and streamline wheel build workflow
…umpy allocations

- Replace O(N log N) numpy argsort and argmin in System.propagate_ray and Component.distance/propagate with inline C-scalar tracking
- Eliminate intermediate Python list allocations (dist_list, surf_list, comp_list, pi_list)
- Remove obsolete numpy array and isinf imports in Cython hot loops
- Remove deprecated setup_requires in setup.py to support fast incremental compilation
- Tracing throughput improved by ~3.5x (~140 us/ray vs ~494 us/ray)
…cript

- Track uv.lock in Git and remove from .gitignore for reproducible environments
- Update AGENTS.md with modern uv workflow, Ruff/cython-lint commands, and fast incremental Cython compilation
- Remove dead autopep8_cython.py script and update scripts/README.md
- Implement Component.hit_list using Eigen Vector3d/Matrix3d coordinate transformations
- Transform surface hit points into component coordinate system
- Resolves long-standing 'TODO: FIX THIS HITLIST TO WORK WITH EIGEN'
- Add test_component_hit_list unit test in tests/raytrace/component/test_component.py
…ug prints

- Remove dead stub files (gui/logutils.py and empty raytrace/config/config.py)
- Remove 292 lines of legacy '# ~' Geany toggle-comment blocks across 15 files
- Remove 110 lines of commented-out Python 2 / scipy.weave code from lsq.pyx
- Remove 43 commented-out '# print' debug statements
- Translate legacy Spanish code annotations in system.pyx and component.pyx into clean English
…ests

- Fix UnboundLocalError crash in detectOpenCL() when pyopencl is not installed
- Modernize detectCPUs() using os.cpu_count() or 1 instead of deprecated os.popen2
- Add test_resources.py unit test suite for detectCPUs and detectOpenCL
- Fix find_aperture() grid shape bug by using complex step in np.mgrid
- Fix chief_ray_search() IndexError when rays miss aperture detector
- Unskip and activate passing unit tests: test_paraxial_location, test_find_aperture, and test_find_ppp
…le proxies

- Fix Sphinx autodoc crash on dynamic catalog modules (library, material) by preserving standard module attributes (__name__, __doc__, etc.) and ignoring private/dunder attributes in __getattr__
- Add nbsphinx_execute = 'never' in doc/conf.py to prevent doc build crashes when Jupyter kernel is unavailable
- Update doc/install.rst with modern uv install commands (uv add / uv pip) and optional visualization packages
- Update doc/development.rst with uv sync, in-place Cython compilation, pytest, ruff, cython-lint, and local doc build instructions
- Update README.md with feature overview, quick installation, working quickstart raytrace example, and docs link
- Update CONTRIBUTING.md with Python >= 3.10 requirement and uv developer setup
Fixes NameError when doc notebooks and user scripts use 'from pyoptools.all import *'
and subsequently access vendor catalog parts via 'library' (e.g. library.Edmund.get()).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant