pyfracval.fractal#
Fractal metrics and validation for PyFracVAL.
Functions for computing mass, radius of gyration, gamma values, cluster properties, and validating fractal structure.
Functions#
- calculate_mass
Compute total particle mass (proportional to r^3).
- calculate_rg
Compute theoretical radius of gyration from fractal scaling law.
- gamma_calculation
Compute the centre-to-centre distance (gamma) for PCA/CCA sticking.
- calculate_cluster_properties
Compute total mass, Rg, centre-of-mass, and max radius of a cluster.
- compute_empirical_rg
Compute empirical Rg from actual particle coordinates.
- compute_pair_correlation_dimensions
Estimate fractal dimension from pair-correlation (mass-radius) scaling.
- validate_fractal_structure
Validate that generated aggregate matches target fractal parameters.
Module Contents#
- pyfracval.fractal.calculate_mass(radii, densities=None)[source]#
Calculate particle mass from radii and (optionally) per-particle density.
m_i = (4/3) pi r_i^3 rho_i.- Parameters:
radii (np.ndarray) – Array of particle radii.
densities (np.ndarray, optional) – Per-particle densities.
None(the default) means uniform density, in which case mass is proportional to r^3 and every density-aware quantity reduces exactly to its single-material form. Supplying densities is what makes heterogeneous aggregates - different materials, not just different sizes - physically meaningful, since the center of mass, radius of gyration and the Gamma equation are all mass-weighted.
- Returns:
Array of corresponding particle masses.
- Return type:
np.ndarray
- pyfracval.fractal.resolve_densities(densities, n, context='densities')[source]#
Validate an optional per-particle density array against a count.
Returns the array unchanged (as float) when supplied, or
Nonefor the uniform-density case so downstream code can keep taking the cheaperNonepath rather than carrying an array of ones.
- pyfracval.fractal.compute_empirical_rg_polydisperse(coords, radii, densities=None)[source]#
Radius of gyration of actual coordinates, including each primary particle’s own gyration radius (paper Eq. 4).
Differs from
compute_empirical_rg(), which treats particles as point masses and so omits the \(r_{g,i}^2\) term below. That omission is a constant offset for monodisperse input but grows with polydispersity, and it makes the point-mass form inconsistent with the Gamma equation, whose derivation (paper Appendix A, Eq. A.5) carries the term throughout. Anything that has to agree with Gamma - the measured-Rg feedback incca/pairing.py, the per-aggregate quality record - must use this function; usecompute_empirical_rg()only where a point-mass Rg is what is actually wanted.The counterpart to
calculate_rg(), which returns the radius of gyration the fractal scaling law prescribes for a given particle count. This one measures what a built aggregate actually has:\[R_g^2 = \frac{1}{m_a}\sum_i m_{p,i}[(R_i - R_c)^2 + r_{g,i}^2]\]with \(r_{g,i}^2 = \frac{3}{5}r_{p,i}^2\) the primary particle’s own gyration radius and \(R_c\) the mass-weighted center of mass (Eq. 5). The \(r_{g,i}^2\) term is what makes this valid for polydisperse primary particles [Morán et al., 2019]; dropping it (as monodisperse treatments do) underestimates Rg for wide size distributions.
- Parameters:
coords (np.ndarray) – Nx3 particle coordinates.
radii (np.ndarray) – N particle radii.
densities (np.ndarray, optional) – Per-particle densities;
Nonemeans uniform. Both the center of mass and the mass weighting below use these, so a heterogeneous aggregate’s Rg is only correct when they are supplied.
- Returns:
Measured radius of gyration; 0.0 for an empty aggregate.
- Return type:
- pyfracval.fractal.calculate_rg(radii, npp, df, kf)[source]#
Calculate the radius of gyration using the fractal scaling law.
Implements the formula Rg = a * (N / kf)^(1/Df), where ‘a’ is the geometric mean radius calculated from the input radii array. See [Morán et al., 2019] and morphology context [Filippov et al., 2000].
- Parameters:
- Returns:
The calculated radius of gyration (Rg). Returns 0.0 if npp is 0, kf or df is zero, or if calculation fails (e.g., log error).
- Return type:
- pyfracval.fractal.gamma_calculation(m1, rg1, radii1, m2, rg2, radii2, df, kf, use_mass=False, all_radii=None)[source]#
Calculates Gamma_pc for adding the next monomer (aggregate 2).
The Gamma_pc relation follows the FracVAL CCA/PCA formulation [Morán et al., 2019].
- Parameters:
use_mass (bool, default False) – Which form of the Gamma equation to solve.
Falsesubstitutes particle counts for the masses, giving Filippov et al. (2000) Eq. 7 - what the Fortran PCA does (PCA_cca.f90’sGamma_calculationtakesn1, n2, n3) and what this port has historically done everywhere.Trueuses the true masses passed in asm1/m2, giving Moran et al. (2019) Eq. 6 - the paper’s central polydisperse contribution, and what the Fortran CCA actually does (CCA_module.f90:301). Identical for monodisperse primary particles; they diverge as polydispersity grows. See NOTE.md 1.2.all_radii (np.ndarray, optional) – If provided, the geometric mean radius for rg3 is computed from this full set of radii (matching Fortran behaviour where R contains all N particles). When None the geometric mean is taken from the local combined set (radii1 + radii2).
rg3_override (float, optional) – Use this radius of gyration for the combined aggregate instead of deriving it from the scaling law. Only meaningful together with measured (rather than scaling-law) rg1/rg2 - see
cca/pairing.py’s measured-Rg feedback.
- pyfracval.fractal.calculate_cluster_properties(coords, radii, df, kf, densities=None)[source]#
Calculate aggregate properties: total mass, Rg, center of mass, Rmax.
- Parameters:
coords (np.ndarray) – Nx3 array of particle coordinates.
radii (np.ndarray) – N array of particle radii.
df (float) – Fractal dimension used for Rg calculation.
kf (float) – Fractal prefactor used for Rg calculation.
densities (np.ndarray, optional) – Per-particle densities;
Nonemeans uniform. Affects the total mass and the center of mass (and hence r_max), which in turn feed the Gamma equation.
- Returns:
- A tuple containing:
total_mass (float): Sum of individual particle masses.
rg (float | None): Radius of gyration calculated via calculate_rg, or None if calculation failed.
cm (np.ndarray | None): 3D center of mass coordinates, or None if calculation failed.
r_max (float): Maximum distance from the center of mass to any particle center in the aggregate.
Returns (0.0, 0.0, np.zeros(3), 0.0) for empty inputs (N=0).
- Return type:
- pyfracval.fractal.compute_empirical_rg(coords, radii)[source]#
Compute empirical Rg directly from particle coordinates (mass-weighted).
Unlike
calculate_rgwhich uses the fractal scaling law Rg = a*(N/kf)^(1/Df), this function measures Rg from the actual spatial distribution of particles.Treats each particle as a point mass. See
compute_empirical_rg_polydisperse()for the form that also carries each particle’s own gyration radius (paper Eq. 4) - required wherever the result has to be consistent with the Gamma equation.- Parameters:
coords (np.ndarray) – Nx3 array of particle center coordinates.
radii (np.ndarray) – N array of particle radii. Mass is proportional to r^3.
- Returns:
Empirical (mass-weighted) radius of gyration.
- Return type:
- pyfracval.fractal.compute_pair_correlation_dimensions(coords, radii, n_bins=50)[source]#
Estimate fractal dimension from pair-correlation (mass-radius) scaling.
Computes the cumulative mass M(r) as a function of radial distance from the centre of mass. For a fractal aggregate, M(r) ~ r^Df, so a log-log fit gives the empirical Df.
The fit uses raw (un-normalised) cumulative mass because normalised mass fractions are in [0,1] whose logs are non-positive, breaking the log-linear regression.
- Parameters:
coords (np.ndarray) – Nx3 array of particle center coordinates.
radii (np.ndarray) – N array of particle radii.
n_bins (int) – Number of radial bins (default 50).
- Returns:
r_bins : np.ndarray — bin edge radii (n_bins+1,) r_centers : np.ndarray — bin centre radii (n_bins,) M_r : np.ndarray — cumulative normalised mass fraction within each radius (n_bins+1,) empirical_Df : float — slope of log(M) vs log(r) fit fit_r_squared : float — R^2 of the linear fit empirical_kf : float — estimated kf from the fit
- Return type:
dict with keys
- pyfracval.fractal.validate_fractal_structure(coords, radii, target_df, target_kf, rg_rtol=0.05)[source]#
Validate that generated aggregate matches target fractal parameters.
Compares theoretical Rg (from scaling law) vs empirical Rg (from coordinates), and estimates the actual fractal dimension from mass-radius scaling.
- Parameters:
- Returns:
N : int — number of particles theoretical_rg : float — Rg from scaling law Rg = a*(N/kf)^(1/Df) empirical_rg : float — Rg measured from coordinates rg_error_pct : float — (empirical - theoretical)/theoretical * 100 rg_ok : bool —
rg_error_pct< rg_rtol * 100 empirical_Df : float — Df estimated from mass-radius scaling target_Df : float — target fractal dimension df_error : float — empirical_Df - target_Df fit_r_squared : float — goodness of fit for Df estimation empirical_kf : float — estimated fractal prefactor target_kf : float — target fractal prefactor- Return type:
dict with keys