Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions sasmodels/models/tetrapod.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// half of the angle between arms in radians
const double A = acos(-1 / 3) / 2.0 * M_PI / 180.0;

static double u_n(int n, double theta, double alpha) {
const double phi[4] = {0.0, M_PI_2, M_PI, 3.0 * M_PI_2};
const double sign[4] = {1.0, -1.0, 1.0, -1.0};
return sign[n] * cos(A) * cos(theta) +
sin(A) * sin(theta) * cos(alpha - phi[n]);
}

static double Fq_n(double q, double u, double L, double R) {
double quL2 = q * u * L * 0.5;

double mu = sqrt(fmax(0.0, 1.0 - u * u));
double qmuR = q * mu * R;

return sas_sinx_x(quL2) * sas_2J1x_x(qmuR);
}

static double form_volume(double L, double R) {
// V = 4 * \pi * R^2 * L
return 4.0 * M_PI * R * R * L;
}

static double Iq(double q, double L, double R, double sld_particle,
double sld_solvent) {
double contrast = sld_particle - sld_solvent;
double total = 0.0;

for (int dtheta = 0; dtheta < GAUSS_N; dtheta++) {
double theta =
M_PI_2 * (GAUSS_Z[dtheta] + 1.0); // map from [-1, 1] to [0, pi]
double w_theta =
GAUSS_W[dtheta] * M_PI_2; // adjust weight for the new range

double integral_alpha = 0.0;
for (int dalpha = 0; dalpha < GAUSS_N; dalpha++) {
double alpha =
M_PI * (GAUSS_Z[dalpha] + 1.0); // map from [-1, 1] to [0, 2*pi]
double w_alpha =
GAUSS_W[dalpha] * M_PI; // adjust weight for the new range

double sum_arms = 0.0;
for (int n = 0; n < 4; n++) {
for (int m = 0; m < 4; m++) {
double u = u_n(n, theta, alpha);
double v = u_n(m, theta, alpha);
sum_arms += Fq_n(q, u, L, R) * Fq_n(q, v, L, R) *
cos(q * (u - v) * L / 2.0) * sin(theta);
}
}
integral_alpha += sum_arms * w_alpha;
}
total += integral_alpha * w_theta;
}
return 1e-4 * contrast * contrast * total * 2 / M_PI;
}
90 changes: 90 additions & 0 deletions sasmodels/models/tetrapod.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
r"""
Definition
----------

Calculates the scattering from a tetrapod-shaped structure. A tetrapod consists
of four cylindrical arms radiating from a central point, oriented along the
(1,1,1), (-1,-1,1), (-1,1,-1), and (1,-1,-1) directions.

The scattering intensity is calculated as an average over all
orientations:

.. math::

I(q) = \frac{(\Delta \rho)^2}{4\pi}
\int_0^{\pi} \int_0^{2\pi}
\left|\sum_{n=1}^{4} F_n(q, \theta, \varphi)\right|^2
\sin\theta \, d\theta \, d\varphi

where $\Delta\rho$ is the SLD contrast and $F_n$ is the form factor amplitude
of the $n$-th cylindrical arm:

.. math::

F_n(q, \theta, \varphi) = \text{sinc}\!\left(\frac{q u_n L}{2}\right)
\cdot \frac{2 J_1(q \mu_n R)}{q \mu_n R}

with $u_n = \hat{q} \cdot \hat{a}_n$ the projection of $\hat{q}$ onto the
arm axis, $\mu_n = \sqrt{1 - u_n^2}$, $L$ the arm length, and $R$ the arm
radius. Expanding the squared modulus into a double sum and exploiting the
reality of $F_n$ gives:

.. math::

I(q) = \frac{(\Delta \rho)^2}{4\pi}
\int \sum_{n=1}^{4}\sum_{m=1}^{4}
F_n F_m \cos\!\left(\frac{q(u_n-u_m)L}{2}\right)
\sin\theta \, d\theta \, d\varphi

The cosine factor is the interference term between the centres of arms $n$
and $m$, which are displaced by $\tfrac{L}{2}\hat{a}_n$ from the junction.

Geometry
--------

The four arms are oriented along tetrahedral directions. With
$A = 109.5°/2$ (the half-angle between arms), the arm unit vectors and the
corresponding projections $u_n$ are

.. math::

u_n = s_n \cos A \cos\theta + \sin A \sin\theta \cos(\varphi - \varphi_n)

where $(s_n, \varphi_n) = (+1,\ 0),\ (-1,\ \pi/2),\ (+1,\ \pi),\ (-1,\ 3\pi/2)$
for $n = 1, 2, 3, 4$ respectively.

Each arm has length $L$ and radius $R$.

References
----------

#. Seoki Kyoo Seo *Korean J. Chem. Eng.* 34(2017) 1192-1198

Authorship and Verification
----------------------------

* **Author:** Yuhei Yamada (Github user name: Indigo Carmine, https://orcid.org/0009-0003-9780-4135)
* **Last Modified by:**
"""

from numpy import inf

name = "tetrapod"
title = "Tetrapod with four cylindrical arms"
description = """
Calculates the scattering from a tetrapod structure with four cylindrical
arms radiating from a central point.
"""
category = "shape:cylinder"

# [ "name", "units", default, [lower, upper], "type", "description"],
parameters = [
["length", "Ang", 400, [0, inf], "volume", "Cylindrical arm length"],
["radius", "Ang", 30, [0, inf], "volume", "Cylindrical arm radius"],
["sld", "1e-6/Ang^2", 4, [-inf, inf], "sld", "Tetrapod scattering length density"],
["sld_solvent", "1e-6/Ang^2", 1, [-inf, inf], "sld", "Solvent scattering length density"],
]

source = ["lib/polevl.c", "lib/sas_J1.c", "lib/gauss76.c", "tetrapod.c"]
have_Fq = False
opencl = True