pyfracval.pca_agg#

Implements Particle-Cluster Aggregation (PCA) for initial subclusters.

This module follows the PCA stage of the FracVAL workflow described in [Morán et al., 2019], with fractal scaling context from [Filippov et al., 2000].

Note

PCA solves the Gamma equation with particle counts, while pyfracval.cca solves it with true masses. That is not an oversight in either place. The scaling law supplying Rg is a function of particle count, and mass-weighting is only consistent with it when both merging bodies are aggregates the law describes - here the second body is a single monomer, whose scaling-law Rg is meaningless at n=1 while its mass can still be a large fraction of the growing cluster’s. Using masses here builds 1/150 subclusters where counts build 93/150. See PCAggregator._gamma_calculation for the full argument and the measurement.

Per-particle densities still matter in this stage: they feed self.mass, self.m1 and the running center of mass.

Module Contents#

class pyfracval.pca_agg.PCAggregator(initial_radii, df, kf, tol_ov, rng=None, algorithm_config=None, densities=None)[source]#

Performs Particle-Cluster Aggregation (PCA).

Builds a single cluster by sequentially adding individual primary particles (monomers) to a growing aggregate, attempting to match the target Df and kf via the Gamma_pc calculation at each step. Includes overlap checking and rotation to find valid placements.

Parameters:
  • initial_radii (np.ndarray) – 1D array of radii for the primary particles to be aggregated.

  • df (float) – Target fractal dimension for the aggregate.

  • kf (float) – Target fractal prefactor for the aggregate.

  • tol_ov (float) – Maximum allowable overlap fraction between particles.

N[source]#

Total number of particles to aggregate.

Type:

int

initial_mass[source]#

Calculated initial masses corresponding to initial_radii.

Type:

np.ndarray

coords[source]#

Nx3 array storing coordinates of particles as they are placed.

Type:

np.ndarray

radii[source]#

N array storing radii of particles as they are placed.

Type:

np.ndarray

mass[source]#

N array storing masses of particles as they are placed.

Type:

np.ndarray

n1[source]#

Number of particles currently in the aggregate.

Type:

int

m1[source]#

Mass of the current aggregate.

Type:

float

rg1[source]#

Radius of gyration of the current aggregate.

Type:

float

cm[source]#

3D center of mass of the current aggregate.

Type:

np.ndarray

r_max[source]#

Maximum distance from CM to any particle center in the aggregate.

Type:

float

not_able_pca[source]#

Flag indicating if the aggregation process failed.

Type:

bool

run()[source]#

Run the complete PCA process for all N particles.

Sequentially adds particles from index 2 to N-1. For each particle k, it calculates Gamma_pc, finds potential sticking partners (candidates) in the existing aggregate (0..k-1), potentially swaps particle k with an unused one if no candidates are found initially.

It then attempts to stick particle k to each candidate partner, calculating an initial position based on sphere intersections defined by Gamma_pc. If overlap occurs, it rotates particle k around the intersection circle (_reintento) up to max_rotations times.

If a non-overlapping position is found for any candidate, the particle is successfully added, and aggregate properties are updated. If all candidates and all rotations fail for a particle k, or if the initial search/swap fails, the aggregation stops, not_able_pca is set True, and None is returned.

Returns:

An Nx4 NumPy array [X, Y, Z, R] of the final aggregate if successful, otherwise None.

Return type:

np.ndarray | None