Skip to content

API — Particle assemblies

MeanFieldHomogenization.Assemblies Module
julia
MeanFieldHomogenization.Assemblies

Assemblies of individually located inclusions, and the two N-body schemes that act on them.

Every other cell of the package describes a microstructure statistically — an RVE by volume fractions, a Laminate by a stacking order. That is all a one-site scheme can use, and it is not enough here: the field one inclusion induces in another depends on the vector joining their centers. Hence ParticleAssembly, a cell that carries positions.

Two schemes consume it, and they share both the cell and the interaction kernel of MeanFieldHomogenization.Interactions:

  • ClusterModel — Molinari & El Mouden (1996), solving for the mean strain of every inclusion inside a cluster of neighbors;

  • EquivalentInclusion — [2], a Galerkin discretization of the weak Lippmann-Schwinger equation, which additionally delivers a rigorous bound on the apparent stiffness.

Contents

  • assembly.jl : Particle, the boundary treatments (MixedBC, PeriodicBox), the ParticleAssembly cell and its AbstractHomogenizationCell contract

  • generators.jl : cubic lattices and hard-particle random microstructures

  • block_solve.jl : linear systems whose unknowns are tensors, flattened onto the Kelvin-Mandel basis

  • cluster_model.jl : the Molinari & El Mouden kernel

  • eim.jl : the equivalent-inclusion kernel

  • as_rve.jl : RVE(asm) — forget the positions, keep the fractions, which is what makes every one-site scheme of the package available on an assembly

  • parameters.jl : parameter lenses (positions, radii) for the differentiation entry points

The cell

MeanFieldHomogenization.Assemblies.ParticleAssembly Type
julia
ParticleAssembly{T<:Number, B<:AbstractAssemblyBoundary} <: AbstractHomogenizationCell

A matrix holding individually located inclusions — the cell the N-body schemes EquivalentInclusion and ClusterModel act on.

Fields:

  • matrix_name::Symbol and matrix_properties::Dict{Symbol,Any} — the reference phase, which is also the reference medium of both models;

  • particle_names::Vector{Symbol} — particles in insertion order;

  • particles::Dict{Symbol,Particle} — position, geometry and moduli of each;

  • boundary::BMixedBC or PeriodicBox;

  • families::Dict{Symbol,Int} — family label per particle. Particles sharing a label are constrained to carry the same polarization or localization tensor, which is how a lattice with a small motif is described without repeating its equations. Defaults to one family per particle.

Construction is two-step, mirroring RVE and Laminate:

julia
asm = ParticleAssembly(; boundary = PeriodicBox(1.0; cutoff = 3.0))
add_matrix!(asm, Dict(:C => C_m))
add_particle!(asm, :p1, (0.0, 0.0, 0.0), Ellipsoid(0.3), Dict(:C => C_i))
homogenize(asm, ClusterModel(), :C)

See also add_particle!, particle_volume_fraction, assembly_volume, validate_assembly.

MeanFieldHomogenization.Assemblies.Particle Type
julia
Particle(center, geometry, properties)

One individually located inclusion of a ParticleAssembly: where it is, what shape it has, and what it is made of.

Unlike a Phase, a particle is a single object rather than a population — it carries no volume fraction, since the fraction follows from its volume and the size of the cell.

A property value may be a Homogenized cell + scheme, resolved lazily at homogenize time exactly as in an RVE.

MeanFieldHomogenization.Assemblies.add_matrix! Function
julia
add_matrix!(asm::ParticleAssembly, properties) -> asm

Set the matrix properties of an assembly. The matrix is also the reference medium of both N-body models — neither uses a reference distinct from the matrix, following the papers they come from.

MeanFieldHomogenization.Assemblies.add_particle! Function
julia
add_particle!(asm, name, center, geometry, properties; family = nothing) -> asm

Add one located inclusion to the assembly.

family groups particles that must share the same unknown. Leaving it unset gives the particle a family of its own, which is what a random assembly wants; passing an explicit label is how a periodic motif with symmetric particles is declared without duplicating equations.

MeanFieldHomogenization.Assemblies.validate_assembly Function
julia
validate_assembly(asm) -> asm

Check that an assembly is solvable: a matrix is present, at least one particle is present, all particles share the same dimension, the total volume fraction is below one, and no two particles overlap.

The overlap check is not pedantry — the interaction kernel is only defined for disjoint regions, and an overlap would otherwise surface much later as a DomainError from deep inside a lattice sum. Overlap is tested between the bounding spheres of the particles, which is exact for spherical particles and conservative otherwise.

Boundary treatments

MeanFieldHomogenization.Assemblies.AbstractAssemblyBoundary Type
julia
AbstractAssemblyBoundary

How a ParticleAssembly closes its far field. This is the one place where the two N-body models of the package genuinely differ: they solve the same linear system and differ in what surrounds the cell.

MeanFieldHomogenization.Assemblies.MixedBC Type
julia
MixedBC(shape) <: AbstractAssemblyBoundary

Mixed boundary conditions of [2]: the statistical volume element shape — which must be an ellipsoid, since the derivation leans on Eshelby's theorem for the domain itself — is embedded in an infinite medium of the matrix stiffness, subject to a uniform strain at infinity plus a uniform surface traction chosen so that the loading parameter coincides with the macroscopic strain.

Its practical virtue is that no periodization is needed: the far field is closed by a single correction term involving the Hill tensor of the SVE domain, , instead of by a lattice sum that is only conditionally convergent.

MixedBC(radius) is shorthand for a spherical (3D) SVE; pass an Ellipsoid for anything else.

MeanFieldHomogenization.Assemblies.PeriodicBox Type
julia
PeriodicBox(period; cutoff = 3 * period) <: AbstractAssemblyBoundary

Periodic elementary representative volume of [1]: the cubic cell of side period tiles space, each particle carrying a family of periodic images, and the interaction sums are truncated to the images lying within cutoff of the receiver.

The cutoff is a sphere, not a box, and that is not cosmetic: Molinari & El Mouden's Appendix B proves convergence from the vanishing of the interaction kernel integrated over the exterior of a sphere. Their own convergence study finds the estimate stable beyond cutoff ≈ 2 · period; the default of three periods is comfortably inside that plateau.

cutoff = 0 reduces every cluster to its own receiver, which is the degenerate case in which the cluster model collapses exactly onto Mori-Tanaka (their Appendix C) — a useful thing to be able to ask for.

The bridge to the one-site schemes

MeanFieldHomogenization.Schemes.RVE Method
julia
RVE(asm::ParticleAssembly; matrix_geometry = nothing, distribution_shape = nothing)

Statistical view of an assembly: forget the positions, keep everything else. Returns an RVE whose matrix carries the assembly's matrix properties and which has one phase per particle, each with that particle's geometry, properties and derived volume fraction  .

This is the bridge that makes every one-site scheme available on an assembly. It is applied automatically by homogenizehomogenize(asm, MoriTanaka(), :C) just works — and is exported so that the intermediate cell can be inspected:

julia
asm = cubic_lattice(:sc, Dict(:C => C_m), Dict(:C => C_i); fraction = 0.3)
homogenize(asm, ClusterModel(), :C)     # sees the positions
homogenize(asm, MoriTanaka(), :C)       # goes through RVE(asm); ignores them
rve = RVE(asm)                          # …and here it is, to look at

matrix_geometry is the shape the matrix phase is given. An assembly has no matrix shape of its own, so it defaults to a ball (a disk in 2D) — the neutral, orientation-free choice, and the one the one-site scripts of the package use. It is read by the schemes that localize every phase alike — the self-consistent family and the bounds — and ignored by MoriTanaka, Dilute, Maxwell and PCW, which need the matrix property only.

distribution_shape is forwarded to the RVE constructor and is what PonteCastanedaWillis needs; an assembly carries no such statistical descriptor, so it must be supplied here if that scheme is wanted.

One phase per particle

The conversion does not merge identical particles. It does not need to: every scheme sums over phases linearly, so N identical phases of fraction f/N give exactly the same effective property as one phase of fraction f. Keeping them apart avoids an equality heuristic on geometries and preserves the particle names.

There is no way back

RVE(asm) discards the positions, which is the whole point — but it means the result can no longer feed ClusterModel or EquivalentInclusion. Those need the assembly itself.

See also ParticleAssembly, particle_volume_fraction.

Accessors

MeanFieldHomogenization.Assemblies.matrix_property Function
julia
matrix_property(asm, key) -> value

Property key of the matrix, resolving a Homogenized value if one is stored. This is also the reference medium of both N-body models.

MeanFieldHomogenization.Assemblies.matrix_volume_fraction Function
julia
matrix_volume_fraction(asm) -> Real

Volume fraction of the matrix, 1 - Σ_a f_a.

MeanFieldHomogenization.Assemblies.particle_names Function
julia
particle_names(asm) -> Vector{Symbol}

Particle names in insertion order.

MeanFieldHomogenization.Assemblies.particle Function
julia
particle(asm, name) -> Particle

The stored Particle of the given name.

MeanFieldHomogenization.Assemblies.particle_center Function
julia
particle_center(asm, name) -> AbstractVector

Center of a particle.

MeanFieldHomogenization.Assemblies.particle_geometry Function
julia
particle_geometry(asm, name) -> AbstractInclusion

Geometry of a particle.

MeanFieldHomogenization.Assemblies.particle_property Function
julia
particle_property(asm, name, key) -> value

Property key of particle name, resolving a Homogenized value if one is stored (declarative multiscale nesting). Use cell_container_property for the raw stored value.

MeanFieldHomogenization.Assemblies.particle_family Function
julia
particle_family(asm, name) -> Int

Family label of a particle. Particles sharing a label share their unknown.

MeanFieldHomogenization.Assemblies.family_labels Function
julia
family_labels(asm) -> Vector{Int}

Distinct family labels, in order of first appearance.

MeanFieldHomogenization.Assemblies.particle_volume Function
julia
particle_volume(asm, name) -> Real

Volume (3D) or area (2D) of one particle.

MeanFieldHomogenization.Assemblies.particle_volume_fraction Function
julia
particle_volume_fraction(asm, name) -> Real

Volume fraction f_a = |Ω_a| / |Ω| of one particle. Derived from the geometry and the boundary, never stored — so it cannot disagree with the microstructure it describes.

MeanFieldHomogenization.Assemblies.inclusion_volume_fraction Function
julia
inclusion_volume_fraction(asm) -> Real

Total volume fraction of the particles, Σ_a f_a.

MeanFieldHomogenization.Assemblies.assembly_volume Function
julia
assembly_volume(asm) -> Real

Measure of the cell: the volume of the SVE for MixedBC, Lᵈ for a PeriodicBox. It is what turns particle volumes into volume fractions.

Generators

MeanFieldHomogenization.Assemblies.cubic_lattice Function
julia
cubic_lattice(kind, matrix_properties, particle_properties;
              fraction = nothing, radius = nothing, period = 1.0,
              cutoff = nothing, name_prefix = :p, T = Float64)
    -> ParticleAssembly

Build a ParticleAssembly on the simple-cubic (:sc), body-centered (:bcc) or face-centered (:fcc) cubic lattice of equal spheres, with PeriodicBox boundary conditions.

Give exactly one of fraction (total volume fraction of the spheres) or radius. cutoff is forwarded to PeriodicBox; the default of three periods sits inside the convergence plateau reported by [1].

particle_properties may be a single property dictionary — applied to every site — or a vector of dictionaries, one per site of the motif, which is how a multi-phase array such as their BCC arrangement of alternating voids and rigid spheres is described. Sites carrying different properties are given different families.

julia
asm = cubic_lattice(:sc, Dict(:C => C_m), Dict(:C => C_i); fraction = 0.3)
homogenize(asm, ClusterModel(), :C)
MeanFieldHomogenization.Assemblies.random_assembly Function
julia
random_assembly(n, matrix_properties, particle_properties;
                fraction = nothing, radius = nothing, period = 1.0,
                rng = Random.default_rng(), cycles = 20_000,
                boundary = nothing, dim = 3, T = Float64)
    -> ParticleAssembly

Build a ParticleAssembly of n equal, non-overlapping spheres (dim = 3) or disks (dim = 2) by the hard-particle Metropolis algorithm used by [2], §5.

The particles start on a regular lattice and are then shuffled by cycles sweeps of trial moves, the move amplitude being re-tuned every 50 sweeps to hold the acceptance ratio near 0.3 — the recipe of the paper. Overlap is tested in the periodic metric, so the resulting microstructure tiles space whatever boundary treatment is then applied.

Pass rng explicitly for reproducibility; the default boundary is a PeriodicBox of the given period, and boundary = MixedBC(...) selects Brisard's ellipsoidal SVE instead.

MeanFieldHomogenization.Assemblies.max_packing_fraction Function
julia
max_packing_fraction(kind::Symbol) -> Float64

Largest volume fraction of equal, non-overlapping spheres on the cubic lattice kind (:sc, :bcc or :fcc) — the point at which neighboring spheres touch: π/6 ≈ 0.5236, √3π/8 ≈ 0.6802 and √2π/6 ≈ 0.7405.

Worth knowing when reading Molinari & El Mouden's figures: their simple-cubic curves stop near f = 0.52 for exactly this reason.

The N-body schemes

MeanFieldHomogenization.Schemes.ClusterModel Type
julia
ClusterModel(; cluster_radius = nothing, kwargs...) <: HomogenizationScheme

Cluster model of [1]: an N-body scheme in which the mean strain of every inclusion is solved for, accounting for the pairwise interaction with every neighbor inside a cluster of radius R_c, on top of the interaction with the matrix.

Acts on a ParticleAssembly, not on an RVE. Writing   , the localization tensors of the families solve

with the sum of the pairwise interaction tensors (interaction_tensor) over the cluster. cluster_radius overrides the cutoff carried by the assembly's PeriodicBox.

Reducing the cluster to a single inclusion (cluster_radius = 0) makes every vanish and the scheme degenerates exactly onto MoriTanaka — the identity proved in Appendix C of the paper, and the sharpest available check on an implementation.

MeanFieldHomogenization.Schemes.EquivalentInclusion Type
julia
EquivalentInclusion(; order = 0, kwargs...) <: HomogenizationScheme

Equivalent inclusion method in the variational (Galerkin) form of [2] — a Galerkin discretization of the weak form of the Lippmann-Schwinger equation, with the polarization taken piecewise constant over each inclusion at order = 0.

Acts on a ParticleAssembly. The polarizations solve

and the apparent stiffness follows from     . The term in , the Hill tensor of the SVE domain itself, is what implements the mixed boundary conditions of the paper — with MixedBC no periodization and no conditionally convergent lattice sum are needed.

Because the method minimizes a Hashin-Shtrikman functional over a finite-dimensional space, the estimate is a rigorous bound on the apparent stiffness whenever the matrix is stiffer (upper bound) or softer (lower bound) than every inhomogeneity — see eim_bound_type.

Brisard et al. note in their §3.1 that at order = 0 their influence pseudotensors coincide with the interaction tensors of [63] and [1]; the two schemes of this package accordingly share interaction_tensor and agree on a periodic assembly with the same cutoff.

MeanFieldHomogenization.Assemblies.eim_bound_type Function
julia
eim_bound_type(asm, prop = :C) -> Symbol

Whether the EquivalentInclusion estimate of property prop is a rigorous bound on the apparent stiffness of the assembly, and which one:

  • :upper — the matrix is stiffer than every inhomogeneity;

  • :lower — the matrix is softer than every inhomogeneity;

  • :none — the contrasts have mixed signs, and the estimate is only an estimate.

This is the extremum property of [2], §3.2, inherited from the Hashin-Shtrikman variational principle. It also implies that the estimate improves monotonically with the polarization order.

Definiteness is tested on the Kelvin-Mandel matrix of the contrast  , which is the exact statement of   in the sense of quadratic forms.

MeanFieldHomogenization.Assemblies.eim_polarizations Function
julia
eim_polarizations(asm, prop = :C; kw...) -> (Vector, Vector{Symbol})

Per-particle polarization operators of the EquivalentInclusion solution, together with the particle names, without going through homogenize.

Local fields follow directly: the strain operator of particle a is    and its stress operator is   .

MeanFieldHomogenization.Assemblies.cluster_localizations Function
julia
cluster_localizations(asm, prop = :C; cluster_radius = nothing, kw...)
    -> (Vector, Vector{Symbol})

Per-family localization tensors of the ClusterModel solution, together with the representative particle of each family.

A[k] maps the macroscopic strain onto the mean strain of family k, so the mean stress follows as   .

Parameter lenses

MeanFieldHomogenization.Assemblies.CenterParameter Type
julia
CenterParameter(name::Symbol, component::Int) <: AbstractParameter

Lens onto one Cartesian component of the center of particle name — the microstructural degree of freedom that no other cell of the package has.

julia
derivative(asm, ClusterModel(), center_param(:p2, 3); indexer = C -> get_array(C)[1,1,1,1])
MeanFieldHomogenization.Assemblies.RadiusParameter Type
julia
RadiusParameter(name::Symbol, axis::Int) <: AbstractParameter

Lens onto one semi-axis of the geometry of particle name. For a sphere every axis is the radius, and setting one sets all of them — otherwise the geometry would silently stop being a sphere and change its shape class mid-derivative.

MeanFieldHomogenization.Assemblies.center_param Function
julia
center_param(name, component) -> CenterParameter

Convenience constructor for CenterParameter.

MeanFieldHomogenization.Assemblies.radius_param Function
julia
radius_param(name, axis = 1) -> RadiusParameter

Convenience constructor for RadiusParameter.