Skip to content

Particle cloud ib el integration - #2113

Draft
danieljvickers wants to merge 17 commits into
MFlowCode:masterfrom
danieljvickers:particle-cloud-ib-el-integration
Draft

danieljvickers wants to merge 17 commits into
MFlowCode:masterfrom
danieljvickers:particle-cloud-ib-el-integration

Conversation

@danieljvickers

Copy link
Copy Markdown
Member

Particle Cloud Integration and Feature Upgrade

Overhaul of the long-ignored particle cloud module. The primary feature of this module is the integration of IB particle generation with EL particles and EL bubbles. This allows all three types of cases to benefit from automated particle generation and to use the new features added in this PR.

Integration

Each cloud generates the same points given the same packing method and bounding box. These points are placed into a new lagrangian point data structure, which just holds the essentials for placing a sphere/circle in 3D/2D space. They are converted at the end to the correct data structure, as follows.

call s_get_cloud_points(cloud_idx, points)
select case (particle_cloud(cloud_idx)%particle_type)
case (particle_type_ib)
    call s_points_to_cloud_ibs(points, glb_bounds, global_index, particle_cloud_ibs, num_particle_cloud_ibs)
case (particle_type_el)
    call s_points_to_lag_bubbles(points, lag_bubbles, num_lag_bubbles)
case default
    call s_mpi_abort("Particle cloud particle_type is not a known particle type of MFC. Exiting.")
 end select

Geometry Extension

I have integrated the geometry feature of the patches with the function calls in the geometry module. This allows particles to be placed in side a bounding box defined by all of those structures, including airfoils, STLs, cubes, ellipses, and more. It also means that future geometries are now capable of being integrated nearly for free. I also refactored the hemispherical shell placement to simply check for particles placed inside of on sphere by not another. This deletes the entire hemispherical shell subroutine and replaces it with 5 lines of code or so.

Because I use these boxes to test sample points, it means that they have automatically been integrated with lattice and rejection packing. Any future packing method added should be able to be integrated for free.

Position Distributions

I added a probability density function input that allows the used to specificy an analytic PDF function which will be used to control the distribution of particles. The default is 1, which returns the uniform distribution.

Radial distribution

To support work being done with Lagrangian bubbles, I added a method of analytically prescribing a log-normal distribution on particle radii. This maintains the bubbles functionality while exposing it to IB and EL particle generation.

File Integration

I maintained the ability to place particles using files by defining an input file packing method. This takes files of the same format as before. This will be the new feature going forward, and I added a warning to users that the old method is going to be deprecated in the future.

Reading EL bubbles from lag_params%input_path without a particle cloud is deprecated and will be removed in a future release. File-based particle generation is available through particle clouds: set particle_cloud(j)%particle_type = 'EL', particle_cloud(j)%packing_method = 'file', and particle_cloud(j)%filepath to your bubble file

Every particle cloud geometry now produces only particle centres
(particle_cloud_coords); particle_cloud(i)%particle_type ('IB' or 'EL',
or 1/2) decides whether pre_process turns them into IB patches in the
initial IB state file or Euler-Lagrange bubbles in input/lag_bubbles.dat.
Adds cloud_geometry = 3, which reads centres from particle_cloud(i)%filepath.

Simulation and post_process count only IB clouds toward the global IB
total. Pre_process now defaults and broadcasts shell_axis.
particle_cloud(i)%pdf sets the relative density of particle centres for
rejection-sampled box and hemisphere-shell clouds. The default, 1, is the
uniform placement both geometries already use, and a cloud without a pdf
draws no extra random numbers, so existing placements are unchanged. An
expression is compiled into pre_process through case.fpp, like an
analytic initial condition, and keeps each uniform candidate with
probability pdf/pdf_max, with pdf_max estimated from 1e5 samples.

Simulation no longer pulls in pre_process's case.fpp, only the analytic
IC macro it uses, so a pdf does not change the simulation build.
cloud_geometry now takes the patch_ib geometry numbers (2 circle,
3 rectangle, 4 airfoil, 5 STL, 6 ellipse; 8 sphere, 9 cuboid,
10 cylinder, 11 airfoil, 12 STL), or their names. A patch-shaped cloud
builds an IB patch from its own centroid, lengths, region_radius,
angles, airfoil_id and model_id, and keeps a generated centre when the
shared is-inside dispatch, f_is_inside_patch, accepts it in the patch
frame and it lies in the domain. Rejection packing samples the patch's
world bounding box; lattice packing lays a triangular or FCC lattice
over it at the largest spacing that leaves num_particles sites, and a
pdf thins either. Box stays 1; the hemisphere shell moves to 20 and
file clouds to 21.

The rotation matrix, IB bound, world bounding box and airfoil surface
build move from m_ib_patches to m_patch_geometries so pre_process can
use them; IB results are unchanged. STL models load once when both
ICPP patches and clouds use them.
particle_cloud(i)%density gives each particle the mass of its own size:
simulation computes an IB's mass from the radius in its state record
(per unit depth in 2D), and a rigid EL particle (bubble_model = 0) from
a cloud with a density takes density times its volume instead of its
gas mass. mass stays for IB clouds of one size.

Radii are drawn per particle, largest first: a lognormal in
ln(r/radius) with radius_sigma, clipped to [radius_min, radius_max]
(default +/-3 sigma), or up to num_radius_classes_max discrete classes
from radius_ratio/radius_fraction. With neither set every particle has
radius, as before. Rejection packing keeps each pair the sum of their
radii plus min_spacing apart; the IB state and EL bubble rows carry
each particle's radius, and the automatic IB neighbourhood uses the
largest one.
Shared cloud helpers replace repeated particle counts and cloud lookups,
box sampling runs through the region sampler, and the 2D and 3D STL
bounding boxes share one corner loop. Names are spelled out, doc
comments cut to a line, and sampling, packing and NACA code cited.
The Box-Muller draw is split into two statements so its order no longer
depends on the compiler. Placements and golden results are unchanged.
Every sampled cloud geometry now sets a bounding box, generates candidates in it by rejection or lattice, and keeps those inside the region. Hemisphere shells gain lattice packing and every lattice takes a pdf.
Every cloud fills one Lagrangian point object (position, velocity, radius, interface velocity) that becomes IB patches or lag_bubbles rows. File clouds read the input/lag_bubbles.dat row layout. The automatic IB neighborhood is sized from the largest loaded IB after the state file is read, and the rejection attempt cap accounts for the share of bounding-box draws that land in the region.
Drops the per-feature particle cloud golden tests for one example per feature: an analytic placement pdf (skipped in the suite, as it compiles into pre_process), a rotated cuboid of EL particles with lognormal radii, the dog stipple as a 2D IB file cloud, and IBs filling the MFC letters STL.
Every cloud region now tests only the particle centre, including the hemisphere shell. The rejection pack defers the region-acceptance estimate until the minimum attempt cap is spent, readability edits across the module, examples and toolchain, and a citation for the shock states.
@github-actions

Copy link
Copy Markdown

Claude Code Review

Head SHA: 85891dc

The review produced no output (Claude step: failure). Run and transcript: https://github.com/MFlowCode/MFC/actions/runs/40514816726

@danieljvickers
danieljvickers force-pushed the particle-cloud-ib-el-integration branch from 85891dc to 60d4e05 Compare October 27, 2026 13:47
@github-actions

Copy link
Copy Markdown

Lines of Code

File Lines Diff
src/pre_process/m_particle_cloud.fpp 611 +208
src/common/m_patch_geometries.fpp 243 +173
src/simulation/m_ib_patches.fpp 493 -147
src/common/m_derived_types.fpp 503 +19
src/common/m_helper.fpp 540 +17
src/pre_process/m_data_output.fpp 690 +14
src/pre_process/m_global_parameters.fpp 501 +14
src/simulation/m_bubbles_EL.fpp 1650 +11
src/pre_process/m_mpi_proxy.fpp 153 +9
src/simulation/m_global_parameters.fpp 805 +8
src/pre_process/m_start_up.fpp 508 +4
src/simulation/m_mpi_proxy.fpp 538 +4
src/common/m_constants.fpp 91 +2
src/common/m_model.fpp 726 +1
src/post_process/m_global_parameters.fpp 415 +1
src/post_process/m_mpi_proxy.fpp 167 +1
Directory Lines Diff
common 10756 +212
pre_process 5283 +249
simulation 28474 -124
post_process 3501 +2
total 48014 +339

This branch has not been deployed

No deployments
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.

1 participant