Skip to content

Add hemisphere shell particle cloud packing#1667

Draft
BCKim55 wants to merge 1 commit into
MFlowCode:masterfrom
BCKim55:feature/particle-cloud-hemi-shell
Draft

Add hemisphere shell particle cloud packing#1667
BCKim55 wants to merge 1 commit into
MFlowCode:masterfrom
BCKim55:feature/particle-cloud-hemi-shell

Conversation

@BCKim55

@BCKim55 BCKim55 commented Jul 22, 2026

Copy link
Copy Markdown

Description

Adds a hemisphere-shell particle cloud packing option for immersed-boundary particle clouds.

This introduces particle_cloud(i)%packing_method = 3, which randomly places spherical/circular IBM particles inside a hemisphere-shell region while enforcing:

  • inner and outer shell-radius clearance,
  • hemisphere plane clearance,
  • bounding-box clearance,
  • particle-particle non-overlap using the existing spatial hash approach.

This also adds shell_inner_radius and shell_outer_radius particle cloud parameters. The local verification example was removed from this PR to avoid introducing a new golden test in the same change.

Type of change

  • New feature

Testing

  • ./mfc.sh format
  • ./mfc.sh validate examples/*/case.py
  • ./mfc.sh validate examples/3D_mibm_particle_cloud_hemi_shell/case.py
  • ./mfc.sh run examples/3D_mibm_particle_cloud_hemi_shell/case.py --clean --no-debug

Additional local checks:

  • Verified generated ib_state_0.dat particle positions.
  • Confirmed no shell-boundary violations.
  • Confirmed no particle overlap violations.
  • Confirmed VF 0.2 succeeds with min_spacing=0.02.
  • Confirmed VF 0.3 succeeds when min_spacing=0.0.

Checklist

  • I added or updated tests for new behavior
  • I updated documentation if user-facing behavior changed
GPU changes (expand if you modified src/simulation/)
  • GPU results match CPU results
  • Tested on NVIDIA GPU or AMD GPU

@BCKim55
BCKim55 requested a review from sbryngelson as a code owner July 22, 2026 06:52
@sbryngelson
sbryngelson marked this pull request as draft July 22, 2026 13:04
@wilfonba

wilfonba commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

I don't think this is implemented quite right. The example you added highlights this fact. It defines a hemispherical particle cloud using a cubic domain. I think instead you should add a particle_cloud(i)%geometry variable, and then treat the particle cloud more like the fluid patches are treated. Also, a hemispherical shell is not a packing method in the same way that rejection sampling and lattice placement are packing methods, so using the existing acking_method variable for this isn't the right thing to do. You can place particles in a hemispherical shell using either rejection sampling, lattice placement, or some other packing method that's not implemented yet.

Edit: Your s_particle_cloud_random_hemi_shell routine appears to do rejection sampling, which adds to the confusion of what packing_method means.

@BCKim55

BCKim55 commented Jul 23, 2026

Copy link
Copy Markdown
Author

Thanks Ben, that makes sense. I agree that the hemisphere shell should be treated as a particle-cloud geometry rather than a packing method.

I’ll refactor this so that particle_cloud(i)%packing_method remains responsible for the placement algorithm, e.g. rejection sampling or lattice, and add a separate particle_cloud(i)%geometry option for the cloud shape. Then the current hemisphere-shell implementation will become the rejection-sampling path for geometry = hemisphere shell, while unsupported combinations such as hemisphere-shell lattice packing can error out explicitly for now.

I’ll also remove or adjust the example so it does not imply that a cubic domain defines the hemispherical cloud.

@BCKim55
BCKim55 force-pushed the feature/particle-cloud-hemi-shell branch from 81e9038 to 933f66c Compare July 23, 2026 23:21
Comment thread src/simulation/m_particle_cloud.fpp
Comment thread src/simulation/m_particle_cloud.fpp Outdated
do while (n_placed < particle_cloud(cloud_idx)%num_particles .and. n_attempts < max_attempts)
n_attempts = n_attempts + 1

if (p == 0) 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.

num_dims < 3 peferred in general. This likely does not affect things, but num_dims is a case-optimization parameter, and therefore the compiler can optimize this away if you make it a check on num_dims.

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.

Updated this to use num_dims < 3 instead of checking p == 0.

xdir = rho*cos(phi)
ydir = rho*sin(phi)
u = f_xorshift(seed)
r_shell = ((r_outer**3._wp - r_inner**3._wp)*u + r_inner**3._wp)**(1._wp/3._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 seems like a lot fo compute for your QOI. You do not use the [xyz]dir parameter at all after computing it. Again, either use it or do not computed.

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.

That said, you using a probability distribution function to weight your random seed is correct here. Just you are computing redundant quantities here that seem pointless.

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.

  1. Thanks for catching that! I completely missed that [xyz]dir wasn't being used later on. I've removed the redundant calculation to save compute.

  2. Thanks for confirming the PDF logic. I've cleaned up all the redundant quantities you mentioned to optimize the compute.

@BCKim55
BCKim55 force-pushed the feature/particle-cloud-hemi-shell branch from 933f66c to 4aff083 Compare July 25, 2026 15:01

@BCKim55 BCKim55 left a comment

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.

Thanks for the feedback. I updated the hemisphere-shell path to remove the redundant box-bounds logic and rely on the shell radii for the placement region. I also changed the dimensionality checks to use num_dims < 3 and removed the extra direction variables in the 3D sampling path.

Comment thread src/simulation/m_particle_cloud.fpp Outdated
do while (n_placed < particle_cloud(cloud_idx)%num_particles .and. n_attempts < max_attempts)
n_attempts = n_attempts + 1

if (p == 0) then

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.

Updated this to use num_dims < 3 instead of checking p == 0.

xdir = rho*cos(phi)
ydir = rho*sin(phi)
u = f_xorshift(seed)
r_shell = ((r_outer**3._wp - r_inner**3._wp)*u + r_inner**3._wp)**(1._wp/3._wp)

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.

  1. Thanks for catching that! I completely missed that [xyz]dir wasn't being used later on. I've removed the redundant calculation to save compute.

  2. Thanks for confirming the PDF logic. I've cleaned up all the redundant quantities you mentioned to optimize the compute.

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

Request changes

  1. Missing regression coverage. This PR adds the hemisphere-shell execution path but removes the local example and adds no test fixture. The existing particle-cloud case is box-only, so CI never executes geometry = 2. Please add a small deterministic 2D or 3D case that checks generated particle positions for shell/plane clearance and non-overlap.

  2. Documentation was not updated. docs/documentation/case.md does not document geometry, shell_inner_radius, or shell_outer_radius, and its length_[x,y,z] description is inaccurate for geometry = 2, where those extents are ignored. Please update the Particle Clouds section accordingly.

shell_outer_radius = self.get(f"particle_cloud({i})%shell_outer_radius", None)
shell_inner_radius = self.get(f"particle_cloud({i})%shell_inner_radius", None)
self.prohibit(
geometry == 2 and (shell_outer_radius is None or shell_inner_radius is None or shell_outer_radius <= shell_inner_radius),

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.

Feasibility validation is incomplete. This accepts (for example) shell_inner_radius=0, shell_outer_radius=0.1, and radius=0.1, even though no centre can satisfy the required radial clearances. The run then reaches the startup sampler and aborts at r_outer <= r_inner. Please validate shell_inner_radius >= 0 and shell_outer_radius > shell_inner_radius + 2*radius here, and add the equivalent Fortran input check so invalid cases fail before initialization.

if (num_dims == 3) bz = int(floor(rz/min_dist))

overlaps = .false.
outer: do dx_b = -1, 1

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 loop looks like you copied the code from the cuboid rejection-packing subroutine and dropped it here. If we are going to do that, seems like it may be best to create a separate routine to check for overlapping and to call it here and in the cuboid routine instead. It would probably delete 30 lines from this section of the code.

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.

4 participants