Core double shell sphere filled with many cylinders in the core - coredoubleshellspherefilledwithmanycylinders.py
# Author:
# Martin Schmiele
# Niels-Bohr-Institutet
# Koebenhavns Universitet
# martin.schmiele@nbi.ku.dk
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
#
#
# // (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
# // (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
# // (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
# // (((((((((((((((((((((((((((((((((+++++++++++++(((((((((((((((((((((((((((((((((
# // (((((((((((((((((((((((((((((++%%%%%%%%%%%%%%%%%++(((((((((((((((((((((((((((((
# // ((((((((((((((((((((((((++%%%%%%%%%%%%%%%%%%%%%%%%%%%++((((((((((((((((((((((((
# // ((((((((((((((((((((++%%%%%%%%%%...............%%%%%%%%%%++((((((((((((((((((((
# // (((((((((((((((((++%%%%%%%%...........%%%...........%%%%%%%%++(((((((((((((((((
# // (((((((((((((((++%%%%%%..............%%%%%..............%%%%%%++(((((((((((((((
# // (((((((((((((++%%%%%%...............%%%%%.................%%%%%%++(((((((((((((
# // ((((((((((((++%%%%%.%%%%%.........%%%%%%....................%%%%%++((((((((((((
# // ((((((((((++%%%%%...%%%%%%%%%%%..%%%%%%.......................%%%%%++((((((((((
# // (((((((((++%%%%%...%%%%%%%%%%%%%%%%%%%.........................%%%%%++(((((((((
# // ((((((((++%%%%%......%%%%%%%%%%%%%%%%%%%%%......................%%%%%++((((((((
# // (((((((++%%%%%.............%%%%%%%%%%%%%%%%%%%%..................%%%%%++(((((((
# // (((((((++%%%%................%%%%%%%%%%%%%%%%%%%%%%%%.............%%%%++(((((((
# // ((((((++%%%%................%%%%%.....%%%%%%%%%%%%%%%%%%%%.........%%%%++((((((
# // ((((((++%%%%..............%%%%%%....%%%%...%%%%%%%%%%%%%%%%%%%%%...%%%%++((((((
# // ((((((++%%%%.............%%%%%%.....%%%%%%%%%....%%%%%%%%%%%%%%%%%%%%%%++((((((
# // (((((++%%%%.............%%%%%......%%%%%%%%%%%%%%%%...%%%%%%%%%%%%..%%%%++(((((
# // (((((++%%%%............%%%%%......%%%%%%%%%%%%%%%%..........%%%%%...%%%%++(((((
# // ((((((++%%%%..........%%%%%......%%%%%%%%%%%%%%%%%.................%%%%++((((((
# // ((((((++%%%%.........%%%%%.......%%%%%%%%%%%%%%%%..................%%%%++((((((
# // ((((((++%%%%..........%%%.......%%%%%%%%%%%%%%%%...................%%%%++((((((
# // (((((((++%%%%..................%%%%%%%%%%%%%%%%...................%%%%++(((((((
# // (((((((++%%%%%.................%%%%%%%%%%%%%%%%..................%%%%%++(((((((
# // ((((((((++%%%%%...............%%%%%%%%%%%%%%%%..................%%%%%++((((((((
# // (((((((((++%%%%%.............%%%%%%%%%%%%%%%%..................%%%%%++(((((((((
# // ((((((((((++%%%%%...........%%%%%%%%%%%%%%%%..................%%%%%++((((((((((
# // ((((((((((((++%%%%%.........%%%%%%%%%%%%%%%%................%%%%%++((((((((((((
# // (((((((((((((++%%%%%%......%%%%%%%%%%%%%%%%...............%%%%%%++(((((((((((((
# // (((((((((((((((++%%%%%%...%%%%%%%%%%%%%%%%..............%%%%%%++(((((((((((((((
# // (((((((((((((((((++%%%%%%%%.....%%%%%%%%%%..........%%%%%%%%++(((((((((((((((((
# // ((((((((((((((((((((++%%%%%%%%%%.....%%%%......%%%%%%%%%%++((((((((((((((((((((
# // ((((((((((((((((((((((((++%%%%%%%%%%%%%%%%%%%%%%%%%%%++((((((((((((((((((((((((
# // (((((((((((((((((((((((((((((++%%%%%%%%%%%%%%%%%++(((((((((((((((((((((((((((((
# // (((((((((((((((((((((((((((((((((+++++++++++++(((((((((((((((((((((((((((((((((
# // (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
# // (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
r"""
Definition
----------
Parameters:
scale = scaling factor, volume fraction of particles scale phi ~ N V_{sph} / V_{irr}, with N / V_{irr} being the number density of particles in the irradiated volume
phi_{cyl} = relative volume fraction of cylinders inside the core sphere phi_{cyl} ~ N V_{cyl} / V_{sph,c}, with N / V_{sph,c} being the number density of cylinders in the core sphere
background = const. background
R_{sph,c} = core radius of sphere
d_{sph,sh} = inner shell thickness of sphere
d_{sph,sh2} = outer shell thickness of sphere
NB: R_{sph,c} + d_{sph,sh} = radius of whole sphere
R_{cyl} = radius of one cylinder
L_{cyl} = length of one cylinder
R_{avgsph,cyl} = radius of the averaging sphere for the cylinders
V_{sph} = volume of whole sphere including core and both shells
V_{sph,i} = volume of sphere including core and inner shell
V_{sph,c} = volume of sphere core
V_{cyl} = volume of cylinder
V_{avgsph,cyl} = volume of the averaging sphere for the cylinders
sld_{sph,c} = scattering length density of core of sphere
sld_{sph,sh} = scattering length density of inner shell of sphere
sld_{sph,sh2} = scattering length density of outer shell of sphere
sld_{cyl} = scattering length density of cylinders inside the core
sld_{solv} = scattering length density of solvent
For the particles with a non-spherical symmetry an orientational average is applied:
F^2(q) = \int_{0}^{\pi/2} f^2(q,\alpha) \sin(\alpha) d\alpha
The output of the 1D scattering intensity function is then given by
P(q) = \frac{\text{scale}}{V_{sph}} \int_0^{\pi/2} f^2(q,\alpha) \sin\alpha\ d\alpha + \text{background}
where
f(q,\alpha) = ( sld_{sph,sh2} - sld_{solv} ) * V_{sph} * f_sph( q*(R_{sph,c} + d_{sph,sh} + d_{sph,sh2}) )
+ ( sld_{sph,sh} - sld_{sph,sh2} ) * V_{sph,i} * f_sph( q*(R_{sph,c} + d_{sph,sh}) )
+ ( sld_{sph,c} - sld_{sph,sh} ) * V_{sph,c} * f_sph( q*R_{sph,c} )
+ ( sld_{cyl} - sld_{sph,c} ) * f_sph( q*R_{avgsph,cyl} ) * phi_{cyl} * V_{sph,c} * f_cyl(q,\alpha)
Note: normalization last term
( 1/V_{avgsph,cyl} * \int exp[i\mathbf{Q}\cdot\mathbf{r}_j] d^3\mathbf{r}_j ) * N * V_{cyl} * f_cyl = 1/V_{avgsph,cyl} * V_{avgsph,cyl} f_sph(q*R_{avgsph,cyl}) * N * V_{cyl} f_cyl = f_sph(q*R_{avgsph,cyl}) * N * V_{cyl} * f_cyl = V_{sph,c} * phi_{cyl} * f_sph(q*R_{avgsph,cyl}) * f_cyl
Note: in case of one shell and sld_{cyl} == sld_{sph,sh} and R_{avgsph,cyl} = R_{sph,c} it simplifies to:
f(q,\alpha) = ( sld_{sph,sh} - sld_{solv} ) * V_{sph} * f_sph( q*(R_{sph,c}+d_{sph,sh}) )
+ ( sld_{sph,c} - sld_{sph,sh} ) * f_sph( q*R_{sph,c} ) * V_{sph,c} * ( 1.0 - phi_{cyl} f_cyl(q,\alpha) )
where
f_cyl(q,alpha) = j_0( q*L_{cyl}*\cos(\alpha)/2 ) * 2J1x( q*R_{cyl}\sin(\alpha) )
f_sph(x) = 3 * \frac{ \sin(x)-x\cos(x) }{ x^3 }
where
j_0(x) = \sin(x) / x
2J1x(x) = 2 * J_1(x) / x , where $J_1$ is the first order Bessel function
V_{cyl} = \pi R_{cyl}^2 L_{cyl}
V_{avgsph,cyl} = 4\pi/3 R_{avgsph,cyl}^3
V_{sph,c} = 4\pi/3 R_{sph,c}^3
V_{sph} = 4\pi/3 (R_{sph,c}+d_{sph,sh})^3
For 2D:
The $\theta$ and $\phi$ parameters only appear in the model when fitting 2D data. For oriented cylinders, we define the direction of the axis of the cylinder using two angles $\theta$ and $\phi$. See cylinder angle definition:
.. figure:: img/cylinder_angle_definition.jpg
Validation
----------
Checked at different contrast conditions if it matches P(Q) of a (core-shell) sphere or a cylinder.
References
----------
Cylinders:
J. S. Pedersen, Adv. Colloid Interface Sci. 70, 171-210 (1997).
G. Fournet, Bull. Soc. Fr. Mineral. Cristallogr. 74, 39-113 (1951).
"""
import numpy as np # type: ignore
from numpy import pi, inf # type: ignore
name = "coredoubleshellspherefilledwithmanycylinders"
title = "Orientationally averaged form factor for a monodisperse spherical particle with a core-double-shell sphere structure, filled with circular cylinders in its core."
description = """
Note that the platelets inside are monodisperse with a given radius_cylinder and length_cylinder. Their amount is controlled via the fit parameter volume fraction = N * V_cylinder/ V_shpere_core. The randomly distributed positions of the cylinders inside a sphere with radius radius_cylinder_avgsph within the core translates into a form amplitude for a sphere with radius 0 < radius_cylinder_avgsph < radius_sphere_core. Applying polydispersity to the cylinders means to have core-double-shell spheres with cylinders inside, which differ between spheres, but not within one sphere.
Output:
P(q) = \frac{\text{scale}}{V_{sph}} \int_0^{\pi/2} f^2(q,\alpha) \sin\alpha\ d\alpha + \text{background}
where
f(q,\alpha) = ( sld_{sph,sh2} - sld_{solv} ) * V_{sph} * f_sph( q*(R_{sph,c} + d_{sph,sh} + d_{sph,sh2}) )
+ ( sld_{sph,sh} - sld_{sph,sh2} ) * V_{sph,i} * f_sph( q*(R_{sph,c} + d_{sph,sh}) )
+ ( sld_{sph,c} - sld_{sph,sh} ) * V_{sph,c} * f_sph( q*R_{sph,c} )
+ ( sld_{cyl} - sld_{sph,c} ) * f_sph( q*R_{avgsph,cyl} ) * phi_{cyl} * V_{sph,c} * f_cyl(q,\alpha)
Note: in case of one shell and sld_{cyl} == sld_{sph,sh} and R_{avgsph,cyl} = R_{sph,c} it simplifies to:
f(q,\alpha) = ( sld_{sph,sh} - sld_{solv} ) * V_{sph} * f_sph( q*(R_{sph,c}+d_{sph,sh}) )
+ ( sld_{sph,c} - sld_{sph,sh} ) * f_sph( q*R_{sph,c} ) * V_{sph,c} * ( 1.0 - phi_{cyl} f_cyl(q,\alpha) )
where
f_cyl(q,alpha) = j_0( q*L_{cyl}*\cos(\alpha)/2 ) * 2J1x( q*R_{cyl}\sin(\alpha) )
f_sph(x) = 3 * \frac{ \sin(x)-x\cos(x) }{ x^3 }
where
j_0(x) = \sin(x) / x
2J1x(x) = 2 * J_1(x) / x , where $J_1$ is the first order Bessel function
V_{cyl} = \pi R_{cyl}^2 L_{cyl}
V_{avgsph,cyl} = 4\pi/3 R_{avgsph,cyl}^3
V_{sph,c} = 4\pi/3 R_{sph,c}^3
V_{sph} = 4\pi/3 (R_{sph,c}+d_{sph,sh})^3
Parameters:
scale = scaling factor, volume fraction of particles scale phi ~ N V_{sph} / V_{irr}, with N / V_{irr} being the number density of particles in the irradiated volume
phi_{cyl} = relative volume fraction of cylinders inside the core sphere phi_{cyl} ~ N V_{cyl} / V_{sph,c}, with N / V_{sph,c} being the number density of cylinders in the core sphere
background = const. background
R_{sph,c} = core radius of sphere
d_{sph,sh} = inner shell thickness of sphere
d_{sph,sh2} = outer shell thickness of sphere
NB: R_{sph,c} + d_{sph,sh} = radius of whole sphere
R_{cyl} = radius of one cylinder
L_{cyl} = length of one cylinder
R_{avgsph,cyl} = radius of the averaging sphere for the cylinders
V_{sph} = volume of whole sphere including core and both shells
V_{sph,i} = volume of sphere including core and inner shell
V_{sph,c} = volume of sphere core
V_{cyl} = volume of cylinder
V_{avgsph,cyl} = volume of the averaging sphere for the cylinders
sld_{sph,c} = scattering length density of core of sphere
sld_{sph,sh} = scattering length density of inner shell of sphere
sld_{sph,sh2} = scattering length density of outer shell of sphere
sld_{cyl} = scattering length density of cylinders inside the core
sld_{solv} = scattering length density of solvent
"""
category = "shape:sphere"
# [ "name", "units", default, [lower, upper], "type", "description"],
#
# convention, first SLDs, then geometry, then orientation
# all functions in C and dict(demo) entries in Py should follow this convention, in order to not mix up params
parameters = [["volfract_cyl", "", 0.4, [0, 1], "", "relative volume fraction of cylinders in core sphere"],
["sld_core", "1e-6/Ang^2", 0.0, [-inf, inf], "sld", "core scattering length density"],
["sld_shell", "1e-6/Ang^2", 4.0, [-inf, inf], "sld", "inner shell scattering length density"],
["sld_shell_2", "1e-6/Ang^2", 4.0, [-inf, inf], "sld", "outer shell scattering length density"],
["sld_cyl", "1e-6/Ang^2", 4.0, [-inf, inf], "sld", "cylinder scattering length density"],
["sld_solvent", "1e-6/Ang^2", 6.34, [-inf, inf], "sld", "solvent scattering length density"],
["sphere_core_radius", "Ang", 500.0, [0, inf], "volume", "sphere core radius"],
["sphere_shell_thickness", "Ang", 100.0, [0, inf], "volume", "sphere inner shell thickness"],
["sphere_shell_thickness_2", "Ang", 50.0, [0, inf], "volume", "sphere outer shell thickness"],
["cyl_radius", "Ang", 400.0, [0, inf], "volume", "cylinder radius"],
["cyl_length", "Ang", 250.0, [0, inf], "volume", "cylinder length"],
["cyl_avgsph_radius", "Ang", 150.0, [0, inf], "volume", "radius of the averaging sphere for the positioning of the cylinders in the core"],
["theta", "degrees", 60, [-360, 360], "orientation", "latitude"],
["phi", "degrees", 60, [-360, 360], "orientation", "longitude"]]
source = ["lib/sas_3j1x_x.c", "lib/polevl.c", "lib/sas_J1.c", "lib/gauss76.c", "coredoubleshellspherefilledwithmanycylinders.c"]
# cylinder
# NB: The 2nd virial coefficient of the cylinder is calculated based on the radius and length values, and used as the effective radius for $S(q)$ when $P(q) \cdot S(q)$ is applied.
#
#def ER(radius, length):
# """
# Return equivalent radius (ER)
# """
# ddd = 0.75 * radius * (2 * radius * length + (length + radius) * (length + pi * radius))
# return 0.5 * (ddd) ** (1. / 3.)
# core-double-shell sphere
# NB: The outer most radius (= radius + thicknesses) is used as the effective radius for $S(Q)$ when $P(Q) \cdot S(Q)$ is applied.
#
def ER(sphere_core_radius, sphere_shell_thickness, sphere_shell_thickness_2):
"""
Equivalent radius
@param sphere_core_radius: sphere core radius
@param sphere_shell_thickness: sphere inner shell thickness
@param sphere_shell_thickness_2: sphere outer shell thickness
"""
return sphere_core_radius + sphere_shell_thickness + sphere_shell_thickness_2
# core-shell sphere
#def VR(radius, thickness):
# """
# Volume ratio
# @param radius: core radius
# @param thickness: shell thickness
# """
# return (1, 1)
# whole = 4.0/3.0 * pi * (radius + thickness)**3
# core = 4.0/3.0 * pi * radius**3
# return whole, whole - core
# parameters for demo
demo = dict(scale=1,
background=0,
volfract_cyl=0.4,
sld_core=0.0,
sld_shell=4.0,
sld_shell_2=2.0,
sld_cyl=4.0,
sld_solvent=6.34,
sphere_core_radius=500,
sphere_shell_thickness=100,
sphere_shell_thickness_2=50,
cyl_radius=400,
cyl_length=250,
cyl_avgsph_radius=150,
theta=60,
phi=60
)
# cyl_radius_pd=.2, cyl_radius_pd_n=9,
# cyl_length_pd=.2, cyl_length_pd_n=10,
qx, qy = 0.2 * np.cos(2.5), 0.2 * np.sin(2.5)
# After redefinition of angles, find new tests values. Was 10 10 in old coords
tests = [[{}, 0.2, 0.042761386790780453],
[{}, [0.2], [0.042761386790780453]],
# new coords
[{'theta':80.1534480601659, 'phi':10.1510817110481}, (qx, qy), 0.03514647218513852],
[{'theta':80.1534480601659, 'phi':10.1510817110481}, [(qx, qy)], [0.03514647218513852]],
# old coords [{'theta':10.0, 'phi':10.0}, (qx, qy), 0.03514647218513852],
# [{'theta':10.0, 'phi':10.0}, [(qx, qy)], [0.03514647218513852]],
]
del qx, qy # not necessary to delete, but cleaner
Back to Model
Download