feature: integrate rotations into ICPP patches (#1594)#1612
Conversation
423d5f1 to
f0332b3
Compare
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.
f0332b3 to
c4dea86
Compare
Codecov Report❌ Patch coverage is
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. 🚀 New features to boost your workflow:
|
danieljvickers
left a comment
There was a problem hiding this comment.
These are pretty much all the same changes I would have made. Well done. Two notes before this should be merged:
- 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.
- The wrapper function in simulation around the s_compute_rotation_matrix subroutine is necessary. It adds nothing meaningful and should be removed.
There was a problem hiding this comment.
Not sure about this name, as it could get confused with IB patch code. Maybe speciify it is a fluid patch?
There was a problem hiding this comment.
Changing it to 2D_rotated_fluid_rectangle. Would that work?
| 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 |
There was a problem hiding this comment.
Is there a reason to add this additional angle value?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
| @@ -415,45 +415,10 @@ contains | |||
There was a problem hiding this comment.
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.
…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
…87/MFC into feature/icpp-patch-rotations
- 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)
There was a problem hiding this comment.
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 registered — tests/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 it2D_rotated_rectangle. - GPU scope (to be precise): the new ICPP rotation path (
m_icpp_patches.fpp) runs only inpre_process, which is CPU-only — so the feature this PR adds has no GPU concern. The only GPU-relevant change is thats_compute_rotation_matrixmoved out ofm_ib_patches(src/simulation) intom_patch_geometries(src/common); it's still called on-device fromm_ibm.fppinside$: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 sincem_patch_geometriesalready 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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
#:endforsize(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. | |||
There was a problem hiding this comment.
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.
Description
Add a rotation framework to initial-condition (ICPP) patches, mirroring the existing immersed-boundary rotation support.
Part of #1594
Type of change (delete unused ones)
Testing
behavior-neutral for all existing cases.
the shared s_compute_rotation_matrix, confirming the extracted routine
matches the original.
output shows the rectangle correctly tilted (image below).
Checklist
Check these like this
[x]to indicate which of the below applies.See the developer guide for full coding standards.
GPU changes (expand if you modified
src/simulation/)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)claude-full-review— Claude full review via label