- Categories
- Ellipsoid
- Displaced core-shell ellipsoids
- core_shell_displ_core.py
Displaced core-shell ellipsoids - core_shell_displ_core.py
r"""
Scattering model for displaced core-shell ellipsoids with polydispersity.
**Description**
This model calculates the scattering intensity from core-shell ellipsoids where
the core centre is displaced relative to the shell centre. The model accounts for:
- Size polydispersity (Gaussian distribution of particle radius, 50-point quadrature)
- Orientation averaging (50-point angular quadrature)
- Hard-sphere structure factor (Percus-Yevick closure)
- Debye (Gaussian chain) background contribution from free polymer
**Model Geometry**
The core is an ellipsoid with equatorial semi-axis *R* and aspect ratio *eps*
(semi-axes *R*, *R*, *R eps*). The shell is a coaxial ellipsoid whose
equatorial outer radius is *R + d_shell*, where
.. math::
d_\text{shell} = |d| + 2\,|\sigma_\text{out}|
with *d* = ``thickness_shell`` and :math:`\sigma_\text{out}` =
``sigma_outer``. The core centre is offset by ``displacement`` in the
direction perpendicular to the symmetry axis.
**Mathematical Basis**
The scattering intensity returned by the kernel (before SASView applies the
global ``scale`` and ``background``) is:
.. math::
I(q) = \bigl[ P(q) + \langle F(q)\rangle^2\,(S(q)-1) \bigr]\,B(q)
+ I_\text{poly}(q)
where
.. math::
P(q) = \frac{\langle F^2(q)\rangle}{F_0^2}, \qquad
B(q) = 1 + A_{10}\!\left(\frac{q_0}{q}\right)^{\!m},
\qquad m = |A_{11}|+2, \quad q_0 = 0.001\,\text{Ang}^{-1}
- :math:`P(q)` — size- and orientation-averaged normalised form factor
- :math:`\langle F(q)\rangle/F_{\theta}` — mean reduced amplitude (used with S(q))
- :math:`S(q)` — Percus-Yevick hard-sphere structure factor
- :math:`B(q)` — empirical power-law low-*q* correction
- :math:`I_\text{poly}(q)` — Debye scattering from Gaussian polymer chains
The global intensity is then:
.. math::
I_\text{total}(q) = \text{scale}\cdot I(q) + \text{background}
**Parameter Definitions**
``scale`` and ``background``
Added automatically by SASView. ``scale`` is an overall multiplicative
factor (units of the desired absolute intensity scale). ``background``
is a flat incoherent baseline in cm\ :sup:`-1`.
``radius`` (*R*, Ang)
Mean equatorial semi-axis of the core ellipsoid, i.e. the half-length
along the two axes perpendicular to the symmetry axis. This is the
centre of the Gaussian size distribution. Typical values: 5–200 Ang.
``aspect_ratio`` (*eps* = c/a, dimensionless)
Ratio of the polar semi-axis to the equatorial semi-axis of the core.
- eps = 1 -> sphere
- eps > 1 -> prolate (cigar-shaped)
- eps < 1 -> oblate (disc-shaped)
The outer shell is constructed so that it has the same equatorial
thickness *d_shell* everywhere: the shell's own aspect ratio is
*(R·eps + d_shell) / (R + d_shell)*, which differs from eps unless
d_shell = 0.
``volfraction_hs`` (*eta*, dimensionless)
Volume fraction of particles used in the Percus-Yevick hard-sphere
structure factor *S(q)*. Set to 0 to suppress inter-particle
interactions (i.e. *S(q)* = 1). Physical upper limit for random
close packing is ~ 0.64.
``radius_hs`` (*R*\ :sub:`HS`, Ang)
Effective radius of the hard-sphere potential in the Percus-Yevick
calculation. This is the centre-to-centre distance at contact and
need not equal the geometric particle radius; it is often larger to
account for a hydration layer, electrostatic repulsion, or a polymer
brush. Only meaningful when ``volfraction_hs`` > 0.
``thickness_shell`` (*d*, Ang)
Equatorial thickness of the shell layer. The quantity actually used
in the geometry is the effective shell extent
.. math:: d_\text{shell} = |d| + 2\,|\sigma_\text{out}|
so the outer radius of the ellipsoid is *R + d_shell*. Note that
``sigma_outer`` also contributes to the shell extent (see below).
``contrast_shell`` (*A*\ :sub:`8`, dimensionless)
Ratio of the shell SLD contrast to the core SLD contrast,
:math:`\Delta\rho_\text{shell}/\Delta\rho_\text{core}`, where each
:math:`\Delta\rho` is measured relative to the solvent. The core
form factor amplitude is weighted by (1 − contrast_shell):
.. math::
F(q) = V_\text{out}\,\phi(q\,r_\text{out})
- V_\text{core}\,(1 - A_8)\,\phi(q\,r_\text{core})
Limiting cases:
- A\ :sub:`8` = 0 — the shell is invisible (delta rho\ :sub:`shell` = 0);
the particle appears as a hollow ellipsoid.
- A\ :sub:`8` = 1 — core and shell have equal contrast; the particle
looks uniform (solid ellipsoid, no internal interface visible).
- A\ :sub:`8` < 0 — shell and core scatter with opposite sign (e.g.
a lipid membrane in D\ :sub:`2`\ O where the hydrocarbon core has
negative contrast and the head-group shell has positive contrast).
``sigma_rel`` (*sigma*\ :sub:`R`/R, dimensionless)
Relative standard deviation of the Gaussian size distribution of the
core radius: :math:`\sigma_R = \sigma_\text{rel}\cdot R`. The
distribution is sampled symmetrically over 3 sigma\ :sub:`R` using 50
Gauss points. Example: ``sigma_rel`` = 0.05 means 5 percent polydispersity.
Set to 0 for a monodisperse sample (the kernel uses a minimum width of
10\ :sup:`-4`*R to avoid division by zero).
``power_law`` (*A*\ :sub:`10`, dimensionless)
Amplitude of the empirical low-*q* power-law correction
.. math:: B(q) = 1 + A_{10}\!\left(\frac{q_0}{q}\right)^{\!m}
with *q*\ :sub:`0` = 0.001 Ang\ :sup:`-1` (fixed reference wavevector)
and *m* = |``exponent_2``| + 2. This term accounts for scattering
from large-scale structures (e.g. fractal aggregates or density
fluctuations) that dominate at very low *q*. Set to 0 to disable.
``exponent_2`` (*A*\ :sub:`11`, dimensionless)
Controls the exponent of the power-law correction through
*m* = |A\ :sub:`11`| + 2. The absolute value ensures *m* >= 2,
which enforces a Porod-like decay at high *q* and prevents the
correction from diverging. Larger values of |A\ :sub:`11`| confine
the correction to a narrower low-*q* range.
``sigma_outer`` (*sigma*\ :sub:`out`, Ang)
Debye–Waller (Gaussian) roughness of the outer shell surface. The
outer form factor amplitude is multiplied by
:math:`\exp(-\tfrac{1}{2}(q\,\sigma_\text{out})^2)`, smearing the
outer interface. *sigma*\ :sub:`out` also adds 2 sigma\ :sub:`out` to the
effective shell thickness *d_shell*. Set to 0 for a perfectly sharp
outer surface.
``rg_polymer`` (*R*\ :sub:`g`, Ang)
Radius of gyration of free Gaussian polymer chains in solution.
Enters the Debye scattering function
.. math::
P_\text{Debye}(u) = \frac{2(\mathrm{e}^{-u}-1+u)}{u^2},
\quad u = (q\,R_g)^2
Only used when ``scale_polymer`` nonequal to 0.
``scale_polymer`` (*A*\ :sub:`14`, cm\ :sup:`-1`)
Amplitude (zero-*q* intensity) of the Debye polymer contribution:
:math:`I_\text{poly}(q) = A_{14}\,P_\text{Debye}(q)`.
Set to 0 to disable. Note that this term is *not* multiplied by the
global ``scale``, so it represents an absolute polymer contribution
independent of the particle scattering amplitude.
``displacement`` (*delta*, Ang)
Distance by which the core centre is displaced from the shell centre,
in the direction *perpendicular* to the ellipsoid symmetry axis.
The displacement introduces an asymmetric contrast profile, generating
a phase factor :math:`\cos(q\,\delta\,\sin\theta)` in the form factor
(where *theta* is the angle between *q* and the symmetry axis). This
modulates the form factor oscillations and can model, for example, an
off-centre protein domain inside a lipid vesicle.
If *delta* exceeds *d_shell* the value is reflected back: effectively
*delta* is clamped to [0, *d_shell*]. Set to 0 for a concentric
core-shell particle.
``sigma_core`` (*sigma*\ :sub:`core`, Ang)
Debye–Waller (Gaussian) roughness of the core–shell interface. The
core amplitude is multiplied by
:math:`\exp(-\tfrac{1}{2}(q\,\sigma_\text{core})^2)`, smearing the
inner interface. Analogous to ``sigma_outer`` but applied at the
inner surface. Set to 0 for a sharp core–shell boundary.
**Notes on the Fortran Reference**
* The Fortran source had a bug in the amplitude accumulator: ``FFF =
SUM1*STEP`` was used instead of ``SUM1X*STEP``, which caused the
structure-factor correction term :math:`\langle F\rangle^2(S-1)` to
vanish silently. This has been corrected.
* The Fortran normalisation denominator used the angle-dependent ``RAO``
(last integration point) instead of the angle-independent ``RO``; this
has been corrected.
**References**
- Spinozzi et al., *Biophys. J.* (2002)
- Orthaber et al., *J. Appl. Cryst.* 33, 218–225 (2000)
"""
from numpy import inf
name = "core_shell_displ_core"
title = "Displaced Core-Shell Ellipsoid with Polydispersity"
category = "shape:ellipsoid"
description = """
Scattering from polydisperse core-shell ellipsoids with a displaced core.
Includes a Percus-Yevick hard-sphere S(q) and a Debye polymer background.
"""
# Model parameters — 'scale' and 'background' are added automatically by SASView.
# Parameter order must match the Iq() argument order in the C kernel exactly.
parameters = [
# name units default [lo, hi] type description
["radius", "Ang", 30.8, [0, inf], "volume",
"Mean equatorial semi-axis of the core ellipsoid"],
["aspect_ratio", "", 1.316, [0, inf], "volume",
"Core polar/equatorial semi-axis ratio eps=c/a (>1 prolate, <1 oblate, =1 sphere)"],
["volfraction_hs", "", 0.0, [0, 0.74], "",
"Hard-sphere volume fraction eta for Percus-Yevick S(q); 0 = no interactions"],
["radius_hs", "Ang", 100.0, [0, inf], "",
"Hard-sphere interaction radius (centre-to-centre at contact); active only when volfraction_hs > 0"],
["thickness_shell","Ang", 11.19, [0, inf], "volume",
"Equatorial shell thickness d; effective shell extent = d + 2*sigma_outer"],
["contrast_shell", "", -0.304, [-inf, inf], "",
"SLD contrast ratio Delta_rho_shell / Delta_rho_core; 0=hollow shell, 1=uniform particle"],
["sigma_rel", "", 0.0205, [0, inf], "",
"Relative polydispersity sigma_R/R of the Gaussian size distribution; 0 = monodisperse"],
["power_law", "", 8.70, [-inf, inf], "",
"Amplitude A10 of low-q power-law correction B(q)=1+A10*(0.001/q)^m; 0 = disabled"],
["exponent_2", "", 0.0748,[-inf, inf], "",
"Exponent parameter A11; actual power-law exponent m = |A11| + 2"],
["sigma_outer", "Ang", 0.0, [0, inf], "",
"Debye-Waller roughness sigma of the outer shell surface; 0 = sharp interface"],
["rg_polymer", "Ang", 10.0, [0, inf], "",
"Radius of gyration of free polymer chains (Debye scattering function)"],
["scale_polymer", "", 0.01726,[-inf,inf], "",
"Zero-q intensity of polymer Debye contribution I_poly(q); 0 = disabled"],
["displacement", "Ang", 7.457, [-inf, inf], "",
"Core-centre offset perpendicular to symmetry axis; 0 = concentric core-shell"],
["sigma_core", "Ang", 0.0, [0, inf], "",
"Debye-Waller roughness sigma of the core-shell interface; 0 = sharp interface"],
]
source = ["lib/sas_3j1x_x.c", "core_shell_displ_core.c"]
effective_radius_type = [
"outer equatorial radius",
"core equatorial radius",
]
def form_volume(radius, aspect_ratio, thickness_shell):
import numpy as np
r_outer = radius + thickness_shell
eps_outer = (radius*aspect_ratio + thickness_shell) / r_outer
return 4.0*np.pi/3.0 * r_outer**3 * eps_outer
def radius_effective(mode, radius, aspect_ratio, thickness_shell):
if mode == 1:
return radius + thickness_shell
else:
return radius
def random():
import numpy as np
radius = 10**np.random.uniform(1, 3)
aspect_ratio = np.random.uniform(0.5, 2.0)
thickness_shell= np.random.uniform(0.05, 0.5)*radius
volfraction_hs = np.random.uniform(0, 0.35)
radius_hs = np.random.uniform(0.8, 2.0)*radius
contrast_shell = np.random.uniform(-1, 1)
sigma_rel = 10**np.random.uniform(-2, -0.3)
power_law = np.random.uniform(0, 15)
exponent_2 = np.random.uniform(0, 1)
sigma_outer = np.random.uniform(0, 2)
rg_polymer = 10**np.random.uniform(0, 2)
scale_polymer = 10**np.random.uniform(-4, -1)
displacement = np.random.uniform(0, 0.8*thickness_shell)
sigma_core = np.random.uniform(0, 2)
return dict(
radius=radius, aspect_ratio=aspect_ratio,
volfraction_hs=volfraction_hs, radius_hs=radius_hs,
thickness_shell=thickness_shell, contrast_shell=contrast_shell,
sigma_rel=sigma_rel, power_law=power_law, exponent_2=exponent_2,
sigma_outer=sigma_outer, rg_polymer=rg_polymer,
scale_polymer=scale_polymer, displacement=displacement,
sigma_core=sigma_core,
)
# Reference values computed from the Python reimplementation of Iq()
# with scale=1, background=0 (SASView adds background separately).
# Default parameters: radius=30.8, aspect_ratio=1.316, volfraction_hs=0,
# radius_hs=100, thickness_shell=11.19, contrast_shell=-0.304,
# sigma_rel=0.0205, power_law=8.70, exponent_2=0.0748, sigma_outer=0,
# rg_polymer=10, scale_polymer=0.01726, displacement=7.457, sigma_core=0.
_default = {
'scale': 1.0, 'background': 0.0,
'radius': 30.8, 'aspect_ratio': 1.316,
'volfraction_hs': 0.0, 'radius_hs': 100.0,
'thickness_shell': 11.19, 'contrast_shell': -0.304,
'sigma_rel': 0.0205, 'power_law': 8.70, 'exponent_2': 0.0748,
'sigma_outer': 0.0, 'rg_polymer': 10.0, 'scale_polymer': 0.01726,
'displacement': 7.457, 'sigma_core': 0.0,
}
tests = [
# [parameters, q, expected_I]
[_default, 0.01, 1.029576e+00],
[_default, 0.05, 2.025142e-01],
[_default, 0.10, 9.031598e-02],
[_default, 0.20, 2.221160e-02],
# With hard-sphere structure factor
[dict(_default, volfraction_hs=0.2, radius_hs=50.0), 0.05, 2.037908e-01],
[dict(_default, volfraction_hs=0.2, radius_hs=50.0), 0.10, 8.549888e-02],
]
Back to Model
Download