Skip to content

Implement CFD grid interpolation logic for validation#268

Open
ryancinsight wants to merge 3 commits intomainfrom
implement-interpolate-todo-236727742202006950
Open

Implement CFD grid interpolation logic for validation#268
ryancinsight wants to merge 3 commits intomainfrom
implement-interpolate-todo-236727742202006950

Conversation

@ryancinsight
Copy link
Owner

@ryancinsight ryancinsight commented Mar 16, 2026

This pull request implements the TODO: Interpolate if needed in validation/compare_cavity_external.py.

Changes:

  • Added scipy.interpolate.RectBivariateSpline to handle grid size mismatches between the cfd_python result and the external reference solution.
  • Updated the validation script to skip 2D comparisons if full 2D fields (u_field, v_field, p_field) are not exported from the Rust solver via cfd_python.
  • Added __pycache__/ to .gitignore.

PR created automatically by Jules for task 236727742202006950 started by @ryancinsight

High-level PR Summary

This PR implements CFD grid interpolation for validation by replacing a TODO placeholder with bivariate spline interpolation using scipy.interpolate.RectBivariateSpline to handle grid size mismatches between the cfd_python solver results and external reference solutions. The validation script now gracefully handles cases where the Rust solver doesn't export full 2D fields, and adds common Python artifacts to .gitignore.

⏱️ Estimated Review Time: 5-15 minutes

💡 Review Order Suggestion
Order File Path
1 .gitignore
2 validation/compare_cavity_external.py

Need help? Join our Discord

Summary by CodeRabbit

  • Bug Fixes

    • Improved grid-mismatch handling in CFD comparisons by interpolating results to match external grids; recomputed centerlines accordingly.
    • Enhanced robustness when solver outputs are missing with warnings and safe fallback values; added informational logs for interpolation and missing fields.
  • Chores

    • Updated ignore patterns to exclude virtual environments and Python caches.
    • CI benchmarking workflow updated to run the renamed performance benchmark.

…nal reference

Co-authored-by: ryancinsight <55164720+ryancinsight@users.noreply.github.com>
@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the CFD validation framework by introducing robust grid interpolation capabilities, allowing for accurate comparisons between CFD Python results and external solutions even when their computational grids differ. It also improves the script's resilience by conditionally skipping 2D comparisons if the solver doesn't provide full field data, and updates solver parameter handling for better compatibility. These changes collectively make the validation process more flexible and less prone to failure due to grid discrepancies or incomplete solver outputs.

Highlights

  • Grid Interpolation: Implemented scipy.interpolate.RectBivariateSpline to handle grid size mismatches between CFD Python results and external reference solutions, ensuring comparisons can proceed even with differing discretizations.
  • Conditional 2D Comparison: Updated the validation script to gracefully skip 2D field comparisons if the cfd_python solver does not export full 2D fields (u_field, v_field, p_field), preventing errors in such scenarios.
  • Solver Parameter Update: Adjusted the CavitySolver2D instantiation to use reynolds instead of Re and removed tolerance and max_iterations parameters, aligning with potential changes in the underlying Rust solver's Python binding.
  • Gitignore Update: Added __pycache__/ to the .gitignore file to prevent Python bytecode cache directories from being committed to the repository.
Changelog
  • .gitignore
    • Added __pycache__/ to the list of ignored files.
  • validation/compare_cavity_external.py
    • Imported RectBivariateSpline from scipy.interpolate.
    • Modified run_cfd_python_cavity to check for the presence of full fields (u_field, v_field, p_field) before returning results, printing a warning and returning None if not found.
    • Updated CavitySolver2D instantiation to use reynolds parameter and removed tolerance and max_iterations.
    • Implemented grid interpolation logic using RectBivariateSpline within compare_solutions to resample cfd_python_result fields to match the external_result grid when shapes differ.
    • Updated centerline data and coordinates in cfd_python_result after interpolation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces interpolation logic to handle grid mismatches in the compare_cavity_external.py validation script, which is a necessary feature for comparing simulation results from different sources. The changes also improve robustness by gracefully handling cases where full 2D fields are not available from the Rust solver. The addition of __pycache__/ and venv/ to .gitignore is a good housekeeping change.

My review includes suggestions to further improve the new code. I've recommended refactoring the interpolation logic to reduce duplication, making it more maintainable. I've also suggested a more robust check for the presence of all required data fields to prevent potential AttributeError exceptions.

Comment on lines +57 to +61
if hasattr(result, "u_field"):
return {
"u": np.array(result.u_field),
"v": np.array(result.v_field),
"p": np.array(result.p_field),
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The check for u_field improves robustness. However, it implicitly assumes that if u_field exists, v_field and p_field also exist. This could lead to an AttributeError if one of them is missing. It would be safer to explicitly check for all required fields before attempting to access them.

Suggested change
if hasattr(result, "u_field"):
return {
"u": np.array(result.u_field),
"v": np.array(result.v_field),
"p": np.array(result.p_field),
if all(hasattr(result, f) for f in ("u_field", "v_field", "p_field")):
return {
"u": np.array(result.u_field),
"v": np.array(result.v_field),
"p": np.array(result.p_field),

Comment on lines +120 to +128
# Interpolate fields (transpose as RectBivariateSpline expects [x, y] ordering)
spline_u = RectBivariateSpline(x_orig, y_orig, cfd_python_result["u"].T)
spline_v = RectBivariateSpline(x_orig, y_orig, cfd_python_result["v"].T)
spline_p = RectBivariateSpline(x_orig, y_orig, cfd_python_result["p"].T)

# Evaluate on new grid (and transpose back to [y, x] ordering)
cfd_python_result["u"] = spline_u(x_new, y_new).T
cfd_python_result["v"] = spline_v(x_new, y_new).T
cfd_python_result["p"] = spline_p(x_new, y_new).T
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

To improve maintainability and reduce code duplication, the interpolation logic for the u, v, and p fields can be refactored into a loop. This makes the code more concise and easier to modify if more fields need interpolation in the future.

Suggested change
# Interpolate fields (transpose as RectBivariateSpline expects [x, y] ordering)
spline_u = RectBivariateSpline(x_orig, y_orig, cfd_python_result["u"].T)
spline_v = RectBivariateSpline(x_orig, y_orig, cfd_python_result["v"].T)
spline_p = RectBivariateSpline(x_orig, y_orig, cfd_python_result["p"].T)
# Evaluate on new grid (and transpose back to [y, x] ordering)
cfd_python_result["u"] = spline_u(x_new, y_new).T
cfd_python_result["v"] = spline_v(x_new, y_new).T
cfd_python_result["p"] = spline_p(x_new, y_new).T
# Interpolate fields (transpose as RectBivariateSpline expects [x, y] ordering)
for field_key in ("u", "v", "p"):
spline = RectBivariateSpline(x_orig, y_orig, cfd_python_result[field_key].T)
# Evaluate on new grid and transpose back to [y, x] ordering
cfd_python_result[field_key] = spline(x_new, y_new).T

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

Warning

Rate limit exceeded

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

⌛ 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: 3d5d8497-d34e-4906-848e-fcc98ebd825a

📥 Commits

Reviewing files that changed from the base of the PR and between 70fffcc and bda3362.

📒 Files selected for processing (1)
  • .github/workflows/performance-benchmarking.yml
📝 Walkthrough

Walkthrough

Updated repository ignores for Python virtualenvs and bytecode. Enhanced validation logic in validation/compare_cavity_external.py to standardize solver argument name, validate solver output, and interpolate CFD fields onto an external grid when grids differ.

Changes

Cohort / File(s) Summary
Configuration
./.gitignore
Added ignore patterns for virtual environments (ven v/) and Python bytecode caches (__pycache__/).
CFD Validation & Comparison
validation/compare_cavity_external.py
Imported SciPy RectBivariateSpline; changed solver init arg from Re to reynolds; added checks for u_field presence and safe defaults for iterations/residual; interpolate CFD u,v,p and centerlines onto external grid when grids mismatch; added informational/warning logs around interpolation and missing fields.
CI Workflow
.github/workflows/performance-benchmarking.yml
Switched Rust benchmark target from comprehensive_cfd_benchmarks to performance_benchmarks in build and run steps.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User
participant Validator as Validation Module
participant Solver as CavitySolver2D
participant Interpolator as SciPy RectBivariateSpline
participant ExtSol as External Solution
participant Logger

User->>Validator: run compare_solutions(ext_sol)
Validator->>Solver: init(reynolds=..., grid=...)
Solver-->>Validator: result (may contain u_field, v_field, p_field)
alt result missing u_field
    Validator->>Logger: warn missing fields
    Validator-->>User: return None
else result has fields
    Validator->>ExtSol: read grid (ext_x, ext_y)
    alt grids differ
        Validator->>Interpolator: build from CFD (x,y,u/v/p)
        Interpolator-->>Validator: interpolated u',v',p' on ext grid
        Validator->>Logger: info interpolation performed
    end
    Validator->>Logger: info returning matched solution
    Validator-->>User: return comparison data (u,v,p,centerlines,coords,iterations,residual)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through ignores and splines so fine,

Virtual nests tucked out of sight,
Reynolds whispered its proper line,
Fields stretched to match a foreign grid tonight,
My little paws aligned each flow with delight.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the main change: implementing CFD grid interpolation logic for validation, which directly corresponds to the primary modification in validation/compare_cavity_external.py.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch implement-interpolate-todo-236727742202006950
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Copy link

@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.

🧹 Nitpick comments (1)
validation/compare_cavity_external.py (1)

109-134: Interpolation logic looks correct; note that input dict is mutated.

The transpose handling is correct: fields stored as (ny, nx) are transposed to (nx, ny) for RectBivariateSpline, then transposed back after evaluation. The centerline recomputation also follows the correct row/column conventions.

One minor observation: this directly mutates cfd_python_result rather than creating a copy. This is fine for the current single-use validation context, but if this function were reused, the caller's original data would be modified.

Optional: work on a copy to avoid mutation
     if cfd_python_result["u"].shape != ext_sol["u"].shape:
         print(f"INFO: Interpolating cfd_python results from {cfd_python_result['u'].shape} to external {ext_sol['u'].shape} grid")
 
+        # Work on a copy to preserve original data
+        cfd_python_result = cfd_python_result.copy()
+
         # Original grid (assuming regular grid)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@validation/compare_cavity_external.py` around lines 109 - 134, The current
interpolation mutates the input dictionary cfd_python_result (fields u,v,p, x,y
and centerlines) in-place; to avoid side effects, create a shallow copy of
cfd_python_result at the start of the interpolation block (e.g., copy =
cfd_python_result.copy() or use dict(copy) or deep copy if nested) and perform
all RectBivariateSpline setup and assignments (spline_u/spline_v/spline_p,
evaluations, and updates to u_centerline/v_centerline/x/y) on that copy, then
return or use the copy instead of overwriting the original cfd_python_result.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@validation/compare_cavity_external.py`:
- Around line 109-134: The current interpolation mutates the input dictionary
cfd_python_result (fields u,v,p, x,y and centerlines) in-place; to avoid side
effects, create a shallow copy of cfd_python_result at the start of the
interpolation block (e.g., copy = cfd_python_result.copy() or use dict(copy) or
deep copy if nested) and perform all RectBivariateSpline setup and assignments
(spline_u/spline_v/spline_p, evaluations, and updates to
u_centerline/v_centerline/x/y) on that copy, then return or use the copy instead
of overwriting the original cfd_python_result.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 76dcd4c0-77f3-4d46-8167-e6f5e2a90577

📥 Commits

Reviewing files that changed from the base of the PR and between 6be1767 and 5b674c7.

📒 Files selected for processing (2)
  • .gitignore
  • validation/compare_cavity_external.py

Copy link

@recurseml recurseml bot left a comment

Choose a reason for hiding this comment

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

Review by RecurseML

🔍 Review performed on 6be1767..5b674c7

  Severity     Location     Issue     Delete  
High validation/compare_cavity_external.py:121 Missing coordinate validation causes crash
✅ Files analyzed, no issues (1)

.gitignore

y_new = ext_sol["y"]

# Interpolate fields (transpose as RectBivariateSpline expects [x, y] ordering)
spline_u = RectBivariateSpline(x_orig, y_orig, cfd_python_result["u"].T)
Copy link

Choose a reason for hiding this comment

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

RectBivariateSpline requires coordinate arrays to be strictly ascending. The code does not validate that x_orig and y_orig (from cfd_python result.x_coords and result.y_coords) are strictly ascending before calling RectBivariateSpline. If the Rust solver returns non-ascending, descending, or duplicate coordinate values, this will crash with a ValueError. According to scipy documentation: 'x,y array_like: 1-D arrays of coordinates in strictly ascending order.' The same issue affects lines 122 and 123. This validation script will crash at runtime if grid coordinates from cfd_python are not properly sorted.


React with 👍 to tell me that this comment was useful, or 👎 if not (and I'll stop posting more comments like this in the future)

Co-authored-by: ryancinsight <55164720+ryancinsight@users.noreply.github.com>
Copy link

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/performance-benchmarking.yml (1)

83-91: ⚠️ Potential issue | 🟠 Major

regression/production steps still call undeclared bench targets.

cargo bench --bench regression_detection (Line 86) and cargo bench --bench production_validation (Line 91) do not match declared bench targets in Cargo.toml (context shows only performance_benchmarks). Because Line 84 triggers regression on schedule events, weekly runs can fail consistently.

#!/bin/bash
set -euo pipefail

echo "Workflow bench invocations:"
rg -n 'cargo bench --bench' .github/workflows/performance-benchmarking.yml

echo
echo "Declared [[bench]] names in Cargo.toml:"
python - <<'PY'
import pathlib, re
text = pathlib.Path("Cargo.toml").read_text(encoding="utf-8")
blocks = re.findall(r'\[\[bench\]\](.*?)(?=\n\[\[|\Z)', text, flags=re.S)
names = []
for b in blocks:
    m = re.search(r'^\s*name\s*=\s*"([^"]+)"', b, flags=re.M)
    if m:
        names.append(m.group(1))
print("\n".join(names) if names else "(none)")
PY

Expected result: workflow references regression_detection / production_validation, while Cargo declares only performance_benchmarks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/performance-benchmarking.yml around lines 83 - 91, The
workflow steps call non-existent bench targets ("cargo bench --bench
regression_detection" and "--bench production_validation"); update the Run
regression detection benchmarks and Run production validation benchmarks steps
to invoke the actual declared benchmark target (performance_benchmarks) or add
matching [[bench]] entries in Cargo.toml; specifically change the cargo
invocations referenced by the step names (Run regression detection benchmarks /
Run production validation benchmarks) to use --bench performance_benchmarks (or
ensure Cargo.toml contains names regression_detection and production_validation)
so scheduled/conditional runs no longer fail.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In @.github/workflows/performance-benchmarking.yml:
- Around line 83-91: The workflow steps call non-existent bench targets ("cargo
bench --bench regression_detection" and "--bench production_validation"); update
the Run regression detection benchmarks and Run production validation benchmarks
steps to invoke the actual declared benchmark target (performance_benchmarks) or
add matching [[bench]] entries in Cargo.toml; specifically change the cargo
invocations referenced by the step names (Run regression detection benchmarks /
Run production validation benchmarks) to use --bench performance_benchmarks (or
ensure Cargo.toml contains names regression_detection and production_validation)
so scheduled/conditional runs no longer fail.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0c7e934d-7066-4293-90b3-48e5febc9ee7

📥 Commits

Reviewing files that changed from the base of the PR and between 5b674c7 and 70fffcc.

📒 Files selected for processing (1)
  • .github/workflows/performance-benchmarking.yml

Co-authored-by: ryancinsight <55164720+ryancinsight@users.noreply.github.com>
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