Skip to content

feature: integrate rotations into ICPP patches (#1594)#1612

Draft
SVS87 wants to merge 8 commits into
MFlowCode:masterfrom
SVS87:feature/icpp-patch-rotations
Draft

feature: integrate rotations into ICPP patches (#1594)#1612
SVS87 wants to merge 8 commits into
MFlowCode:masterfrom
SVS87:feature/icpp-patch-rotations

Conversation

@SVS87

@SVS87 SVS87 commented Jun 20, 2026

Copy link
Copy Markdown

Description

Add a rotation framework to initial-condition (ICPP) patches, mirroring the existing immersed-boundary rotation support.

  • Extract the rotation-matrix computation into a new shared module m_patch_geometries, taking angle/matrix arrays as arguments so both ICPP and IB patches can call it (m_ib_patches now uses a thin wrapper).
  • Add angles + rotation_matrix(_inverse) fields to ic_patch_parameters, defaulting angles to zero (identity rotation) so existing cases are unaffected.
  • Apply the inverse-rotation transform in the rectangle inside-test as a proof of concept; remaining geometries are straightforward follow-up.
  • Register patch_icpp(i)%angles in the parameter definitions so the angle is settable from a case file.
  • Add a 2D_rotated_rectangle example demonstrating a 45-degree patch.

Part of #1594

Type of change (delete unused ones)

  • New feature
  • Refactor

Testing

  • Built pre_process and simulation against current master.
  • Full CPU test suite passes; the angles=0 default makes the rotation
    behavior-neutral for all existing cases.
  • IB patch tests pass after routing s_update_ib_rotation_matrix through
    the shared s_compute_rotation_matrix, confirming the extracted routine
    matches the original.
  • Added examples/2D_rotated_rectangle (45-degree patch); pre_process
    output shows the rectangle correctly tilted (image below).
rotated_rectangle_fields

Checklist

Check these like this [x] to indicate which of the below applies.

  • I added or updated tests for new behavior
  • I updated documentation if user-facing behavior changed

See the developer guide for full coding standards.

GPU changes (expand if you modified src/simulation/)
  • GPU results match CPU results
  • Tested on NVIDIA GPU or AMD GPU
    Verified CPU only

AI code reviews

Reviews are not retriggered automatically. To request a review, comment on the PR:

  • @claude full review — Claude full review (also triggers on PR open/reopen/ready)
  • Or add label claude-full-review — Claude full review via label

@SVS87 SVS87 requested a review from sbryngelson as a code owner June 20, 2026 01:04
@SVS87 SVS87 force-pushed the feature/icpp-patch-rotations branch 2 times, most recently from 423d5f1 to f0332b3 Compare June 20, 2026 04:47
Add a rotation framework to initial-condition (ICPP) patches, mirroring
the existing immersed-boundary rotation support.

- Extract the rotation-matrix computation into a new shared module
  m_patch_geometries, taking angle/matrix arrays as arguments so both
  ICPP and IB patches can call it (m_ib_patches now uses a thin wrapper).
- Add angles + rotation_matrix(_inverse) fields to ic_patch_parameters,
  defaulting angles to zero (identity rotation) so existing cases are
  unaffected.
- Apply the inverse-rotation transform in the rectangle inside-test as a
  proof of concept; remaining geometries are straightforward follow-up.
- Register patch_icpp(i)%angles in the parameter definitions so the angle
  is settable from a case file.
- Add a 2D_rotated_rectangle example demonstrating a 45-degree patch.
@SVS87 SVS87 force-pushed the feature/icpp-patch-rotations branch from f0332b3 to c4dea86 Compare June 20, 2026 04:51
@sbryngelson sbryngelson marked this pull request as draft June 20, 2026 05:59
@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 70.73171% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.50%. Comparing base (5385190) to head (cf6be2f).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
src/pre_process/m_icpp_patches.fpp 41.17% 8 Missing and 2 partials ⚠️
src/common/m_patch_geometries.fpp 89.47% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1612   +/-   ##
=======================================
  Coverage   60.50%   60.50%           
=======================================
  Files          83       83           
  Lines       19909    19915    +6     
  Branches     2951     2951           
=======================================
+ Hits        12046    12050    +4     
- Misses       5869     5871    +2     
  Partials     1994     1994           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@danieljvickers danieljvickers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These are pretty much all the same changes I would have made. Well done. Two notes before this should be merged:

  1. I assume you are still working on integrating this with all of the other icpp patch geometries. This should be integrated with all of them before this can be merged. The STL geometry will require some special attention. Just copy what is in the m_ib_patches.fpp file.
  2. The wrapper function in simulation around the s_compute_rotation_matrix subroutine is necessary. It adds nothing meaningful and should be removed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not sure about this name, as it could get confused with IB patch code. Maybe speciify it is a fluid patch?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Changing it to 2D_rotated_fluid_rectangle. Would that work?

Comment thread src/common/m_patch_geometries.fpp Outdated
real(wp), dimension(1:3,1:3), intent(out) :: rotation_matrix
real(wp), dimension(1:3,1:3), intent(out) :: rotation_matrix_inverse
real(wp), dimension(3, 3, 3) :: rotation
real(wp) :: angle

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a reason to add this additional angle value?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Removed it, it was unnecessary. Updated change just uses angles(1, 2, 3) respectively

real(wp), dimension(1:3), intent(in) :: angles
real(wp), dimension(1:3,1:3), intent(out) :: rotation_matrix
real(wp), dimension(1:3,1:3), intent(out) :: rotation_matrix_inverse
real(wp), dimension(3, 3, 3) :: rotation

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Making this 3x3x3 is a nice touch

! Assign patch vars if cell is covered and patch has write permission
do j = 0, n
do i = 0, m
if (f_is_inside_cuboid(x_cc(i) - x_centroid, y_cc(j) - y_centroid, 0._wp, [length_x, length_y, 0._wp])) then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see where you added cuboids. I assume you are in the process of adding this to the remaining geometries? That is fine if so. It just needs to be integrated with all of them before merge.

Comment thread src/simulation/m_ib_patches.fpp Outdated
@@ -415,45 +415,10 @@ contains

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This wrapper function is now unnecessary. You should just modify the code everywhere to take the new rotation matrix subroutine and delete this subroutine all together.

SVS87 added 4 commits June 20, 2026 23:43
…ation wrapper

- Extend rotation transform to ellipse, ellipsoid, cuboid, cylinder, TaylorGreen, and STL (mirroring m_ib_patches.fpp; omits IB-only centroid_offset)
- Skip circle/sphere as rotation-invariant
- Remove unused angle variable in s_compute_rotation_matrix
- Delete s_update_ib_rotation_matrix wrapper; callers now call s_compute_rotation_matrix directly
- Rename example to 2D_rotated_fluid_rectangle to clarify it is an ICPP patch
- Add model_rotate parameter to stl_models (parallel to model_scale/model_translate), applied at model load in s_instantiate_STL_models so STL geometry rotates in world coordinates
- Wire model_rotate through derived type, defaults, MPI broadcast, and toolchain registration
- Verified: a cube rotated 45 degrees about z expands its x/y bounding box by sqrt(2) as expected
- Extend per-cell rotation to remaining ICPP geometries (ellipse, ellipsoid, cuboid, cylinder, TaylorGreen)
@SVS87 SVS87 marked this pull request as ready for review June 21, 2026 17:55
@sbryngelson sbryngelson marked this pull request as draft June 22, 2026 15:27
@SVS87 SVS87 marked this pull request as ready for review June 22, 2026 22:53

@sbryngelson sbryngelson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed the rotation framework. The core math is sound and the refactor of the IB rotation routine into the shared s_compute_rotation_matrix is faithful (identical computation, just parameterized). The inside-test/smoothing changes reduce exactly to the original expressions when angles = 0, so existing non-rotated cases are unaffected, and every dispatch branch (3D/2D/1D) computes the rotation matrix before use, so rotation_matrix_inverse is never read uninitialized. Verified the cylinder-3D axis permutations and ellipse/cuboid component mappings match the originals.

Two issues I'd consider blockers, plus minor notes:

1. (blocker) patch_icpp%angles is never broadcast to non-root MPI ranks — see inline comment. Multi-rank pre_process of a rotated patch will rotate the patch only on rank 0's subdomain and leave it axis-aligned everywhere else (silent, decomposition-dependent wrong IC). Note this is a CPU/MPI issue — pre_process is CPU-only but still runs multi-rank, so the bug is fully live.

2. (blocker) The new rotation tests aren't registeredtests/A9D344BA and tests/E01D26AE golden files were added, but toolchain/mfc/test/cases.py is not modified, so no test produces those hashes. As-is the golden files are orphaned and the feature has zero CI coverage. (The golden-metadata shows they were generated from a local feature/icpp-patch-rotations (dirty) tree — looks like the cases.py additions were left out of the PR.)

Minor (non-blocking):

  • Example dir is examples/2D_rotated_fluid_rectangle/ but the PR description calls it 2D_rotated_rectangle.
  • GPU scope (to be precise): the new ICPP rotation path (m_icpp_patches.fpp) runs only in pre_process, which is CPU-only — so the feature this PR adds has no GPU concern. The only GPU-relevant change is that s_compute_rotation_matrix moved out of m_ib_patches (src/simulation) into m_patch_geometries (src/common); it's still called on-device from m_ibm.fpp inside $:GPU_PARALLEL_LOOP — but that's the pre-existing IB path, unchanged in behavior (just relocated). The only residual question is whether the relocated routine still gets device codegen, which should be fine since m_patch_geometries already exports device routines (f_is_inside_*) used inside simulation GPU loops. Worth one device build to confirm, but low risk.
  • The PR description says only the rectangle inside-test was rotated 'as a proof of concept', but the diff actually rotates ellipse, ellipsoid, rectangle, Taylor-Green rectangle, 3D cuboid, and 3D cylinder — description undersells the change.

patch_icpp(i)%epsilon = dflt_real
patch_icpp(i)%beta = dflt_real
patch_icpp(i)%normal = dflt_real
patch_icpp(i)%angles = 0._wp

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This 0 default is exactly the value non-root MPI ranks will keep, because patch_icpp%angles is never broadcast. In src/pre_process/m_mpi_proxy.fpp the patch_icpp array-field broadcast loop (around line 103) is #:for VAR in ['normal','radii','vel','tau_e','alpha_rho','alpha','fourier_cos','fourier_sin']angles is missing. patch_icpp is intentionally part of the manual broadcast residue (see toolchain/.../fortran_gen.py, which lists patch_icpp as manual), so it is NOT covered by generated_bcast.fpp; the manual loop is the only broadcaster.

Consequence: only rank 0 reads angles from the case file. Each rank then computes rotation_matrix(_inverse) locally from its own angles, so non-root ranks build the identity → their subdomains get the patch unrotated. In a multi-rank pre_process run this produces a torn initial condition (rotated on rank 0, axis-aligned elsewhere), silently and dependent on domain decomposition. Affects every rotated geometry in this PR.

Fix: add 'angles' to that #:for VAR list in m_mpi_proxy.fpp (rotation_matrix/rotation_matrix_inverse are recomputed per-rank and don't need broadcasting). Also regenerate the golden files afterward, since any that were produced multi-rank would encode the pre-fix torn output.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Concrete fix (GitHub won't let me post this as a click-to-apply suggestion because the target line in src/pre_process/m_mpi_proxy.fpp — the patch_icpp array-field broadcast loop, ~line 103 — isn't part of this PR's diff). The one-line change is to add 'angles' to that loop:

            #:for VAR in [ 'angles', 'normal', 'radii', 'vel', 'tau_e', 'alpha_rho', 'alpha', &
                'fourier_cos', 'fourier_sin' ]
                call MPI_BCAST(patch_icpp(i)%${VAR}$, size(patch_icpp(i)%${VAR}$), mpi_p, 0, MPI_COMM_WORLD, ierr)
            #:endfor

size(patch_icpp(i)%angles) == 3, matching the other rank-1 members already in the loop, so no special-casing is needed. rotation_matrix/rotation_matrix_inverse are recomputed per-rank and don't need broadcasting. After applying, regenerate any goldens that were produced multi-rank.

@@ -0,0 +1,159 @@
This file was created on 2026-06-20 00:40:29.329446.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These golden files (tests/A9D344BA, tests/E01D26AE) don't appear to be wired to any registered test: toolchain/mfc/test/cases.py isn't modified in this PR and contains no rotation/angles case, so nothing generates these hashes. As-is they're orphaned — ./mfc.sh test won't exercise them and the rotation feature has no CI coverage. Looks like the cases.py additions (which exist on your local feature/icpp-patch-rotations branch per the metadata) were left out. Please add the rotation test case(s) to cases.py so these goldens are actually run.

@sbryngelson sbryngelson marked this pull request as draft June 23, 2026 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants