source: sasmodels/explore/symint.py @ 4f611f1

core_shell_microgelsmagnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 4f611f1 was 4f611f1, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

play with cylinder integral

  • Property mode set to 100644
File size: 3.7 KB
Line 
1"""
2Explore integration of rotationally symmetric shapes
3"""
4
5from __future__ import print_function, division
6
7import os, sys
8sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
9
10import numpy as np
11from numpy import pi, sin, cos, sqrt, exp, expm1, degrees, log10
12from scipy.integrate import dblquad, simps, romb, romberg
13import pylab
14
15from sasmodels.special import square
16from sasmodels.special import Gauss20Wt, Gauss20Z
17from sasmodels.special import Gauss76Wt, Gauss76Z
18from sasmodels.special import Gauss150Wt, Gauss150Z
19from sasmodels.special import sas_2J1x_x, sas_sinx_x, sas_3j1x_x
20
21SLD = 3.0
22SLD_SOLVENT = 6.3
23CONTRAST = SLD - SLD_SOLVENT
24
25def make_cylinder(radius, length):
26    def cylinder(qab, qc):
27        return sas_2J1x_x(qab*radius) * sas_sinx_x(qc*0.5*length)
28    volume = pi*radius**2*length
29    norm = 1e-4*volume*CONTRAST**2
30    return norm, cylinder
31
32def make_sphere(radius):
33    def sphere(qab, qc):
34        q = sqrt(qab**2 + qc**2)
35        return sas_3j1x_x(q*radius)
36    volume = 4*pi*radius**3/3
37    norm = 1e-4*volume*CONTRAST**2
38    return norm, sphere
39   
40THETA_LOW, THETA_HIGH = 0, pi
41SCALE = 1
42
43
44def kernel(q, theta):
45    """
46    S(q) kernel for paracrystal forms.
47    """
48    qab = q*sin(theta)
49    qc = q*cos(theta)
50    return NORM*KERNEL(qab, qc)**2
51
52
53def gauss_quad(q, n=150):
54    """
55    Compute the integral using gaussian quadrature for n = 20, 76 or 150.
56    """
57    if n == 20:
58        z, w = Gauss20Z, Gauss20Wt
59    elif n == 76:
60        z, w = Gauss76Z, Gauss76Wt
61    else:
62        z, w = Gauss150Z, Gauss150Wt
63    theta = (THETA_HIGH-THETA_LOW)*(z + 1)/2 + THETA_LOW
64    sin_theta = abs(sin(theta))
65    Zq = kernel(q=q, theta=theta)
66    return np.sum(Zq*w*sin_theta)*SCALE/2
67
68
69def gridded_integrals(q, n=300):
70    """
71    Compute the integral on a regular grid using rectangular, trapezoidal,
72    simpsons, and romberg integration.  Romberg integration requires that
73    the grid be of size n = 2**k + 1.
74    """
75    theta = np.linspace(THETA_LOW, THETA_HIGH, n)
76    Zq = kernel(q=q, theta=theta)
77    Zq *= abs(sin(theta))
78    dx = theta[1]-theta[0]
79    print("rect", n, np.sum(Zq)*dx*SCALE/pi)
80    print("trapz", n, np.trapz(Zq, dx=dx)*SCALE/pi)
81    print("simpson", n, simps(Zq, dx=dx)*SCALE/pi)
82    print("romb", n, romb(Zq, dx=dx)*SCALE/pi)
83
84def scipy_romberg(q):
85    """
86    Compute the integral using romberg integration.  This function does not
87    complete in a reasonable time.  No idea if it is accurate.
88    """
89    evals = [0]
90    def outer(theta):
91        evals[0] += 1
92        return kernel(q, theta=theta)*abs(sin(theta))
93    result = romberg(outer, THETA_LOW, THETA_HIGH, divmax=100)*SCALE/pi
94    print("scipy romberg", evals[0], result)
95
96def plot(q, n=300):
97    """
98    Plot the 2D surface that needs to be integrated in order to compute
99    the BCC S(q) at a particular q, dnn and d_factor.  *n* is the number
100    of points in the grid.
101    """
102    theta = np.linspace(THETA_LOW, THETA_HIGH, n)
103    Zq = kernel(q=q, theta=theta)
104    Zq *= abs(sin(theta))
105    pylab.semilogy(degrees(theta), np.fmax(Zq, 1.e-6))
106    pylab.title("%s Z(q) for q=%g" % (KERNEL.__name__, q))
107    pylab.xlabel("theta (degrees)")
108    pylab.ylabel("Iq 1/cm")
109    pylab.show()
110
111NORM, KERNEL = make_cylinder(radius=10., length=100000.)
112#NORM, KERNEL = make_cylinder(radius=10., length=10000.)
113#NORM, KERNEL = make_cylinder(radius=10., length=30.)
114#NORM, KERNEL = make_sphere(radius=50.)
115
116if __name__ == "__main__":
117    Q = 0.8
118    print("gauss", 20, gauss_quad(Q, n=20))
119    print("gauss", 76, gauss_quad(Q, n=76))
120    print("gauss", 150, gauss_quad(Q, n=150))
121    gridded_integrals(Q, n=2**8+1)
122    gridded_integrals(Q, n=2**10+1)
123    gridded_integrals(Q, n=2**13+1)
124    gridded_integrals(Q, n=2**16+1)
125    gridded_integrals(Q, n=2**19+1)
126    #scipy_romberg(Q)
127    plot(Q, n=2000)
Note: See TracBrowser for help on using the repository browser.