API Reference

Complete reference for the public symbols exported by pyFracAggregate (the package’s __all__), grouped by layer: the top-level facade, the core data structures and scaling laws, the two generation algorithms, the analysis functions, the I/O exporters, and the placement strategies.

Top-level API

The facade functions cover the common workflow: build an aggregate with generate() (which validates the method × scaling × placement coordinate and dispatches), then summarize its morphology with analyze() (returning a MorphologyReport).

pyFracAggregate.generate(n_particles: int, df: float, kf: float, method: Literal['pca', 'cca'] = 'pca', scaling: Literal['count', 'mass'] = 'mass', placement: Literal['sampled', 'solved', 'constructed'] = 'solved', particle_dist: ParticleDistribution | None = None, overlap_tolerance: float = 1e-05, seed: int | None = None, **kwargs) Aggregate[source]

High-level API to generate a fractal aggregate.

Parameters:
  • n_particles (int) – Target number of particles.

  • df (float) – Fractal dimension (typically 1.5 - 2.5).

  • kf (float) – Fractal prefactor (typically 1.0 - 2.0).

  • method (str) – Algorithm family: ‘pca’ (particle-cluster) or ‘cca’ (cluster-cluster). ‘fracval’ is a deprecated alias for (cca, mass, constructed).

  • scaling (str) – ‘count’ (Filippov 2000 count weighting) or ‘mass’ (Moran 2019 mass weighting; polydispersity-correct). Default ‘mass’.

  • placement (str) – ‘sampled’ (Monte Carlo), ‘solved’ (closed-form tangency; default), or ‘constructed’ (FracVAL contact construction; cca only).

  • particle_dist – Particle radius distribution (defaults to Monodisperse(1.0)).

  • overlap_tolerance (float) – Allowed overlap between spheres.

  • seed (int) – Seed for reproducible generation (None = fresh entropy).

Returns:

The generated fractal aggregate.

Return type:

Aggregate

pyFracAggregate.analyze(aggregate: Aggregate, estimator: Literal['sandbox', 'pcf'] = 'sandbox') MorphologyReport[source]

Compute the core morphological properties of an aggregate.

Parameters:
  • aggregate (Aggregate) – Cluster object.

  • estimator (str) – ‘sandbox’ (default) fits the cumulative mass-radius curves <N(r)> and <M(r)> — statistically robust for both measures; ‘pcf’ fits the differenced pair-correlation curves C(r) and C_m(r) — the counting path is the classic estimator, the mass path is noisy on single realizations.

Core

Aggregate is the central data structure every other layer produces or consumes: a pre-allocated (max_particles, 5) NumPy array of [x, y, z, radius, mass] rows whose positions, radii, and masses properties are zero-copy views. The distribution classes describe primary-particle sizes and are passed to generators via the particle_dist argument; the scaling laws own the parallel-axis target-distance equations (count- vs mass-weighted).

class pyFracAggregate.core.aggregate.Aggregate(max_particles: int, length_unit: str = 'nm', mass_unit: str = 'g', density: float = 1.0)[source]

Core physical entity representing a fractal cluster.

Uses pre-allocated contiguous memory via NumPy for high data locality and access performance.

add_particle(x: float, y: float, z: float, r: float, m: float) None[source]

Adds a new particle. O(1) complexity.

Parameters:
Raises:

RuntimeError – If cluster reaches maximum capacity.

property current_size: int

Gets the current total number of particles.

property masses: ndarray

Gets particle masses.

Returns:

A zero-copy view with shape (N,).

Return type:

np.ndarray

property max_size: int

Gets the maximum allowed number of particles.

property positions: ndarray

Gets particle coordinates.

Returns:

A zero-copy view with shape (N, 3).

Return type:

np.ndarray

property radii: ndarray

Gets particle radii.

Returns:

A zero-copy view with shape (N,).

Return type:

np.ndarray

to_numpy() ndarray[source]

Exports a copy of valid particles.

Returns:

A copy of the data with shape (N, 5).

Return type:

np.ndarray

class pyFracAggregate.core.distributions.Monodisperse(radius: float)[source]

Monodisperse distribution (all particles have the same radius).

sample(n: int, rng: Generator | None = None) ndarray[source]

Samples n particle sizes.

Parameters:
  • n (int) – Number of particle sizes to generate.

  • rng (np.random.Generator, optional) – Random generator; None uses NumPy’s global legacy stream.

Returns:

An array of particle sizes with shape (n,).

Return type:

np.ndarray

class pyFracAggregate.core.distributions.LognormalDistribution(mean: float, std: float)[source]

Lognormal distribution.

sample(n: int, rng: Generator | None = None) ndarray[source]

Samples n particle sizes.

Parameters:
  • n (int) – Number of particle sizes to generate.

  • rng (np.random.Generator, optional) – Random generator; None uses NumPy’s global legacy stream.

Returns:

An array of particle sizes with shape (n,).

Return type:

np.ndarray

class pyFracAggregate.core.distributions.FixedRadii(radii: ndarray)[source]

Replays a pre-sampled radius array verbatim.

Used to seed CCA subclusters from an already-sampled global distribution.

sample(n: int, rng: Generator | None = None) ndarray[source]

Samples n particle sizes.

Parameters:
  • n (int) – Number of particle sizes to generate.

  • rng (np.random.Generator, optional) – Random generator; None uses NumPy’s global legacy stream.

Returns:

An array of particle sizes with shape (n,).

Return type:

np.ndarray

class pyFracAggregate.core.scaling.ScalingLaw(df: float, kf: float)[source]

Strategy for target distances in PCA steps and CCA merges.

abstractmethod cca_gamma(agg1: Aggregate, agg2: Aggregate) float[source]

Required center-of-mass separation for merging two clusters.

abstractmethod char_radius(radii: ndarray) float[source]

Characteristic primary radius for the scaling-law target.

abstractmethod pca_step(agg: Aggregate, r_new: float, m_new: float, all_radii: ndarray) tuple[ndarray, float][source]

Reference center and step distance for adding one particle.

Parameters:
  • agg – Aggregate with n-1 existing particles.

  • r_new – Radius of the incoming particle.

  • m_new – Mass of the incoming particle.

  • all_radii – Radii of all n particles (existing + incoming).

Returns:

the placement reference point and the required distance of the new particle from it.

Return type:

(center, distance)

abstractmethod weights(aggregate: Aggregate) ndarray[source]

Per-particle weights used for centers of mass.

class pyFracAggregate.core.scaling.CountScaling(df: float, kf: float)[source]

Count-weighted parallel axis law (Filippov et al., 2000).

cca_gamma(agg1: Aggregate, agg2: Aggregate) float[source]

Required center-of-mass separation for merging two clusters.

char_radius(radii: ndarray) float[source]

Characteristic primary radius for the scaling-law target.

pca_step(agg: Aggregate, r_new: float, m_new: float, all_radii: ndarray) tuple[ndarray, float][source]

Reference center and step distance for adding one particle.

Parameters:
  • agg – Aggregate with n-1 existing particles.

  • r_new – Radius of the incoming particle.

  • m_new – Mass of the incoming particle.

  • all_radii – Radii of all n particles (existing + incoming).

Returns:

the placement reference point and the required distance of the new particle from it.

Return type:

(center, distance)

weights(aggregate: Aggregate) ndarray[source]

Per-particle weights used for centers of mass.

class pyFracAggregate.core.scaling.MassScaling(df: float, kf: float)[source]

Mass-weighted parallel axis law (Moran et al., 2019, FracVAL).

cca_gamma(agg1: Aggregate, agg2: Aggregate) float[source]

Required center-of-mass separation for merging two clusters.

char_radius(radii: ndarray) float[source]

Characteristic primary radius for the scaling-law target.

pca_step(agg: Aggregate, r_new: float, m_new: float, all_radii: ndarray) tuple[ndarray, float][source]

Reference center and step distance for adding one particle.

Parameters:
  • agg – Aggregate with n-1 existing particles.

  • r_new – Radius of the incoming particle.

  • m_new – Mass of the incoming particle.

  • all_radii – Radii of all n particles (existing + incoming).

Returns:

the placement reference point and the required distance of the new particle from it.

Return type:

(center, distance)

weights(aggregate: Aggregate) ndarray[source]

Per-particle weights used for centers of mass.

Generators

Both algorithms share the BaseGenerator constructor contract (n_particles, df, kf, particle_dist, overlap_tolerance, scaling, placement, seed) and each returns an Aggregate from its generate() method. Users normally reach them through generate(method=...); the classes are public for direct use and subclassing.

class pyFracAggregate.generators.pca.PCAGenerator(n_particles: int, df: float, kf: float, particle_dist: ParticleDistribution, overlap_tolerance: float = 1e-05, length_unit: str = 'nm', mass_unit: str = 'g', density: float = 1.0, placement: str | PlacementStrategy = 'solved', scaling: ScalingLaw | str | None = None, seed: int | None = None, surface_beta: float | None = None, rng: Generator | None = None)[source]

Particle-Cluster Aggregation with pluggable placement strategy.

generate() Aggregate[source]

Executes the generation logic.

Returns:

The generated fractal cluster.

Return type:

Aggregate

class pyFracAggregate.generators.cca.CCAGenerator(n_particles: int, df: float, kf: float, particle_dist: ParticleDistribution, overlap_tolerance: float = 1e-05, length_unit: str = 'nm', mass_unit: str = 'g', density: float = 1.0, placement: str | PlacementStrategy = 'solved', scaling: ScalingLaw | str | None = None, seed: int | None = None, surface_beta: float | None = None, rng: Generator | None = None)[source]

Cluster-Cluster Aggregation with pluggable scaling and placement.

generate() Aggregate[source]

Executes the generation logic.

Returns:

The generated fractal cluster.

Return type:

Aggregate

Analysis

Morphological descriptors computed from an Aggregate: global quantities (radius of gyration, center of mass), per-measure fractal-dimension estimators — the sandbox (mass-radius) family for the robust default, the pair-correlation family for the classic counting path — and matplotlib diagnostics. analyze(estimator=...) bundles both measures into a MorphologyReport.

class pyFracAggregate.MorphologyReport(rg: float, com: ndarray, n: int, estimator: str, df_num_est: float, r2_num: float, r_num: ndarray, num_correlation: ndarray, df_mass_est: float, r2_mass: float, r_mass: ndarray, mass_correlation: ndarray)[source]

Typed morphology summary of an aggregate, per measure.

estimator records which family produced the report: “sandbox” (cumulative <N(r)>/<M(r)> curves, default) or “pcf” (differenced pair-correlation curves). Curve field contents follow the estimator; export_yaml serializes all fields under the v0.6 snapshot key names.

pyFracAggregate.analysis.morphology.radius_of_gyration(aggregate: Aggregate) float[source]

Calculate the radius of gyration (Rg) of the aggregate. Uses the parallel axis theorem to account for the finite size of the primary particles. For a solid sphere, the radius of gyration about its own center is sqrt(3/5) * r.

Parameters:

aggregate (Aggregate) – The aggregate object.

Returns:

The radius of gyration.

Return type:

float

pyFracAggregate.analysis.morphology.center_of_mass(aggregate: Aggregate) ndarray[source]

Calculate the center of mass of the aggregate.

Parameters:

aggregate (Aggregate) – The aggregate object.

Returns:

A 1D array of shape (3,) representing the (x, y, z) coordinates of the center of mass.

Return type:

np.ndarray

pyFracAggregate.analysis.correlation.pair_correlation_function(aggregate: Aggregate, bins: int = 50, r_max: float | None = None) tuple[ndarray, ndarray][source]

Calculates the two-point density correlation function C(r).

Efficient calculation based on scipy.spatial.cKDTree.

C(r) = n(r) / (4 * pi * r^2 * h * N) where n(r) is the number of particle pairs between distance r and r+h, N is the total number of particles, and h is the step size (bin width).

Parameters:
  • aggregate (Aggregate) – Cluster object.

  • bins (int) – Number of bins for r.

  • r_max (float, optional) – Maximum distance for calculating the correlation function. If None, the maximum distance between particles is used.

Returns:

(r_centers, C_r) where r_centers are the bin

center distances and C_r are the corresponding correlation values.

Return type:

tuple[np.ndarray, np.ndarray]

pyFracAggregate.analysis.correlation.mass_pair_correlation_function(aggregate: Aggregate, bins: int = 50, r_max: float | None = None) tuple[ndarray, ndarray][source]

Calculates the mass-weighted pair correlation function C_m(r).

Each pair (i, j) contributes weight m_i * m_j with m_i = r_i**3 (volume; with constant material density mass- and volume-weighting are identical up to a constant factor, so the slope is unaffected):

C_m(r) = (sum of m_i*m_j over ordered pairs (i != j) with distance

in [r, r+h]) / (4 * pi * r^2 * h * M)

where M = sum_i m_i and h is the linear bin width. Each unordered pair contributes twice (once per endpoint), matching pair_correlation_function’s ordered-pair counting so the two curves are absolutely comparable (monodisperse: C_m = r^3 * C).

Statistical caveat: a single-realization C_m(r) is noisy — it is dominated by the few largest primaries (participation ratio sum(m)^2/sum(m^2) is small for lognormal radii). Prefer mass_sandbox_dimension for a single aggregate’s Df,m; use this function for ensemble-averaged curves.

Parameters:
  • aggregate (Aggregate) – Cluster object.

  • bins (int) – Number of linear bins for r.

  • r_max (float, optional) – Maximum distance; defaults to twice the largest centre distance from the centroid.

Returns:

(r_centers, C_m).

Return type:

tuple[np.ndarray, np.ndarray]

pyFracAggregate.analysis.correlation.estimate_fractal_dimension(r_centers: ndarray, c_r: ndarray, r_min: float | None = None, r_max: float | None = None) tuple[float, float, dict][source]

Estimates the fractal dimension Df from the pair correlation function C(r).

Performs log-log linear regression on the fractal regime (a < r < Rg). Df is calculated as: Df = slope + 3.

Parameters:
  • r_centers (np.ndarray) – Bin center distances.

  • c_r (np.ndarray) – Correlation function values.

  • r_min (float, optional) – Lower bound for regression.

  • r_max (float, optional) – Upper bound for regression.

Returns:

(Df, R_squared, fit_results)
  • Df: Estimated fractal dimension.

  • R_squared: Coefficient of determination.

  • fit_results: Dictionary containing ‘slope’, ‘intercept’, ‘x_fit’, ‘y_fit’.

Return type:

tuple[float, float, dict]

pyFracAggregate.analysis.correlation.plot_pair_correlation(aggregate: Aggregate, bins: int = 50, show_fit: bool = True, reference_df: float | None = None, measure: str = 'num', save_path: str | None = None) None[source]

Plots the pair correlation function(s) and optionally the fractal fit.

Parameters:
  • aggregate (Aggregate) – Cluster object.

  • bins (int) – Number of bins for the PCF.

  • show_fit (bool) – Whether to show the fractal dimension fit.

  • reference_df (float, optional) – Reference Df to show in plot.

  • measure (str) – ‘num’ (C(r), default), ‘mass’ (C_m(r)), or ‘both’. Single-realization ‘mass’ curves are noisy — see mass_pair_correlation_function.

  • save_path (str, optional) – Path to save the figure.

pyFracAggregate.analysis.sandbox.number_radius_function(aggregate: Aggregate, bins: int = 15, r_min: float | None = None, r_max: float | None = None) tuple[ndarray, ndarray][source]

<N(r)>: mean number of primary centres within r of a primary.

Parameters:
  • aggregate (Aggregate) – Cluster object.

  • bins (int) – Number of log-spaced grid points.

  • r_min (float, optional) – Lower grid bound (default: mean primary radius).

  • r_max (float, optional) – Upper grid bound (default: radius of gyration).

Returns:

(r_centers, N_r).

Return type:

tuple[np.ndarray, np.ndarray]

pyFracAggregate.analysis.sandbox.mass_radius_function(aggregate: Aggregate, bins: int = 15, r_min: float | None = None, r_max: float | None = None) tuple[ndarray, ndarray][source]

<M(r)>: mean summed primary mass within r of a primary.

Weights are r_i**3 (volume); with constant material density mass- and volume-weighting differ only by a constant factor and yield identical exponents.

Parameters:
  • aggregate (Aggregate) – Cluster object.

  • bins (int) – Number of log-spaced grid points.

  • r_min (float, optional) – Lower grid bound (default: mean primary radius).

  • r_max (float, optional) – Upper grid bound (default: radius of gyration).

Returns:

(r_centers, M_r).

Return type:

tuple[np.ndarray, np.ndarray]

pyFracAggregate.analysis.sandbox.number_sandbox_dimension(aggregate: Aggregate, bins: int = 15, r_min: float | None = None, r_max: float | None = None) tuple[float, float, dict][source]

Estimate the number-based fractal dimension Df,n from <N(r)>.

Fits <N(r)> ~ r**Df on a log-log grid (default window: mean primary radius to Rg); returns (Df, R_squared, fit_results) like estimate_fractal_dimension.

pyFracAggregate.analysis.sandbox.mass_sandbox_dimension(aggregate: Aggregate, bins: int = 15, r_min: float | None = None, r_max: float | None = None) tuple[float, float, dict][source]

Estimate the mass-based fractal dimension Df,m from <M(r)>.

Fits <M(r)> ~ r**(Df, m); weights are r_i**3 (volume ≡ mass at constant density). For monodisperse primaries the result is identical to number_sandbox_dimension (constant weights cancel in the slope).

pyFracAggregate.analysis.sandbox.plot_sandbox(aggregate: Aggregate, bins: int = 15, show_fit: bool = True, reference_df: float | None = None, measure: str = 'both', save_path: str | None = None) None[source]

Plot <N(r)> and/or <M(r)> on log-log axes with fractal fits.

The default measure="both" overlays the number and mass curves with their respective fits — the measure-comparison figure.

Parameters:
  • aggregate (Aggregate) – Cluster object.

  • bins (int) – Number of log-spaced grid points.

  • show_fit (bool) – Whether to draw the power-law fits.

  • reference_df (float, optional) – Reference Df slope to show.

  • measure (str) – ‘num’, ‘mass’, or ‘both’.

  • save_path (str, optional) – Path to save the figure.

I/O

Export an Aggregate for downstream use: a YAML snapshot bundling the particle data with generation parameters and analysis results, VTK/VTM files built with pyvista for ParaView and other tools, and off-screen rendered PNG images or MP4 rotation videos. The render and video exporters require a working pyvista 3D backend (see the user guide for headless-environment notes).

pyFracAggregate.io.data.export_yaml(aggregate: Aggregate, output_path: str, *, generation_params: dict | None = None, analysis_results: dict | MorphologyReport | None = None) None[source]

Export aggregate to YAML with optional generation params and analysis results.

Parameters:
  • aggregate – The fractal aggregate object to export.

  • output_path – Path to save the YAML file.

  • generation_params – Optional dict of generation parameters (method, df, kf, etc.).

  • analysis_results – Optional dict of analysis results, or a MorphologyReport from pfa.analyze (serialized under the v0.6 key names “Rg”/”CoM”/”N”/”estimator”/”Df_num_estimated”/ “R2_num”/”r_num”/”num_correlation”/”Df_mass_estimated”/ “R2_mass”/”r_mass”/”mass_correlation”).

pyFracAggregate.io.visualization.save_screenshot(aggregate: Aggregate, path: str, color: str = 'lightblue', opacity: float = 0.8, color_by: str | None = None, cmap: str = 'viridis', background: str = 'white', camera_position: str | tuple = 'iso', window_size: tuple[int, int] = (1024, 768)) None[source]

Render an off-screen 3D screenshot of the aggregate and save as PNG.

Parameters:
  • aggregate – The fractal aggregate to render.

  • path – Output file path (must end in .png).

  • color – Sphere color name or hex; ignored when color_by=”radius”.

  • opacity – Sphere opacity (0.0 to 1.0).

  • color_by – None (solid color) or “radius” (colormap over monomer radii).

  • cmap – Colormap name for color_by=”radius”.

  • background – Background color name or hex.

  • camera_position – Preset name (“iso”, “xy”, “xz”, “yz”) or a (position, focal_point, up) tuple.

  • window_size – (width, height) in pixels.

Raises:

ValueError – If path does not end in .png, the aggregate is empty, or color_by is invalid.

pyFracAggregate.io.visualization.save_rotation_video(aggregate: Aggregate, path: str, color: str = 'lightblue', opacity: float = 0.8, color_by: str | None = None, cmap: str = 'viridis', background: str = 'white', window_size: tuple[int, int] = (1024, 768), n_frames: int = 72, fps: int = 24, elevation: float = 30.0) None[source]

Generate a 360-degree rotation animation of the aggregate and save as MP4.

The camera is auto-framed from the mesh bounds (aerosol3d rule) and orbits once around the aggregate at the given elevation.

Parameters:
  • aggregate – The fractal aggregate to animate.

  • path – Output file path (must end in .mp4).

  • color – Sphere color name or hex; ignored when color_by=”radius”.

  • opacity – Sphere opacity (0.0 to 1.0).

  • color_by – None (solid color) or “radius” (colormap over monomer radii).

  • cmap – Colormap name for color_by=”radius”.

  • background – Background color name or hex.

  • window_size – (width, height) in pixels.

  • n_frames – Total frames for the full 360 degree rotation.

  • fps – Frames per second in the output video.

  • elevation – Camera elevation angle in degrees.

Raises:
  • ValueError – If path does not end in .mp4, the aggregate is empty, or color_by is invalid.

  • ImportError – If imageio is not installed.

pyFracAggregate.io.vtk.export_vtm(aggregate: Aggregate, path: str)[source]

Export the aggregate as a VTM (MultiBlock) file.

Each monomer is represented as a separate sphere block.

pyFracAggregate.io.vtk.export_vtk(aggregate: Aggregate, path: str)[source]

Export the aggregate as a VTK PolyData file (point cloud with attributes).

In ParaView, use the ‘Glyph’ filter with ‘Sphere’ type to visualize.

Placement

Placement strategies decide where a new particle or cluster touches the existing structure while respecting the overlap tolerance; every generator selects one via placement= (name or instance). All classes implement the same two entry points: place_particle() for particle-cluster stages and merge_clusters() for cluster-cluster stages.

class pyFracAggregate.generators.placement.solved.SolvedPlacement(overlap_tolerance: float = 1e-05, surface_beta: float = 0.3, rng: Generator | None = None)[source]

Emergent contact via closed-form tangency solving (Skorupski et al., 2014, FLAGE), with Monte Carlo fallback.

merge_clusters(pos1: ndarray, r1: ndarray, agg1: Aggregate, pos2_centered: ndarray, r2: ndarray, agg2: Aggregate, Gamma: float, mean_radius: float) ndarray[source]

FLAGE-style merge with surface particle filtering + random fallback.

place_particle(agg: Aggregate, candidate_radius: float, candidate_mass: float, geom_center: ndarray, L: float, mean_radius: float) tuple | None[source]

Try algebraic placement, then fall back to random sampling.

class pyFracAggregate.generators.placement.sampled.SampledPlacement(overlap_tolerance: float = 1e-05, rng: Generator | None = None)[source]

Emergent contact via Monte Carlo sampling (Filippov et al., 2000).

merge_clusters(pos1: ndarray, r1: ndarray, agg1: Aggregate, pos2_centered: ndarray, r2: ndarray, agg2: Aggregate, Gamma: float, mean_radius: float) ndarray[source]

Merge two sub-clusters (CCA stage).

Parameters:
  • pos1 – Positions of cluster 1 centered at origin.

  • r1 – Radii of cluster 1.

  • agg1 – Cluster 1 aggregate.

  • pos2_centered – Positions of cluster 2 centered at its COM.

  • r2 – Radii of cluster 2.

  • agg2 – Cluster 2 aggregate.

  • Gamma – Required COM distance between clusters.

  • mean_radius – Mean particle radius.

Returns:

pos2_final array (N2, 3), or None if merge failed.

place_particle(agg: Aggregate, candidate_radius: float, candidate_mass: float, geom_center: ndarray, L: float, mean_radius: float) tuple | None[source]

Place a single particle onto the Gamma sphere (PCA stage).

Parameters:
  • agg – Current aggregate with existing particles.

  • candidate_radius – Radius of the new particle.

  • candidate_mass – Mass of the new particle.

  • geom_center – Geometric center of existing particles.

  • L – Required distance from center to new particle.

  • mean_radius – Mean particle radius.

Returns:

(x, y, z) position tuple, or None if placement failed.

class pyFracAggregate.generators.placement.constructed.ConstructedPlacement(overlap_tolerance: float = 1e-05, rng: Generator | None = None)[source]

Specified contact pair + attitude construction + COM correction (Moran et al., 2019, FracVAL sub-steps b-d).

merge_clusters(pos1: ndarray, r1: ndarray, agg1: Aggregate, pos2_centered: ndarray, r2: ndarray, agg2: Aggregate, Gamma: float, mean_radius: float) ndarray[source]

Merge two sub-clusters (CCA stage).

Parameters:
  • pos1 – Positions of cluster 1 centered at origin.

  • r1 – Radii of cluster 1.

  • agg1 – Cluster 1 aggregate.

  • pos2_centered – Positions of cluster 2 centered at its COM.

  • r2 – Radii of cluster 2.

  • agg2 – Cluster 2 aggregate.

  • Gamma – Required COM distance between clusters.

  • mean_radius – Mean particle radius.

Returns:

pos2_final array (N2, 3), or None if merge failed.

place_particle(agg: Aggregate, candidate_radius: float, candidate_mass: float, geom_center: ndarray, L: float, mean_radius: float) tuple | None[source]

Place a single particle onto the Gamma sphere (PCA stage).

Parameters:
  • agg – Current aggregate with existing particles.

  • candidate_radius – Radius of the new particle.

  • candidate_mass – Mass of the new particle.

  • geom_center – Geometric center of existing particles.

  • L – Required distance from center to new particle.

  • mean_radius – Mean particle radius.

Returns:

(x, y, z) position tuple, or None if placement failed.