Skip to content

[Fixes / Docs]: Fix a sign error, add linter, type checker, and add examples to README#19

Merged
QuentinWach merged 9 commits into
mainfrom
strict
May 20, 2026
Merged

[Fixes / Docs]: Fix a sign error, add linter, type checker, and add examples to README#19
QuentinWach merged 9 commits into
mainfrom
strict

Conversation

@QuentinWach
Copy link
Copy Markdown
Collaborator

@QuentinWach QuentinWach commented May 20, 2026

Summary by CodeRabbit

Release Notes v0.1.0-alpha.4

  • New Features

    • Added Tidy3D modal sources/monitors example demonstrating field visualization.
    • Expanded examples with documented workflows (Tidy3D Waveguide and Hybridization Sweep).
  • Bug Fixes

    • Fixed y-normal field mapping sign issue with +y power overlap calculation.
  • Documentation

    • Updated README with new examples section and instructions.
    • Redesigned ridge waveguide example to angled-slab waveguide geometry.
  • Chores

    • Version bumped to 0.1.0-alpha.4.

Review Change Stack

…ype checking

- Added Clippy linting configuration to `Cargo.toml` to allow specific lints.
- Updated `pyproject.toml` to include new dependencies: `pyright` for type checking and `ruff` for linting.
- Enhanced GitHub Actions workflow to include a new linting job that runs Rust and Python linting checks before tests.
- Made minor formatting adjustments in various Python scripts for consistency and clarity.
…r scale normalization

- Updated axis limits to use dynamic extent values for better visualization.
- Added vmin and vmax parameters to the color mapping for improved clarity in mode field plots.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Warning

Rate limit exceeded

@QuentinWach has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 32 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 03c236b4-5602-4f3f-8671-18188406df5d

📥 Commits

Reviewing files that changed from the base of the PR and between 920e53e and 8b9afa9.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • .github/workflows/publish.yml
  • .github/workflows/tests.yml
  • examples/ridge_waveguide_readme.py
  • examples/tidy3d_modal_sources_monitors.py
  • pyproject.toml
  • python/micromode/result.py
  • tests/test_micromode_api.py
📝 Walkthrough

Walkthrough

This PR bumps MicroMode to version 0.1.0a4, fixes a y-normal field mapping sign bug affecting power overlap, refines Python type annotations and the PML/Materials API surface, adds stricter sequence validation via zip(..., strict=True), introduces a new Tidy3D modal example, redesigns the ridge waveguide example as an angled-slab geometry, and updates Rust eigensolver checkpointing logic.

Changes

0.1.0a4 Release with Field Mapping Fix and API Refinement

Layer / File(s) Summary
Version bump and CI/linting infrastructure
Cargo.toml, pyproject.toml, .github/workflows/tests.yml
Package version updated to 0.1.0a4. New lint job added to CI workflow running cargo fmt, cargo clippy, ruff, and pyright. Project-level ruff and pyright configuration sections added to pyproject.toml.
Y-normal field mapping sign correction and test
python/micromode/raster.py, CHANGELOG.md, tests/test_micromode_api.py
Applies sign flip in _local_fields_to_global when normal_axis == 1 to restore physical +y flux. Changelog documents fix for right-handed basis / +y power overlap sign. Regression test test_y_normal_power_overlap_is_positive verifies unit-magnitude positive-real power overlap for y-normal slices.
Type annotation and API surface refinement
python/micromode/_rust.py, python/micromode/models.py, python/micromode/result.py, python/micromode/sweep.py
Introduces SparseSolveResult type alias. PmlSpec.as_dict() replaced with profile_dict() (omits num_cells). BoundarySpec adds dmin_pmc property. Removes quoted forward references from Material/Result classmethods. Updates collections.abc imports across modules.
Solver and raster integration with refined APIs
python/micromode/raster.py
Calls pml_spec.profile_dict() instead of as_dict(), sources transformed mu tensor via _resolved_mu_tensor(), enforces component/field row alignment with strict zip, casts boundary tuples for type safety. Updates Yee grid dual-step computation clarity and initial vector assembly via per-x slice concatenation.
Validation tightening with strict sequence alignment
benchmarks/compare_mode_solver_fixtures.py, benchmarks/mode_solver/fixtures.py, examples/material_grid_demos.py, examples/ridge_waveguide_readme.py, examples/soi_hybridization_sweep.py, python/micromode/result.py
Applies zip(..., strict=True) throughout benchmarks, examples, and result loading to enforce sequence length matching, converting silent truncation into explicit errors.
Rust eigensolver and sparse matrix implementation details
src/eigensolve.rs, src/derivatives.rs, src/sparse_matrix.rs
Shifts profiling argument passing to direct profile instead of as_deref_mut(). Simplifies checkpoint_start using div_ceil. Changes checkpoint trigger from remainder check to is_multiple_of. Updates PML boundary guard from i <= n_pml - 1 to i < n_pml. Refactors sparse matrix column iteration with explicit mutable enumerate patterns.
New example and example updates
examples/tidy3d_modal_sources_monitors.py, examples/ridge_waveguide_readme.py, examples/README.md
Introduces complete tidy3d_modal_sources_monitors.py example with waveguide materials, mode solving, and field visualization. Redesigns ridge_waveguide_readme.py from SOI rib to angled-slab geometry with 80° sidewalls. Implements 3×2 component grid plotting with format_complex helper. Updates examples README with new entries and descriptions.
Demo script cleanups and validation updates
examples/material_grid_demos.py, examples/soi_hybridization_sweep.py
Updates material_grid_demos.py with collections.abc imports, rewrites boolean masks for slot/rib regions, consolidates formatting. Removes unused Patch import and add_panel_label function from soi_hybridization_sweep.py. Applies strict zip coordinate validation to both.
Build scripts and test harness updates
scripts/check_dist_artifacts.py, scripts/check_release_metadata.py, scripts/generate_coverage_badge.py, scripts/smoke_wheel.py, tests/test_mode_solver_fixtures.py
Replaces require() checks with explicit if-statements in validation scripts. Adds tomllib type-checking ignore. Converts smoke test edge arguments to tuple(float(...)). Reformats coverage badge generation. Reorganizes test imports.
Housekeeping: gitignore and documentation touch-ups
.gitignore, README.md, scripts/smoke_dist.py
Adds examples/tidy3d_modal_outputs/ to .gitignore. Minor whitespace adjustments in smoke_dist.py and README.md solver description.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • QuentinWach/micromode#7: Shift-invert eigensolver and native Rust sparse eigensolver refactor overlaps with this PR's checkpoint scheduling and profiling updates in src/eigensolve.rs.

Poem

🐰 A version hops forward, math signs now align,
Field mappings fixed with y-normal divine,
Types cleaned, validators strict and true,
New examples bloom with waveguides anew!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.51% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title broadly covers multiple aspects of the PR but accurately summarizes the main changes: a sign error fix for y-normal field mapping, addition of linting/type-checking workflow, and documentation updates including new examples.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch strict

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@QuentinWach QuentinWach changed the title [Fixes / Docs]: Fix a sign error and add examples to README [Fixes / Docs]: Fix a sign error, add linter, type checker, and add examples to README May 20, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/tests.yml:
- Around line 18-26: The workflow uses tag-pinned actions and leaves checkout
credentials persisted; update the steps using actions/checkout and
astral-sh/setup-uv (and any other action usages) to use commit SHAs instead of
tags and add persist-credentials: false to the actions/checkout step;
specifically locate the checkout step named "uses: actions/checkout@v4" and set
persist-credentials: false, and replace "uses: astral-sh/setup-uv@v5" (and any
other tag-pinned actions such as those for rust tooling if applicable) with
their corresponding full commit SHA refs to harden supply-chain integrity.

In `@examples/ridge_waveguide_readme.py`:
- Around line 104-111: The functions centered_edges and offset_edges can produce
invalid grids or divide-by-zero for nonpositive or too-large step values; add
input guards: validate that step > 0, compute cells = round(width / step) (or
round((upper - lower) / step)) and ensure cells >= 1 (and for offset_edges also
verify upper > lower), and raise a clear ValueError if these checks fail before
calling np.linspace so linspace always receives a positive count (cells + 1) and
valid bounds.

In `@examples/tidy3d_modal_sources_monitors.py`:
- Around line 93-95: The centered_edges function should validate inputs: ensure
step is positive (step > 0) to avoid divide-by-zero and compute cells =
round(width / step) then require cells >= 1; if these checks fail, raise a
ValueError with a clear message referencing width and step. Update
centered_edges to perform these validations before calling np.linspace so bad
CLI inputs fail fast and produce an actionable error.

In `@python/micromode/result.py`:
- Line 335: The assignment to solver_info currently wraps the HDF5 attribute in
str(), which mangles bytes payloads (e.g. b'{"ok":true}') and breaks json.loads;
update the solver_info assignment (the line creating solver_info from
handle.attrs["solver_info"]) to pass the raw attribute value to json.loads
(i.e., remove the str() coercion) so bytes returned by h5py are handled
correctly.

In `@scripts/check_release_metadata.py`:
- Around line 10-12: The fallback import for tomli in
scripts/check_release_metadata.py lacks the type-check ignore; update the
fallback import statement "import tomli as tomllib" to include the same comment
as the primary import by adding "# type: ignore[import-not-found]" so pyright
won't error during type-checking.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b9cec96f-49fa-4ff8-9690-cda8d1b6f153

📥 Commits

Reviewing files that changed from the base of the PR and between a188999 and 920e53e.

⛔ Files ignored due to path filters (5)
  • Cargo.lock is excluded by !**/*.lock
  • docs/assets/hybridization_sweep.png is excluded by !**/*.png
  • docs/assets/ridge_modes.png is excluded by !**/*.png
  • docs/assets/tidy3d_modal_modes.png is excluded by !**/*.png
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (28)
  • .github/workflows/tests.yml
  • .gitignore
  • CHANGELOG.md
  • Cargo.toml
  • README.md
  • benchmarks/compare_mode_solver_fixtures.py
  • benchmarks/mode_solver/fixtures.py
  • examples/README.md
  • examples/material_grid_demos.py
  • examples/ridge_waveguide_readme.py
  • examples/soi_hybridization_sweep.py
  • examples/tidy3d_modal_sources_monitors.py
  • pyproject.toml
  • python/micromode/_rust.py
  • python/micromode/models.py
  • python/micromode/raster.py
  • python/micromode/result.py
  • python/micromode/sweep.py
  • scripts/check_dist_artifacts.py
  • scripts/check_release_metadata.py
  • scripts/generate_coverage_badge.py
  • scripts/smoke_dist.py
  • scripts/smoke_wheel.py
  • src/derivatives.rs
  • src/eigensolve.rs
  • src/sparse_matrix.rs
  • tests/test_micromode_api.py
  • tests/test_mode_solver_fixtures.py
💤 Files with no reviewable changes (1)
  • scripts/smoke_dist.py

Comment on lines +18 to +26
- uses: actions/checkout@v4

- name: Install Rust tooling
run: rustup component add rustfmt clippy

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "latest"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify unpinned action refs and checkout credential persistence in workflow files.
rg -n 'uses:\s*[^ ]+@v[0-9]+' .github/workflows/tests.yml
rg -n -A3 -B1 'uses:\s*actions/checkout@' .github/workflows/tests.yml

Repository: QuentinWach/micromode

Length of output: 1232


Pin action SHAs and disable checkout credential persistence.

The actions at these lines are tag-pinned (@v4, @v5) rather than commit-pinned, and actions/checkout lacks persist-credentials: false. This weakens CI supply-chain hardening.

Suggested hardening
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@<pinned-commit-sha>
+        with:
+          persist-credentials: false

-      - name: Install uv
-        uses: astral-sh/setup-uv@v5
+      - name: Install uv
+        uses: astral-sh/setup-uv@<pinned-commit-sha>
         with:
           version: "latest"

Note: This pattern appears throughout the workflow file; consider applying the same hardening to all action usages.

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 18-18: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 18-18: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 24-24: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/tests.yml around lines 18 - 26, The workflow uses
tag-pinned actions and leaves checkout credentials persisted; update the steps
using actions/checkout and astral-sh/setup-uv (and any other action usages) to
use commit SHAs instead of tags and add persist-credentials: false to the
actions/checkout step; specifically locate the checkout step named "uses:
actions/checkout@v4" and set persist-credentials: false, and replace "uses:
astral-sh/setup-uv@v5" (and any other tag-pinned actions such as those for rust
tooling if applicable) with their corresponding full commit SHA refs to harden
supply-chain integrity.

Comment thread examples/ridge_waveguide_readme.py
Comment on lines +93 to +95
def centered_edges(*, width: float, step: float) -> np.ndarray:
cells = round(width / step)
return np.linspace(-0.5 * width, 0.5 * width, cells + 1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate step and enforce at least one cell in centered_edges.

round(width / step) can produce invalid grids (or divide-by-zero) for bad CLI inputs; fail fast with a clear error.

Suggested fix
 def centered_edges(*, width: float, step: float) -> np.ndarray:
+    if not np.isfinite(step) or step <= 0:
+        raise ValueError("step must be finite and > 0")
     cells = round(width / step)
+    if cells < 1:
+        raise ValueError("step is too large for width; expected at least one cell")
     return np.linspace(-0.5 * width, 0.5 * width, cells + 1)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def centered_edges(*, width: float, step: float) -> np.ndarray:
cells = round(width / step)
return np.linspace(-0.5 * width, 0.5 * width, cells + 1)
def centered_edges(*, width: float, step: float) -> np.ndarray:
if not np.isfinite(step) or step <= 0:
raise ValueError("step must be finite and > 0")
cells = round(width / step)
if cells < 1:
raise ValueError("step is too large for width; expected at least one cell")
return np.linspace(-0.5 * width, 0.5 * width, cells + 1)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/tidy3d_modal_sources_monitors.py` around lines 93 - 95, The
centered_edges function should validate inputs: ensure step is positive (step >
0) to avoid divide-by-zero and compute cells = round(width / step) then require
cells >= 1; if these checks fail, raise a ValueError with a clear message
referencing width and step. Update centered_edges to perform these validations
before calling np.linspace so bad CLI inputs fail fast and produce an actionable
error.

Comment thread python/micromode/result.py Outdated
Comment on lines +10 to 12
import tomllib # type: ignore[import-not-found]
except ModuleNotFoundError: # pragma: no cover - Python 3.10 compatibility.
import tomli as tomllib
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify whether tomli is declared anywhere and inspect type-check config.
rg -n --iglob 'pyproject.toml' --iglob 'requirements*.txt' --iglob '*lock*' '\btomli\b|requires-python|pyright'

Repository: QuentinWach/micromode

Length of output: 11043


🏁 Script executed:

cat -n pyproject.toml | sed -n '90,110p'

Repository: QuentinWach/micromode

Length of output: 357


🏁 Script executed:

cat -n scripts/check_release_metadata.py | head -20

Repository: QuentinWach/micromode

Length of output: 669


🏁 Script executed:

rg -A 20 '\[tool\.pyright\]' pyproject.toml

Repository: QuentinWach/micromode

Length of output: 225


Add # type: ignore[import-not-found] to the fallback tomli import on line 12.

The fallback import at line 12 needs the same type-checking ignore as line 10. Even though tomli is declared in pyproject.toml as a conditional dev dependency (python_version < '3.11'), pyright configured in basic mode at Python 3.10 doesn't recognize it as available during type-checking. Add the matching ignore comment to make CI pass.

Suggested patch
 try:
     import tomllib  # type: ignore[import-not-found]
 except ModuleNotFoundError:  # pragma: no cover - Python 3.10 compatibility.
-    import tomli as tomllib
+    import tomli as tomllib  # type: ignore[import-not-found]
🧰 Tools
🪛 GitHub Actions: Tests / 4_Lint and type check.txt

[error] 12-12: pyright: Import "tomli" could not be resolved (reportMissingImports).

🪛 GitHub Actions: Tests / Lint and type check

[error] 12-12: pyright: Import "tomli" could not be resolved (reportMissingImports)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check_release_metadata.py` around lines 10 - 12, The fallback import
for tomli in scripts/check_release_metadata.py lacks the type-check ignore;
update the fallback import statement "import tomli as tomllib" to include the
same comment as the primary import by adding "# type: ignore[import-not-found]"
so pyright won't error during type-checking.

- Updated GitHub Actions workflows to disable credential persistence during checkout for better security.
- Added input validation in `centered_edges` and `offset_edges` functions to ensure positive step sizes and valid width/upper-lower relationships.
- Refactored solver info access in tests for improved clarity and maintainability.
@QuentinWach QuentinWach merged commit 8d68e83 into main May 20, 2026
9 checks passed
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