tengfeiluo's picture
Upload folder using huggingface_hub
01a0b26 verified
"""Core-shell equivalent inclusion models.
Replaces a coated sphere (or multi-layer concentric sphere) with a single
homogeneous sphere having the same far-field response. The returned
equivalent property P_equiv can then be used as the filler property P_f in
any EMT formula (Maxwell-Garnett, Bruggeman, Mori-Tanaka, etc.).
Models implemented
------------------
hashin_csa — Single coated sphere (Hashin composite sphere assembly).
multilayer_recursive — Multi-layer sphere by recursive Hashin CSA (Hervé 2002).
References
----------
Hashin, Z. (1962).
The elastic moduli of heterogeneous materials.
*J. Appl. Mech.*, 29(1), 143–150.
Nan, C.-W. et al. (1997).
Effective thermal conductivity of particulate composites with interfacial
thermal resistance. *J. Appl. Phys.*, 81(10), 6692.
Hervé, E. (2002).
Thermal and thermoelastic behaviour of multiply coated
inclusion-reinforced composites.
*Int. J. Solids Struct.*, 39(4), 1041–1058.
"""
from __future__ import annotations
from typing import Sequence
import numpy as np
__all__ = ["hashin_csa", "multilayer_recursive"]
def hashin_csa(
P_core: float,
P_shell: float,
f_core: float,
) -> float:
"""Equivalent property of a single coated sphere (Hashin CSA).
Computes the equivalent homogeneous property of a concentric two-phase
sphere (core + shell) by matching the exact potential boundary-value
solution—the Hashin composite sphere assembly (CSA). The result can be
substituted as the filler property into any two-phase EMT formula.
Parameters
----------
P_core : float
Property of the inner core (e.g. W/(m·K) for thermal conductivity).
P_shell : float
Property of the outer shell (same units as P_core).
f_core : float
Volume fraction of the core, ``f_core = (r_core / r_shell)³``.
Must satisfy 0 ≤ f_core ≤ 1.
Returns
-------
P_equiv : float
Equivalent homogeneous property of the coated sphere.
Raises
------
ValueError
If *f_core* is outside [0, 1].
Notes
-----
From the model catalog (Part VI) and Nan et al. (1997):
.. math::
P_{\\text{equiv}} = P_{\\text{shell}}\\,
\\frac{2P_{\\text{shell}} + P_{\\text{core}}
- 2f(P_{\\text{shell}} - P_{\\text{core}})}
{2P_{\\text{shell}} + P_{\\text{core}}
+ f(P_{\\text{shell}} - P_{\\text{core}})}
where :math:`f = (r_{\\text{core}}/r_{\\text{shell}})^3`.
**Limits:**
- :math:`f \\to 0` (vanishing core): :math:`P_{\\text{equiv}} \\to P_{\\text{shell}}`.
- :math:`f \\to 1` (vanishing shell): :math:`P_{\\text{equiv}} \\to P_{\\text{core}}`.
- :math:`P_{\\text{core}} = P_{\\text{shell}}`: :math:`P_{\\text{equiv}} = P_{\\text{shell}}`.
References
----------
Hashin, Z. (1962). *J. Appl. Mech.*, 29(1), 143.
Catalog: Part VI, "Interphase and core-shell equivalent inclusion models".
Examples
--------
>>> hashin_csa(5.0, 5.0, 0.5) # no contrast → shell value
5.0
>>> hashin_csa(10.0, 1.0, 0.0) # f=0 → shell value
1.0
>>> hashin_csa(10.0, 1.0, 1.0) # f=1 → core value
10.0
>>> hashin_csa(1.0, 10.0, 0.125) # r_core/r_shell = 0.5
"""
f = float(f_core)
if not (0.0 <= f <= 1.0):
raise ValueError(
f"f_core must be in [0, 1], got {f}."
)
P_c = float(P_core)
P_s = float(P_shell)
num = 2.0 * P_s + P_c - 2.0 * f * (P_s - P_c)
den = 2.0 * P_s + P_c + f * (P_s - P_c)
return P_s * num / den
def multilayer_recursive(
layers: Sequence[tuple[float, float]],
) -> float:
"""Equivalent property of a multi-layer sphere by recursive Hashin CSA.
Starting from the innermost core, applies the Hashin CSA formula
iteratively outward, following the Hervé & Zaoui (1993) / Hervé (2002)
scheme. Each iteration wraps the current equivalent sphere with the
next shell.
Parameters
----------
layers : sequence of (P, r) tuples
Each tuple ``(property, outer_radius)`` describes one concentric
layer, listed from the **innermost** core to the **outermost** shell.
At least two entries are required (core + one shell).
Radii must be strictly increasing.
Returns
-------
P_equiv : float
Equivalent homogeneous property of the full multi-layer sphere.
Raises
------
ValueError
If fewer than 2 layers are provided, or if radii are not strictly
increasing.
Notes
-----
The recursion (Hervé, 2002) is:
.. math::
P^{(i+1)}_{\\text{equiv}} =
\\operatorname{hashin\\_csa}\\!\\left(
P^{(i)}_{\\text{equiv}},\\;
P^{(i+1)},\\;
\\left(\\frac{r_i}{r_{i+1}}\\right)^{\\!3}
\\right)
initialised with :math:`P^{(0)}_{\\text{equiv}} = P_{\\text{core}}`.
References
----------
Hervé, E. (2002). *Int. J. Solids Struct.*, 39(4), 1041.
Examples
--------
>>> multilayer_recursive([(5.0, 1e-9), (5.0, 2e-9)]) # uniform → 5.0
5.0
>>> # Two-layer: equivalent to hashin_csa(10.0, 1.0, 0.125)
>>> multilayer_recursive([(10.0, 50e-9), (1.0, 100e-9)])
"""
layers = list(layers)
if len(layers) < 2:
raise ValueError(
"At least 2 layers (core + one shell) are required; "
f"got {len(layers)}."
)
# Validate strictly increasing radii
radii = [r for _, r in layers]
for i in range(len(radii) - 1):
if radii[i + 1] <= radii[i]:
raise ValueError(
f"Radii must be strictly increasing; layer {i} has r={radii[i]}, "
f"layer {i+1} has r={radii[i+1]}."
)
# Start with core
P_equiv = float(layers[0][0])
r_inner = float(layers[0][1])
# Wrap with each successive shell
for P_shell, r_outer in layers[1:]:
P_shell = float(P_shell)
r_outer = float(r_outer)
f_core = (r_inner / r_outer) ** 3
P_equiv = hashin_csa(P_equiv, P_shell, f_core)
r_inner = r_outer
return P_equiv