Analyzing aggregates

The one-call entry point, pfa.analyze(), computes the core morphological properties of an aggregate:

import pyFracAggregate as pfa

agg = pfa.generate(256, df=1.8, kf=1.9, method="pca", seed=0)

report = pfa.analyze(agg)   # MorphologyReport
print(f"Rg:       {report.rg:.3f} {agg.length_unit}")
print(f"Df,num:   {report.df_num_est:.3f}  (R2={report.r2_num:.4f})")
print(f"Df,mass:  {report.df_mass_est:.3f}  (R2={report.r2_mass:.4f})")

which for this seed prints:

Rg:       15.230 nm
Df,num:   1.889  (R2=0.9788)
Df,mass:  1.889  (R2=0.9788)

analyze() returns a typed MorphologyReport (a dataclass; pass it through dataclasses.asdict when you need a plain dict):

Field

Meaning

rg

Radius of gyration (float, in length_unit; mass-weighted).

com

Center of mass, shape (3,) array.

n

Number of particles (aggregate.current_size).

estimator

Which family produced the report: "sandbox" or "pcf".

df_num_est

Number-based fractal dimension (counting measure).

r2_num

Fit quality of the number-measure fit.

r_num, num_correlation

Number-measure curve (sandbox: cumulative ⟨N(r)⟩; pcf: C(r)).

df_mass_est

Mass-based fractal dimension (≡ volume-based; constant density).

r2_mass

Fit quality of the mass-measure fit.

r_mass, mass_correlation

Mass-measure curve (sandbox: cumulative ⟨M(r)⟩; pcf: C_m(r)).

export_yaml(agg, path, analysis_results=report) serializes the report under the v0.6 snapshot key names (Rg, CoM, N, estimator, Df_num_estimated, R2_num, r_num, num_correlation, Df_mass_estimated, R2_mass, r_mass, mass_correlation). The estimator key records which family produced the numbers, so snapshots stay traceable. Consumers must read the estimator field before interpreting r_num/num_correlation (sandbox mode holds cumulative curves; pcf mode holds differenced curves).

Interpreting df_num_est, df_mass_est and the r2 fields

analyze() reports both measures (see the background chapter for what the two measures mean). For monodisperse primaries the mass measure is the counting measure times a constant, so df_mass_est equals df_num_est exactly — a useful sanity check. For polydisperse primaries the two track the same underlying arrangement unless radii correlate with position.

Two caveats: a single realization at moderate N deviates from the requested df by a few tenths, and the r2 fields measure fit quality, not agreement with the request. Average over several seeded realizations before quoting ensemble numbers.

estimator="pcf" switches the classic pair-correlation path (differenced C(r)/C_m(r) curves); the mass PCF curve is noisy on single realizations — prefer the default sandbox estimator for df_mass_est.

Individual functions

All helpers accept an Aggregate and are re-exported at the top level (full signatures in the API reference).

Morphology

rg = pfa.radius_of_gyration(agg)   # float
com = pfa.center_of_mass(agg)      # (3,) array

radius_of_gyration includes the finite size of the primaries via the parallel-axis theorem (\(3/5\,r^2\) per solid sphere).

Sandbox functions

r_num, n_r = pfa.number_radius_function(agg)      # <N(r)>, 15 log-spaced points
r_mass, m_r = pfa.mass_radius_function(agg)       # <M(r)>, weights r_i^3

dfn, r2n, fitn = pfa.number_sandbox_dimension(agg)
dfm, r2m, fitm = pfa.mass_sandbox_dimension(agg)

bins is the number of log-spaced grid points; the default window runs from the mean primary radius to Rg (pass r_min/r_max to override). plot_sandbox(agg, measure="both") overlays both curves with their fits — the measure-comparison figure.

Mass pair correlation

r, c_m = pfa.mass_pair_correlation_function(agg, bins=50)

Pairs are weighted by \(m_i m_j\) (particle volumes; constant density makes mass- and volume-weighting identical). Noisy on single realizations — intended for ensemble-averaged curves.

Pair correlation function

r_centers, c_r = pfa.pair_correlation_function(agg, bins=50)

bins sets the number of equal-width bins between 0 and r_max; when r_max is None (default) it defaults to twice the largest distance of any particle center from the cluster centroid. Distances are in length_unit.

Fractal-dimension estimation

df_est, r2, fit = pfa.estimate_fractal_dimension(
    r_centers, c_r, r_min=np.mean(agg.radii), r_max=rg
)

r_min/r_max bound the regression window — restrict them to the fractal regime (between roughly the mean primary radius and \(R_g\)) rather than fitting the whole curve. fit is a dict with the slope, intercept, and the fitted points (x_fit, y_fit).

Plotting

plot_pair_correlation renders \(C(r)\) on log-log axes with the fractal fit and fit window; pass save_path="pcf.png" to write a file instead of opening a window.

plot_pair_correlation accepts measure="num" (default), "mass", or "both". plot_sandbox accepts the same values with "both" as default.

pfa.plot_pair_correlation(agg, save_path="pcf.png")

Note

Plotting requires matplotlib, which is not installed by default: run pip install "pyFracAggregate[plot]" (see Installation). On servers without a display, matplotlib automatically selects its non-interactive backend at import time, and save_path writes the figure to disk without opening a window.

Units

An Aggregate carries its units as plain attributes, set at construction time by the generator: length_unit (default 'nm'), mass_unit (default 'g'), and density (default 1.0). Particle masses are computed as \(\rho \cdot \frac{4}{3}\pi r^3\), i.e. density times sphere volume in the chosen units. pfa.generate() forwards these as keyword-only arguments:

agg = pfa.generate(
    32, df=1.8, kf=1.9,
    length_unit="um", mass_unit="kg", density=1.8,
    particle_dist=pfa.Monodisperse(15.0),  # radii now in um
)

pfa.analyze() and radius_of_gyration return values in length_unit; nothing converts units for you — if you generate with length_unit="um" and radii of 15.0, Rg is in um as well. The units are carried through verbatim by the YAML export (see Exporting data).