Core-Shell Sphere¶
A core-shell sphere consists of a solid core with one SLD surrounded by a concentric shell with a different SLD, all embedded in a matrix. This is a direct extension of the solid sphere model — the key change is in how the amplitude is computed.
Why amplitudes, not intensities¶
Before writing any code, there is a conceptual point that must be clear.
Key Concept: Adding Amplitudes, Then Squaring
When combining scattering from multiple regions, you must sum the amplitudes first and then square the result to get the intensity. You cannot add intensities directly.
This matters because amplitudes can be positive or negative — they carry phase information about whether scattered waves reinforce or cancel each other. If you added intensities instead, you would always get more scattering as you add more material, which is physically wrong. Shells with the right SLD can reduce the total scattering by partially cancelling the core contribution.
In Section 2 we defined the normalized form factor as the square of the amplitude:
For the core-shell model we need to work with the unsquared amplitude \(F(q, R)\) so we can combine contributions from the core and shell before squaring.
The core-shell amplitude¶
A core-shell sphere has three regions: core (radius \(R_c\), SLD \(\rho_c\)), shell (outer radius \(R_s = R_c + t\), SLD \(\rho_s\)), and matrix (SLD \(\rho_m\)). The total scattering amplitude is:
where \(V = \frac{4}{3}\pi R^3\) and \(F(q, R)\) is the unnormalized sphere amplitude.
The structure of this expression has a clear physical reading: each term is the contribution of a uniform sphere at that radius, weighted by the contrast step at its boundary. The first term describes what the core looks like relative to the shell material. The second describes what the entire particle looks like relative to the matrix.
The normalized form factor is:
where \(F_{\text{cs}}(0) = (\rho_c - \rho_s)V_c + (\rho_s - \rho_m)V_s\) is the zero-\(q\) limit (obtained by substituting \(F(q,R) = 1\)).
Implementation¶
Create chapter_04_shells.ipynb and paste in the helper functions from Section 2.
Then add the following new cells.
First, extract the unsquared amplitude from the Section 2 function:
import numpy as np
def sphere_amplitude(q, R):
"""
Unsquared scattering amplitude F(q, R) for a uniform sphere.
Parameters
----------
q : array-like
Scattering vector in Å^-1.
R : float
Sphere radius in Å.
Returns
-------
numpy.ndarray
Amplitude, normalized to F(q -> 0) = 1.
"""
qR = q * R
with np.errstate(invalid="ignore", divide="ignore"):
F = np.where(
qR < 1e-10,
1.0,
3.0 * (np.sin(qR) - qR * np.cos(qR)) / qR**3
)
return F
Note that sphere_form_factor from Section 2 is just sphere_amplitude(q, R)**2.
Now add the core-shell function:
def core_shell_form_factor(q, R_core, t_shell, rho_core, rho_shell, rho_matrix):
"""
Normalized form factor P(q) for a core-shell sphere.
Parameters
----------
q : array-like
Scattering vector in Å^-1.
R_core : float
Core radius in Å.
t_shell : float
Shell thickness in Å.
rho_core : float
Core SLD in Å^-2.
rho_shell : float
Shell SLD in Å^-2.
rho_matrix : float
Matrix SLD in Å^-2.
Returns
-------
numpy.ndarray
P(q), normalized to 1 at q -> 0.
"""
R_total = R_core + t_shell
V_core = (4/3) * np.pi * R_core**3
V_total = (4/3) * np.pi * R_total**3
# Sum amplitudes with contrast-weighted volumes
F = ((rho_core - rho_shell) * V_core * sphere_amplitude(q, R_core) +
(rho_shell - rho_matrix) * V_total * sphere_amplitude(q, R_total))
# Zero-q normalization (sphere_amplitude -> 1 as q -> 0)
F0 = ((rho_core - rho_shell) * V_core +
(rho_shell - rho_matrix) * V_total)
return (F / F0)**2
Exploring the core-shell model¶
Generate a \(q\) array and compare the core-shell form factor against the plain sphere:
import matplotlib.pyplot as plt
q = np.logspace(-3, 0, 500)
# Baseline: solid sphere with same outer radius
R_core = 40.0 # Å
t_shell = 15.0 # Å — shell thickness
R_total = R_core + t_shell
rho_core = 10.0e-6 # Å^-2
rho_shell = 14.0e-6 # Å^-2
rho_matrix = 9.47e-6 # water
P_sphere = sphere_amplitude(q, R_total)**2
P_core_shell = core_shell_form_factor(q, R_core, t_shell,
rho_core, rho_shell, rho_matrix)
fig, ax = plt.subplots(figsize=(8, 5))
plot_form_factor(q, P_sphere, label=f"Solid sphere R = {R_total} Å", ax=ax, color="steelblue")
plot_form_factor(q, P_core_shell, label=f"Core-shell (core {R_core} Å + shell {t_shell} Å)", ax=ax, color="tomato")
ax.set_title("Core-shell vs solid sphere")
plt.tight_layout()
plt.show()
The core-shell curve has the same low-\(q\) plateau but different oscillation positions and depths compared to the solid sphere. The shell introduces a second length scale into the problem — features from both \(R_c\) and \(R_s\) are present in the curve.
Try It Yourself
Using the parameters above as a starting point:
- Set
rho_shell = rho_core. What does the form factor look like? Does this make physical sense? - Set
rho_shell = rho_matrix. What does the form factor look like now? Which part of the particle is effectively invisible? - Set
rho_shellto a value betweenrho_coreandrho_matrix. How does the depth of the oscillations change compared to the extremes above?
Solution
Part 1: When rho_shell = rho_core, the contrast step at the core-shell
boundary disappears: \(\rho_c - \rho_s = 0\). The first term in the amplitude
vanishes and only the second term remains — which is identical to a solid sphere
of radius \(R_{\text{total}}\). The core-shell model reduces exactly to the solid
sphere, as expected.
Part 2: When rho_shell = rho_matrix, the contrast step at the outer
surface disappears: \(\rho_s - \rho_m = 0\). The second term vanishes and only the
core contribution remains — equivalent to a solid sphere of radius \(R_c\) with
\(\Delta\rho = \rho_c - \rho_m\). The shell is invisible because it matches the
surrounding medium.
Part 3: Intermediate SLD values produce intermediate oscillation depths. The destructive interference between the two amplitude terms is partial rather than complete.
Git checkpoint
What's next: Multiple Shells — generalizing the model to any number of concentric layers.