Skip to content

Periodic Immersed Boundary Wrapping for Circular and Spherical Geometries#1117

Open
conraddelgado wants to merge 13 commits intoMFlowCode:masterfrom
conraddelgado:master
Open

Periodic Immersed Boundary Wrapping for Circular and Spherical Geometries#1117
conraddelgado wants to merge 13 commits intoMFlowCode:masterfrom
conraddelgado:master

Conversation

@conraddelgado
Copy link

@conraddelgado conraddelgado commented Jan 29, 2026

User description

User description

Description

Adds periodic wrapping for circular and spherical immersed boundaries.

Fixes #(issue) [optional]

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

Scope

  • This PR comprises a set of related changes with a common goal

If you cannot check the above box, please split your PR into multiple PRs that each have a common goal.

How Has This Been Tested?

Please describe the tests that you ran to verify your changes.
Provide instructions so we can reproduce.
Please also list any relevant details for your test configuration

Tested 2D case (circle) and 3D case (sphere): in both cases the circle/sphere is placed in the corner of the domain and the flow field is compared against a simulation where the circle/sphere is located in the center of the domain. The flow fields should be exactly the same but offset.

2D circle located at center of domain - x velocity across diagonal

2d_circle_verification_center

2D circle located at corner of domain - x velocity across diagonal

2d_circle_verification_corner

2D circle located at center of domain - x velocity video

2d_circle_verification_center.mp4

2D circle located at corner of domain - x velocity video

2d_circle_verification_corner.mp4

3D sphere located at center of domain - x velocity across diagonal

3d_sphere_verification_center

3D sphere located at corner of domain - x velocity across diagonal

3d_sphere_verification_corner

3D sphere located at center of domain - x velocity video

3d_sphere_verification_center.mp4

3D sphere located at corner of domain - x velocity video

3d_sphere_verification_corner.mp4

Added the following examples

  • examples/2D_ibm_circle_periodic
  • examples/3D_ibm_sphere_periodic

Test Configuration:

  • What computers and compilers did you use to test this:
    Ubuntu, MacOs

Checklist

  • I have added comments for the new code
  • I added Doxygen docstrings to the new code
  • I have made corresponding changes to the documentation (docs/)
  • I have added regression tests to the test suite so that people can verify in the future that the feature is behaving as expected
  • I have added example cases in examples/ that demonstrate my new feature performing as expected.
    They run to completion and demonstrate "interesting physics"
  • I ran ./mfc.sh format before committing my code
  • New and existing tests pass locally with my changes, including with GPU capability enabled (both NVIDIA hardware with NVHPC compilers and AMD hardware with CRAY compilers) and disabled
  • This PR does not introduce any repeated code (it follows the DRY principle)
  • I cannot think of a way to condense this code and reduce any introduced additional line count

If your code changes any code source files (anything in src/simulation)

To make sure the code is performing as expected on GPU devices, I have:

  • Checked that the code compiles using NVHPC compilers
  • Checked that the code compiles using CRAY compilers
  • Ran the code on either V100, A100, or H100 GPUs and ensured the new feature performed as expected (the GPU results match the CPU results)
  • Ran the code on MI200+ GPUs and ensure the new features performed as expected (the GPU results match the CPU results)
  • Enclosed the new feature via nvtx ranges so that they can be identified in profiles
  • Ran a Nsight Systems profile using ./mfc.sh run XXXX --gpu -t simulation --nsys, and have attached the output file (.nsys-rep) and plain text results to this PR
  • Ran a Rocprof Systems profile using ./mfc.sh run XXXX --gpu -t simulation --rsys --hip-trace, and have attached the output file and plain text results to this PR.
  • Ran my code using various numbers of different GPUs (1, 2, and 8, for example) in parallel and made sure that the results scale similarly to what happens if you run without the new code/feature

PR Type

Enhancement

Description

  • Implements periodic wrapping for circular and spherical immersed boundaries

  • Adds global domain bounds tracking and periodic boundary synchronization

  • Extends levelset computation to handle periodically wrapped geometries

  • Includes 2D circle and 3D sphere example cases with validation tests

Diagram Walkthrough

flowchart LR
  A["IB Patch Definition"] -->|periodic_ibs flag| B["Calculate Periodic Centers"]
  B -->|2D/3D| C["Mark IB Cells"]
  C -->|Multiple center positions| D["Levelset Computation"]
  D -->|Minimum distance| E["Wrapped IB Field"]
  F["IB Centroid Update"] -->|Final stage| G["Wrap Around Domain"]
  G -->|Modulo operation| H["Periodic Position"]
Loading

File Walkthrough

Relevant files
Enhancement
8 files
m_ib_patches.fpp
Periodic wrapping logic for circle and sphere patches       
+120/-41
m_compute_levelset.fpp
Levelset computation with periodic distance calculations 
+98/-20 
m_ibm.fpp
Buffer population for periodic immersed boundaries             
+78/-0   
m_time_steppers.fpp
IB centroid wrapping after final RK stage                               
+12/-2   
m_mpi_common.fpp
Global domain bounds computation and storage                         
+35/-0   
m_start_up.fpp
Initialize global domain bounds during startup                     
+4/-1     
m_start_up.fpp
Initialize global domain bounds in preprocessing                 
+3/-1     
case_validator.py
Validation rules for periodic immersed boundaries               
+12/-0   
Configuration changes
8 files
m_global_parameters.fpp
Add periodic_ibs flag to global parameters                             
+3/-1     
m_mpi_proxy.fpp
Broadcast periodic_ibs parameter across MPI ranks               
+2/-1     
m_mpi_proxy.fpp
Broadcast periodic_ibs in preprocessing stage                       
+1/-1     
m_global_parameters.fpp
Add periodic_ibs flag to preprocessing parameters               
+2/-0     
m_mpi_proxy.fpp
Broadcast periodic_ibs in postprocessing stage                     
+1/-1     
m_start_up.fpp
Include periodic_ibs in postprocessing startup                     
+1/-1     
m_global_parameters.fpp
Add periodic_ibs flag to postprocessing parameters             
+2/-0     
case_dicts.py
Add periodic_ibs parameter to case dictionary                       
+1/-0     
Tests
4 files
case.py
2D periodic circle immersed boundary test case                     
+141/-0 
case.py
3D periodic sphere immersed boundary test case                     
+150/-0 
golden-metadata.txt
Test metadata for 2D periodic circle case                               
+193/-0 
golden-metadata.txt
Test metadata for 3D periodic sphere case                               
+193/-0 
Additional files
2 files
golden.txt +11/-0   
golden.txt +13/-0   

Summary by CodeRabbit

  • New Features

    • Periodic immersed boundaries: immersed objects now wrap across periodic domains; centroids and patches auto-wrap at timestep boundaries.
    • New example case generators for 2D circular and 3D spherical periodic IB simulations.
  • Tests

    • Added golden test data and metadata for periodic IB scenarios and updated validation to enforce compatible boundary/geometry settings.

CodeAnt-AI Description

Periodic wrapping for circular and spherical immersed boundaries

What Changed

  • When enabled via the new periodic_ibs option, circle (2D) and sphere (3D) immersed boundaries are treated as periodic: their centroid is projected to neighboring periodic images and the levelset/marker assignment uses the nearest periodic image so objects overlapping a domain boundary appear on the opposite side.
  • After a timestep, moving immersed-boundary centroids are wrapped back into the global domain bounds so positions remain inside the domain when periodic_ibs is set.
  • Ghost/buffer IB marker cells are populated from the opposite periodic faces so IB markers are continuous across periodic boundaries.
  • Input validation rejects incompatible setups: periodic_ibs requires IB enabled, non-cylindrical coordinates, periodic boundary conditions in all directions, and only circle/sphere geometries when periodic_ibs is true. Example cases and tests for 2D/3D periodic IBs were added.

Impact

✅ Immersed boundaries wrap across periodic domain boundaries
✅ Identical flow for an object at corner vs center when using periodic IBs
✅ Clearer errors when periodic IBs are misconfigured

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

📝 Walkthrough

Walkthrough

Adds support for periodic immersed boundaries: new periodic_ibs flag, domain bounds storage, periodic wrapping of IB centers/centroids, levelset and patch detection extended to test periodic images, MPI/user-input plumbing, validation checks, and IB buffer/time-step updates to handle periodic boundaries.

Changes

Cohort / File(s) Summary
Example Configurations
examples/2D_ibm_circle_periodic/case.py, examples/3D_ibm_sphere_periodic/case.py
New example scripts generating JSON case dictionaries for 2D circle and 3D sphere periodic IB test cases.
Levelset Computation
src/common/m_compute_levelset.fpp
Adds s_periodic_project_center; center arrays expanded to hold wrapped images; distance/normal computations now search minimum over periodic image centers when periodic_ibs is enabled.
Patch Detection
src/common/m_ib_patches.fpp
Patch center representation changed to per-dimension matrices; radius-squared cache added; periodic wrapping tests all image combinations (2×2 in 2D, 2×2×2 in 3D) in GPU loops.
Global Parameters
src/pre_process/m_global_parameters.fpp, src/post_process/m_global_parameters.fpp, src/simulation/m_global_parameters.fpp
Introduces public logical periodic_ibs (default .false.) and allocatable domain_glb to store domain bounds; alloc/dealloc and GPU declarations updated.
MPI Synchronization
src/pre_process/m_mpi_proxy.fpp, src/post_process/m_mpi_proxy.fpp, src/simulation/m_mpi_proxy.fpp
Adds periodic_ibs to MPI broadcast lists so the flag is synchronized across ranks.
Input/Start-up
src/pre_process/m_start_up.fpp, src/post_process/m_start_up.fpp, src/simulation/m_start_up.fpp
Adds periodic_ibs to the user_inputs namelist in pre/post/simulation start-up modules.
IB Buffer Population
src/simulation/m_ibm.fpp
New periodic branch in s_populate_ib_buffers to populate IB marker buffers for periodic BC edges (beg/end) in x/y/z when periodic_ibs is true.
Time Stepping
src/simulation/m_time_steppers.fpp
s_propagate_immersed_boundaries signature updated to accept nstage; final-stage centroid wrapping using domain_glb/modulo applied when periodic_ibs is enabled.
Validation & Tooling
toolchain/mfc/case_validator.py, toolchain/mfc/run/case_dicts.py
case_validator.check_ibm enforces constraints for periodic_ibs (IB enabled, no cylindrical coords, BCs set to periodic, only circle/sphere geometries); periodic_ibs added to case schema as a logical parameter.
Tests / Golden Data
tests/60AD8A56/*, tests/FF27BC5E/golden-metadata.txt
Adds/updates golden metadata and data files for tests (static artifacts).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User as "User / Input"
participant MPI as "MPI (broadcast)"
participant StartUp as "Start-up Modules"
participant Global as "m_global_parameters"
participant Compute as "Levelset / IB Patches (GPU)"
participant Time as "Time-steppers / IB propagation"
User->>StartUp: read user_inputs (incl. periodic_ibs)
StartUp->>MPI: broadcast inputs (periodic_ibs)
MPI->>Global: set periodic_ibs, populate domain_glb
Global->>Compute: provide domain_glb & periodic flag
Compute->>Compute: project centers to periodic images; compute levelset/patch masks (min over images)
Time->>Compute: propagate IBs per stage
Time->>Global: on final stage if periodic_ibs -> wrap centroids using domain_glb

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • sbryngelson

Poem

🐰 I hopped through bounds and wrapped each little sphere,
Centers cloned like carrots, tucked each neighbor near,
Distances seek shortcuts through the periodic dew,
Centroids spin home when a timestep says adieu,
Now fields loop like ribbons — hooray, the domain is clear! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature: periodic wrapping functionality for circular and spherical immersed boundaries.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description check ✅ Passed Pull request provides clear motivation, includes testing details with visual verification, and addresses most checklist items substantively.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@codecov
Copy link

codecov bot commented Jan 30, 2026

Codecov Report

❌ Patch coverage is 55.63380% with 63 lines in your changes missing coverage. Please review.
✅ Project coverage is 44.15%. Comparing base (a6d3f37) to head (d371d40).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/common/m_compute_levelset.fpp 56.25% 14 Missing and 7 partials ⚠️
src/simulation/m_ibm.fpp 48.64% 12 Missing and 7 partials ⚠️
src/common/m_ib_patches.fpp 55.00% 17 Missing and 1 partial ⚠️
src/simulation/m_time_steppers.fpp 28.57% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1117      +/-   ##
==========================================
+ Coverage   44.03%   44.15%   +0.12%     
==========================================
  Files          70       70              
  Lines       20649    20757     +108     
  Branches     2053     2074      +21     
==========================================
+ Hits         9093     9166      +73     
- Misses      10368    10388      +20     
- Partials     1188     1203      +15     

☔ View full report in Codecov by Sentry.
📢 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.

@conraddelgado conraddelgado marked this pull request as ready for review January 30, 2026 18:27
@qodo-code-review
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

The periodic-wrapping branch for circle/sphere overwrites ib_markers_sf from multiple wrapped images and does not resolve conflicts when multiple immersed boundaries overlap or when multiple wrapped copies hit the same cell; validate marker priority/ordering is still correct and deterministic on GPU. Also verify the periodic logic matches the intended geometry (comments mention spheres inside the circle routine) and that unused iterators do not mask mistakes.

if (periodic_ibs) then ! periodically wrap spheres around domain
    if ((center(1, 1) - domain_glb(1, 1)) <= radius) then
        center(1, 2) = domain_glb(1, 2) + (center(1, 1) - domain_glb(1, 1))
    else if ((domain_glb(1, 2) - center(1, 1)) <= radius) then
        center(1, 2) = domain_glb(1, 1) - (domain_glb(1, 2) - center(1, 1))
    else
        center(1, 2) = center(1, 1)
    end if
    if ((center(2, 1) - domain_glb(2, 1)) <= radius) then
        center(2, 2) = domain_glb(2, 2) + (center(2, 1) - domain_glb(2, 1))
    else if ((domain_glb(2, 2) - center(2, 1)) <= radius) then
        center(2, 2) = domain_glb(2, 1) - (domain_glb(2, 2) - center(2, 1))
    else
        center(2, 2) = center(2, 1)
    end if

    $:GPU_PARALLEL_LOOP(private='[i,j,ix,iy]', copy='[ib_markers_sf]',&
              & copyin='[patch_id,center,r2]', collapse=2)
    do j = 0, n
        do i = 0, m
            do ix = 1, 2
                do iy = 1, 2
                    if ((x_cc(i) - center(1, ix))**2 &
                        + (y_cc(j) - center(2, iy))**2 <= r2) then
                        ib_markers_sf(i, j, 0) = patch_id
                    end if
                end do
            end do
        end do
    end do
    $:END_GPU_PARALLEL_LOOP()
else
    $:GPU_PARALLEL_LOOP(private='[i,j]', copy='[ib_markers_sf]',&
              & copyin='[patch_id,center,r2]', collapse=2)
    do j = 0, n
        do i = 0, m
            if ((x_cc(i) - center(1, 1))**2 &
                + (y_cc(j) - center(2, 1))**2 <= r2) &
                then
                ib_markers_sf(i, j, 0) = patch_id
            end if
        end do
    end do
    $:END_GPU_PARALLEL_LOOP()
end if
Duplication

The domain-wrapping logic (building center(:,2) and checking all 2^D permutations to find minimum distance) is duplicated across circle/sphere marker placement and levelset computation. This increases the chance of future divergence/bugs (e.g., cylindrical coordinates handled in s_ib_sphere but not in the periodic branch). Consider extracting a shared helper to compute wrapped centroids / minimum-image distance consistently for 2D/3D and for both marker and levelset paths.

real(wp) :: radius, dist
real(wp), dimension(2, 2) :: center
real(wp), dimension(3) :: dist_vec
!< temporary distance and distance vector used for periodicity
real(wp) :: dist_temp
real(wp), dimension(3) :: dist_vec_temp

integer :: i, j, ix, iy !< Loop index variables

radius = patch_ib(ib_patch_id)%radius
center(1, 1) = patch_ib(ib_patch_id)%x_centroid
center(2, 1) = patch_ib(ib_patch_id)%y_centroid

if (periodic_ibs) then ! periodically wrap spheres around domain
    if ((center(1, 1) - domain_glb(1, 1)) <= radius) then
        center(1, 2) = domain_glb(1, 2) + (center(1, 1) - domain_glb(1, 1))
    else if ((domain_glb(1, 2) - center(1, 1)) <= radius) then
        center(1, 2) = domain_glb(1, 1) - (domain_glb(1, 2) - center(1, 1))
    else
        center(1, 2) = center(1, 1)
    end if
    if ((center(2, 1) - domain_glb(2, 1)) <= radius) then
        center(2, 2) = domain_glb(2, 2) + (center(2, 1) - domain_glb(2, 1))
    else if ((domain_glb(2, 2) - center(2, 1)) <= radius) then
        center(2, 2) = domain_glb(2, 1) - (domain_glb(2, 2) - center(2, 1))
    else
        center(2, 2) = center(2, 1)
    end if
end if

$:GPU_PARALLEL_LOOP(private='[i,j,ix,iy,dist_vec,dist,dist_vec_temp,dist_temp]', &
                  & copyin='[ib_patch_id,center,radius,periodic_ibs]', collapse=2)
do i = 0, m
    do j = 0, n
        dist_vec(1) = x_cc(i) - center(1, 1)
        dist_vec(2) = y_cc(j) - center(2, 1)
        dist_vec(3) = 0._wp
        dist = sqrt(sum(dist_vec**2))
        if (periodic_ibs) then
            ! check all permutations of periodically projected ib to find minimum distance
            do ix = 1, 2
                do iy = 1, 2
                    dist_vec_temp(1) = x_cc(i) - center(1, ix)
                    dist_vec_temp(2) = y_cc(j) - center(2, iy)
                    dist_vec_temp(3) = 0._wp
                    dist_temp = sqrt(sum(dist_vec_temp**2))
                    if (dist_temp < dist) then
                        dist = dist_temp
                        dist_vec = dist_vec_temp
                    end if
                end do
            end do
        end if
        levelset%sf(i, j, 0, ib_patch_id) = dist - radius
        if (f_approx_equal(dist, 0._wp)) then
            levelset_norm%sf(i, j, 0, ib_patch_id, :) = 0
        else
            levelset_norm%sf(i, j, 0, ib_patch_id, :) = &
                dist_vec(:)/dist
        end if
    end do
end do
$:END_GPU_PARALLEL_LOOP()
Possible Issue

Buffer population for ib_markers under periodic_ibs should be validated for correctness at edges/corners (especially the order of filling x/y/z halos and whether corner halos end up consistent). Since this runs on GPU and writes ghost layers, confirm no race conditions and that the chosen loop bounds cover all required halo regions without writing outside allocated extents for all dimensionalities (2D vs 3D).

if (periodic_ibs) then
    ! Population of Buffers in x-direction
    if (bc_x%beg == BC_PERIODIC) then
        $:GPU_PARALLEL_LOOP(collapse=3)
        do l = 0, p
            do k = 0, n
                do j = 1, buff_size
                    ib_markers%sf(-j, k, l) = &
                        ib_markers%sf(m - (j - 1), k, l)
                end do
            end do
        end do
    end if

    if (bc_x%end == BC_PERIODIC) then
        $:GPU_PARALLEL_LOOP(collapse=3)
        do l = 0, p
            do k = 0, n
                do j = 1, buff_size
                    ib_markers%sf(m + j, k, l) = &
                        ib_markers%sf(j - 1, k, l)
                end do
            end do
        end do
    end if

    ! Population of Buffers in y-direction
    if (bc_y%beg == BC_PERIODIC) then
        $:GPU_PARALLEL_LOOP(collapse=3)
        do l = 0, p
            do k = -buff_size, m + buff_size
                do j = 1, buff_size
                    ib_markers%sf(k, -j, l) = &
                        ib_markers%sf(k, n - (j - 1), l)
                end do
            end do
        end do
    end if

    if (bc_y%end == BC_PERIODIC) then
        $:GPU_PARALLEL_LOOP(collapse=3)
        do l = 0, p
            do k = -buff_size, m + buff_size
                do j = 1, buff_size
                    ib_markers%sf(k, n + j, l) = &
                        ib_markers%sf(k, j - 1, l)
                end do
            end do
        end do
    end if

    ! Population of Buffers in z-direction
    if (bc_z%beg == BC_PERIODIC) then
        $:GPU_PARALLEL_LOOP(collapse=3)
        do l = -buff_size, n + buff_size
            do k = -buff_size, m + buff_size
                do j = 1, buff_size
                    ib_markers%sf(k, l, -j) = &
                        ib_markers%sf(k, l, p - (j - 1))
                end do
            end do
        end do
    end if

    if (bc_z%end == BC_PERIODIC) then
        $:GPU_PARALLEL_LOOP(collapse=3)
        do l = -buff_size, n + buff_size
            do k = -buff_size, m + buff_size
                do j = 1, buff_size
                    ib_markers%sf(k, l, p + j) = &
                        ib_markers%sf(k, l, j - 1)
                end do
            end do
        end do
    end if
end if

Comment on lines +825 to +832
! wrap ib centroid around domain after final stage in timestep
if (periodic_ibs .and. s == nstage) then
patch_ib(i)%x_centroid = domain_glb(1, 1) + modulo(patch_ib(i)%x_centroid - domain_glb(1, 1), domain_glb(1, 2) - domain_glb(1, 1))
patch_ib(i)%y_centroid = domain_glb(2, 1) + modulo(patch_ib(i)%y_centroid - domain_glb(2, 1), domain_glb(2, 2) - domain_glb(2, 1))
if (p > 0) then ! 3D
patch_ib(i)%z_centroid = domain_glb(3, 1) + modulo(patch_ib(i)%z_centroid - domain_glb(3, 1), domain_glb(3, 2) - domain_glb(3, 1))
end if
end if
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: Modify the immersed boundary wrapping logic to execute at every Runge-Kutta sub-stage, not just the final one, by removing the s == nstage condition. [possible issue, importance: 7]

Suggested change
! wrap ib centroid around domain after final stage in timestep
if (periodic_ibs .and. s == nstage) then
patch_ib(i)%x_centroid = domain_glb(1, 1) + modulo(patch_ib(i)%x_centroid - domain_glb(1, 1), domain_glb(1, 2) - domain_glb(1, 1))
patch_ib(i)%y_centroid = domain_glb(2, 1) + modulo(patch_ib(i)%y_centroid - domain_glb(2, 1), domain_glb(2, 2) - domain_glb(2, 1))
if (p > 0) then ! 3D
patch_ib(i)%z_centroid = domain_glb(3, 1) + modulo(patch_ib(i)%z_centroid - domain_glb(3, 1), domain_glb(3, 2) - domain_glb(3, 1))
end if
end if
! wrap ib centroid around domain
if (periodic_ibs) then
patch_ib(i)%x_centroid = domain_glb(1, 1) + modulo(patch_ib(i)%x_centroid - domain_glb(1, 1), domain_glb(1, 2) - domain_glb(1, 1))
patch_ib(i)%y_centroid = domain_glb(2, 1) + modulo(patch_ib(i)%y_centroid - domain_glb(2, 1), domain_glb(2, 2) - domain_glb(2, 1))
if (p > 0) then ! 3D
patch_ib(i)%z_centroid = domain_glb(3, 1) + modulo(patch_ib(i)%z_centroid - domain_glb(3, 1), domain_glb(3, 2) - domain_glb(3, 1))
end if
end if

Copy link
Author

Choose a reason for hiding this comment

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

We can change this to wrap the centroids around the domain at every RK substep instead of only at the end of a timestep. It will just require also updating step_[x,y,z]_centroid as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

Code Implementation 🛠️

Implementation: Apply periodic immersed-boundary centroid wrapping at every Runge–Kutta sub-stage (not only the final stage) and keep the RK reference centroid values (step_x/y/z_centroid) consistent by wrapping them as well.

Suggested change
! wrap ib centroid around domain after final stage in timestep
if (periodic_ibs .and. s == nstage) then
patch_ib(i)%x_centroid = domain_glb(1, 1) + modulo(patch_ib(i)%x_centroid - domain_glb(1, 1), domain_glb(1, 2) - domain_glb(1, 1))
patch_ib(i)%y_centroid = domain_glb(2, 1) + modulo(patch_ib(i)%y_centroid - domain_glb(2, 1), domain_glb(2, 2) - domain_glb(2, 1))
if (p > 0) then ! 3D
patch_ib(i)%z_centroid = domain_glb(3, 1) + modulo(patch_ib(i)%z_centroid - domain_glb(3, 1), domain_glb(3, 2) - domain_glb(3, 1))
end if
end if
! wrap ib centroid around domain at every RK sub-stage
if (periodic_ibs) then
patch_ib(i)%x_centroid = domain_glb(1, 1) + modulo(patch_ib(i)%x_centroid - domain_glb(1, 1), domain_glb(1, 2) - domain_glb(1, 1))
patch_ib(i)%y_centroid = domain_glb(2, 1) + modulo(patch_ib(i)%y_centroid - domain_glb(2, 1), domain_glb(2, 2) - domain_glb(2, 1))
! Keep RK reference centroid consistent with wrapped coordinates
patch_ib(i)%step_x_centroid = domain_glb(1, 1) + modulo(patch_ib(i)%step_x_centroid - domain_glb(1, 1), domain_glb(1, 2) - domain_glb(1, 1))
patch_ib(i)%step_y_centroid = domain_glb(2, 1) + modulo(patch_ib(i)%step_y_centroid - domain_glb(2, 1), domain_glb(2, 2) - domain_glb(2, 1))
if (p > 0) then ! 3D
patch_ib(i)%z_centroid = domain_glb(3, 1) + modulo(patch_ib(i)%z_centroid - domain_glb(3, 1), domain_glb(3, 2) - domain_glb(3, 1))
patch_ib(i)%step_z_centroid = domain_glb(3, 1) + modulo(patch_ib(i)%step_z_centroid - domain_glb(3, 1), domain_glb(3, 2) - domain_glb(3, 1))
end if
end if

See review comment here

Copy link
Author

Choose a reason for hiding this comment

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

As its written, this will not change the value of step_[x,y,z]_centroid as long as they are within the computational domain. To update [x,y,z]centroid at every step we need to wrap step[x,y,z]_centroid such that it ends up outside the computational domain on the other side if [x,y,z]_centroid has been wrapped, which is why I originally only wrapped the centroids at the end of every timestep. It really should not matter as the ib_markers and levelset routines should still return the same values regardless.

Copy link
Contributor

Choose a reason for hiding this comment

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

Question:

As its written, this will not change the value of step_[x,y,z]_centroid as long as they are within the computational domain. To update [x,y,z]centroid at every step we need to wrap step[x,y,z]_centroid such that it ends up outside the computational domain on the other side if [x,y,z]_centroid has been wrapped, which is why I originally only wrapped the centroids at the end of every timestep. It really should not matter as the ib_markers and levelset routines should still return the same values regardless.

Answer:

Add a repo-level instruction to prevent speculative changes to numerical-integration/sub-stepping invariants unless the model can prove semantic equivalence, and to explicitly reason about coupled “state vs reference” variables (like centroid vs step_centroid) before proposing wrapping changes.

Recommended .pr_agent.toml snippet:

[pr_code_suggestions]
extra_instructions = """\
- Be conservative with numerical time-integration logic (e.g., Runge–Kutta sub-stages). Do NOT suggest moving logic between sub-stages vs end-of-timestep unless you can clearly justify equivalence and identify all state variables that must be updated consistently.
- For periodic-wrapping changes: if a variable has both a "current" value and an RK reference/anchor (e.g., `x_centroid` and `step_x_centroid`), explicitly explain whether the reference must remain unwrapped (physical displacement continuity) or be wrapped, and why.
- If the correct behavior depends on solver conventions (e.g., whether `step_*` is an unwrapped reference used for displacement), ask a clarifying question instead of proposing a patch.
- Prefer “discussion-only” suggestions (explain the risk/tradeoff) over concrete code diffs when the change affects algorithmic invariants.
"""

If you want to further reduce algorithmic “refactor” suggestions and keep only clear problems/bugs:

[pr_code_suggestions]
focus_only_on_problems = true

Relevant Sources:

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 22 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/common/m_ib_patches.fpp">

<violation number="1" location="src/common/m_ib_patches.fpp:657">
P2: In the periodic_ibs branch of s_ib_sphere, cylindrical grids (grid_geometry == 3) are no longer converted to cartesian coordinates before distance checks. This will misplace periodic spheres in cylindrical/axisymmetric geometries; mirror the cart_y/cart_z conversion used in the non-periodic branch.</violation>
</file>

<file name="toolchain/mfc/case_validator.py">

<violation number="1" location="toolchain/mfc/case_validator.py:360">
P2: Add a validation that periodic_ibs requires ib to be enabled; otherwise invalid configurations (periodic_ibs='T' with ib='F') will pass validation.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@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: 8

Caution

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

⚠️ Outside diff range comments (2)
toolchain/mfc/case_validator.py (1)

347-370: ⚠️ Potential issue | 🟠 Major

Dimension-specific geometry check is too permissive for periodic_ibs.
The current rule accepts geometry 2 or 8 for any dimension. That allows spheres in 2D and circles in 3D to pass validation, which contradicts the intended constraints and can slip invalid configs through. Also, consider rejecting periodic_ibs when ib is false to avoid silent no-op configurations.

🔧 Proposed fix
     def check_ibm(self):
         """Checks constraints on Immersed Boundaries parameters"""
         ib = self.get('ib', 'F') == 'T'
         n = self.get('n', 0)
+        p = self.get('p', 0)
         num_ibs = self.get('num_ibs', 0)
         periodic_ibs = self.get('periodic_ibs', 'F') == 'T'
@@
         self.prohibit(not ib and num_ibs > 0,
                      "num_ibs is set, but ib is not enabled")
         if periodic_ibs:
+            self.prohibit(not ib,
+                         "periodic_ibs requires ib = T")
             for direction in ['x', 'y', 'z']:
                 for end in ['beg', 'end']:
                     bc_val = self.get(f'bc_{direction}%{end}')
                     if bc_val is not None:
                         self.prohibit(bc_val != -1,
                                       "periodic_ibs requires periodicity in all directions (all BCs should be -1)")
             for i in range(1, num_ibs+1):
                 ib_geometry = self.get(f'patch_ib({i})%geometry')
-                self.prohibit(ib_geometry not in [2, 8],
-                              "periodic_ibs requires all immersed boundaries to be circles (2D) or spheres (3D)")
+                if p == 0:
+                    self.prohibit(ib_geometry != 2,
+                                  "periodic_ibs requires circles (geometry = 2) in 2D")
+                else:
+                    self.prohibit(ib_geometry != 8,
+                                  "periodic_ibs requires spheres (geometry = 8) in 3D")
src/simulation/m_start_up.fpp (1)

149-191: ⚠️ Potential issue | 🔴 Critical

Add GPU_UPDATE(device='[periodic_ibs]') after namelist input is read in m_start_up.fpp.
The variable periodic_ibs is read from the user_inputs namelist (lines 189-191) and used in GPU kernels within m_compute_levelset.fpp (copyin at lines 68 and 585), but it is never synchronized to the GPU device. Without this update, GPU levelset calculations will always see periodic_ibs = .false. regardless of user input, causing incorrect IB wrapping behavior.

🤖 Fix all issues with AI agents
In `@examples/2D_ibm_circle_periodic/case.py`:
- Around line 38-40: The inline comment above the grid size (near Nx and Ny
variables) incorrectly refers to a "sphere"; update that comment to say "circle"
since this is a 2D case (e.g., change the comment string "# to fully resolve
requires 40-60 cells across sphere diameter" to use "circle" instead). Ensure
the wording remains accurate and brief and that it sits immediately above or
next to the Nx/Ny declarations (symbols: Nx, Ny).

In `@examples/3D_ibm_sphere_periodic/case.py`:
- Around line 38-41: The comment about required resolution is inconsistent with
the grid settings: with L = 1 and Nx = 127 (Ny = Nz = Nx), the sphere diameter
covers roughly 13 cells, not 40–60; update the comment above the Nx/Ny/Nz
definitions (referencing Nx, Ny, Nz and L) to either state the actual
cells-per-diameter for this grid (~13) or note that 40–60 cells would require
increasing Nx accordingly, so the comment accurately reflects the chosen
resolution.

In `@src/common/m_ib_patches.fpp`:
- Around line 649-666: The periodic GPU path in the GPU_PARALLEL_LOOP uses x_cc,
y_cc, z_cc directly when computing distances and therefore skips
cylindrical-to-Cartesian conversion; update the periodic branch to perform the
same s_convert_cylindrical_to_cartesian_coord(center, center_cart) conversion
used in the non-periodic path (or compute center_cart before entering the loop)
and then use center_cart(1,ix)/center_cart(2,iy)/center_cart(3,iz) in the
distance test that assigns ib_markers_sf(i,j,k)=patch_id (preserving r2 and
patch_id usage), ensuring the cylindrical grid_geometry==3 case is handled
identically inside the periodic loop.

In `@src/common/m_mpi_common.fpp`:
- Around line 1895-1924: The subroutine s_mpi_global_domain_bounds allocates
domain_glb but never frees it; add a guarded deallocation in
s_finalize_mpi_common_module to avoid leaks/double-init cycles by checking that
domain_glb is allocated (e.g., using the ALLOCATED intrinsic) and then
CALL/DEALLOCATE (or DEALLOCATE) it safely, and ensure the finalize routine
references the same symbol name domain_glb and follows existing module
finalization ordering/guards so multiple finalize calls are safe.

In `@src/simulation/m_ibm.fpp`:
- Around line 156-231: The GPU kernels that populate periodic buffers (the
$:GPU_PARALLEL_LOOP blocks used around loops filling ib_markers%sf for x/y/z
directions when bc_x%beg/end, bc_y%beg/end, bc_z%beg/end are BC_PERIODIC) are
missing private lists for loop indices, so loop variables (e.g., j, k, l) can be
shared across threads; update each $:GPU_PARALLEL_LOOP invocation to include
private='[j,k,l]' (or the exact loop indices used in that block) so all
loop-local indices are declared private for the GPU kernels.
- Around line 207-231: The z-direction periodic buffer-fill writes
negative/positive z indices even when p == 0 (2D runs), causing out-of-bounds
access; guard the entire z-periodic block by checking p > 0 (or num_dims == 3)
before evaluating bc_z%beg/end so the loops that reference
ib_markers%sf(k,l,...) only run for 3D cases. Wrap the two if blocks that test
bc_z%beg==BC_PERIODIC and bc_z%end==BC_PERIODIC with a surrounding condition
(e.g., if (p > 0) then) so the code using ib_markers%sf and p, buff_size, k, l,
j is skipped for 2D runs.

In `@src/simulation/m_time_steppers.fpp`:
- Around line 825-831: The wrap for immersed boundary centroids uses
domain_glb(2,*) unconditionally, which will out-of-bounds in 1D; modify the
periodic_ib wrapping block (the if (periodic_ibs .and. s == nstage) branch that
updates patch_ib(i)%x_centroid, %y_centroid, and %z_centroid) to only perform
the y wrapping when num_dims > 1 (e.g., if (n > 0) then) and keep the existing
3D z guard (if (p > 0) then) so domain_glb indexing is safe for 1D, 2D and 3D
cases.

In `@tests/FF27BC5E/golden-metadata.txt`:
- Around line 1-193: The golden metadata includes a volatile "Git: ... (dirty)"
entry which causes flaky comparisons; update the metadata generator to normalize
the Git field (the "Git:" line) by either omitting the "(dirty)" marker or
writing only the commit hash (without workspace cleanliness), or regenerate the
golden from a clean working tree; change the code that emits the Git line so it
strips the "(dirty)" suffix or uses git rev-parse --short HEAD to always produce
a stable value.
🧹 Nitpick comments (1)
tests/60AD8A56/golden-metadata.txt (1)

5-33: Consider normalizing machine-specific metadata.

Fields like absolute paths, hostnames, and “git dirty” can make golden files noisy across machines; consider redacting or normalizing these in the generator to reduce churn.

@sbryngelson
Copy link
Member

@danieljvickers can you help review plz

@sbryngelson
Copy link
Member

sbryngelson commented Feb 2, 2026

@conraddelgado you should go through the ai suggestions and comment on them or fix them or dismiss them 😃 . i know it's a little annoying but it helps us catch bugs or just not great code

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 2, 2026

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Feb 2, 2026
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 2, 2026

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Module-global race
    The code calls s_convert_cylindrical_to_cartesian_coord() from inside GPU-parallel loops to obtain cartesian coordinates, but that routine assigns module-level variables (cart_y, cart_z). In a parallel/GPU region this leads to concurrent writes to shared module storage and data races. Convert the routine to return values via arguments or compute cart_y/cart_z locally inside the loop to avoid race conditions.

  • Potential incomplete domain coverage
    For periodic wrapping you read from and write into indices spanning negative and >m/n/p ranges. If buff_size can be larger than interior extents (or if stretched grids are used), some source or destination indices could overlap or be outside the intended populated region. Verify that the source indices (e.g. m - (j - 1), j - 1, n - (j - 1), p - (j - 1)) are always valid and that the order of writes does not overwrite data that is later used as a read source in the same kernel.

  • Domain size guard
    The new periodic wrapping uses modulo(..., domain_glb(d,2)-domain_glb(d,1)). If any domain extent is zero or extremely small this will be invalid (divide-by-zero / nonsense result). Add an explicit guard so wrapping is skipped or handled if the domain width <= 0.

  • Re-allocation safety
    s_mpi_global_domain_bounds unconditionally allocates domain_glb via the macro
    @:ALLOCATE(domain_glb(num_dims, 2)). If this subroutine is called more than once,
    repeated allocation without checking allocated(domain_glb) or matching dimensions may
    cause runtime errors or leaks. Add guards to avoid double allocation or perform safe
    reallocation when sizes change.

  • Caller compatibility
    The subroutine signature s_propagate_immersed_boundaries was changed to accept a second argument nstage. Ensure every call site across the codebase was updated. If any callers still call the old one-argument interface this will break (or require a compatibility shim). Consider making the new argument optional to avoid missing-call-site issues.

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 2, 2026

CodeAnt AI finished reviewing your PR.

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 2, 2026

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Feb 2, 2026
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 2, 2026

CodeAnt AI Incremental review completed.

Copy link
Contributor

@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: 0

Caution

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

⚠️ Outside diff range comments (2)
src/simulation/m_global_parameters.fpp (2)

1421-1429: ⚠️ Potential issue | 🟠 Major

Fix domain_glb deallocation for 1D/2D runs (early return skips cleanup).

domain_glb is deallocated after return guards; in 1D (n == 0) and 2D (p == 0), it never gets freed. Move the deallocation before the early returns or replace returns with conditional blocks.

🛠️ Proposed fix
-        @:DEALLOCATE(x_cb, x_cc, dx)
-
-        if (n == 0) return; 
-        @:DEALLOCATE(y_cb, y_cc, dy)
-
-        if (p == 0) return; 
-        @:DEALLOCATE(z_cb, z_cc, dz)
-
-        @:DEALLOCATE(domain_glb)
+        @:DEALLOCATE(x_cb, x_cc, dx)
+        @:DEALLOCATE(domain_glb)
+
+        if (n /= 0) then
+          @:DEALLOCATE(y_cb, y_cc, dy)
+          if (p /= 0) then
+            @:DEALLOCATE(z_cb, z_cc, dz)
+          end if
+        end if

399-412: ⚠️ Potential issue | 🟠 Major

Add GPU_UPDATE call to synchronize IB parameters after initialization.

The IB parameters (ib, num_ibs, patch_ib, periodic_ibs) are declared with GPU_DECLARE(create='[...]') at line 411, but they are initialized at lines 716–718 without a corresponding GPU_UPDATE call. This leaves the device with uninitialized values. Add $:GPU_UPDATE(device='[ib,num_ibs,patch_ib,periodic_ibs]') immediately after line 718 to ensure the device sees the correct runtime values.

🧹 Nitpick comments (1)
src/pre_process/m_global_parameters.fpp (1)

306-308: Use fypp allocation macros for domain_glb to align with src/**/*.fpp rules.

This file is under src/, so prefer @:ALLOCATE/@:DEALLOCATE for device-aware allocation.

♻️ Proposed changes
@@
-#:include 'case.fpp'
+#:include 'case.fpp'
+#:include 'macros.fpp'
-        allocate (domain_glb(num_dims, 2))
+        @:ALLOCATE(domain_glb(num_dims, 2))
@@
-        deallocate (domain_glb)
+        @:DEALLOCATE(domain_glb)

Also applies to: 979-989, 1046-1046

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 3, 2026

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Feb 3, 2026
Copy link
Contributor

@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: 1

Caution

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

⚠️ Outside diff range comments (2)
toolchain/mfc/case_validator.py (1)

347-375: ⚠️ Potential issue | 🟠 Major

Enforce dimension-specific periodic IB geometries (circle in 2D, sphere in 3D).
The current check allows geometry 2 or 8 regardless of dimensionality, so a 3D case could pass with a circle (or 2D with a sphere), contradicting the stated constraints and likely breaking downstream assumptions.

✅ Suggested fix
-        n = self.get('n', 0)
+        n = self.get('n', 0)
+        p = self.get('p', 0)
         num_ibs = self.get('num_ibs', 0)
         periodic_ibs = self.get('periodic_ibs', 'F') == 'T'
         cyl_coord = self.get('cyl_coord', 'F') == 'T'
@@
-            for i in range(1, num_ibs+1):
+            expected_geom = 8 if (p is not None and p > 0) else 2
+            for i in range(1, num_ibs + 1):
                 ib_geometry = self.get(f'patch_ib({i})%geometry')
-                self.prohibit(ib_geometry not in [2, 8],
-                              "periodic_ibs requires all immersed boundaries to be circles (2D) or spheres (3D)")
+                self.prohibit(ib_geometry != expected_geom,
+                              "periodic_ibs requires circles (2) in 2D and spheres (8) in 3D")
src/simulation/m_global_parameters.fpp (1)

1438-1447: ⚠️ Potential issue | 🟡 Minor

domain_glb never deallocates in 1D/2D due to early returns.
The early return statements exit before domain_glb is released, so 1D/2D runs leak the allocation.

🛠️ Suggested fix
-        @:DEALLOCATE(x_cb, x_cc, dx)
-
-        if (n == 0) return; 
-        @:DEALLOCATE(y_cb, y_cc, dy)
-
-        if (p == 0) return; 
-        @:DEALLOCATE(z_cb, z_cc, dz)
-
-        @:DEALLOCATE(domain_glb)
+        @:DEALLOCATE(x_cb, x_cc, dx)
+        if (n > 0) then
+            @:DEALLOCATE(y_cb, y_cc, dy)
+        end if
+        if (p > 0) then
+            @:DEALLOCATE(z_cb, z_cc, dz)
+        end if
+        @:DEALLOCATE(domain_glb)
🤖 Fix all issues with AI agents
In `@src/simulation/m_global_parameters.fpp`:
- Around line 558-561: CI reports a formatting mismatch around the domain_glb
declaration; to fix it, re-run the project's code formatter on the file
containing the declaration of domain_glb (the allocatable real(wp), dimension(:,
:) :: domain_glb and its GPU_DECLARE directive) so the spacing/indentation and
continuation markers are normalized, then commit the formatted file to clear the
Pretty pipeline failure.

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 3, 2026

CodeAnt AI Incremental review completed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review effort 4/5 size:XXL This PR changes 1000+ lines, ignoring generated files

Development

Successfully merging this pull request may close these issues.

2 participants