source: sasmodels/explore/symint.py @ fac6657

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

play with cylinder integral

  • Property mode set to 100644
File size: 5.1 KB
RevLine 
[4f611f1]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
[d327066]13from scipy.special.orthogonal import p_roots
[4f611f1]14import pylab
15
16from sasmodels.special import square
17from sasmodels.special import Gauss20Wt, Gauss20Z
18from sasmodels.special import Gauss76Wt, Gauss76Z
19from sasmodels.special import Gauss150Wt, Gauss150Z
20from sasmodels.special import sas_2J1x_x, sas_sinx_x, sas_3j1x_x
21
22SLD = 3.0
23SLD_SOLVENT = 6.3
24CONTRAST = SLD - SLD_SOLVENT
25
26def make_cylinder(radius, length):
27    def cylinder(qab, qc):
28        return sas_2J1x_x(qab*radius) * sas_sinx_x(qc*0.5*length)
[d327066]29    cylinder.__doc__ = "cylinder radius=%g, length=%g"%(radius, length)
[4f611f1]30    volume = pi*radius**2*length
31    norm = 1e-4*volume*CONTRAST**2
32    return norm, cylinder
33
34def make_sphere(radius):
35    def sphere(qab, qc):
36        q = sqrt(qab**2 + qc**2)
37        return sas_3j1x_x(q*radius)
[d327066]38    sphere.__doc__ = "sphere radius=%g"%(radius,)
[4f611f1]39    volume = 4*pi*radius**3/3
40    norm = 1e-4*volume*CONTRAST**2
[d327066]41    return norm, sphere
42
43THETA_LOW, THETA_HIGH = 0, pi/2
[4f611f1]44SCALE = 1
45
46
47def kernel(q, theta):
48    """
49    S(q) kernel for paracrystal forms.
50    """
51    qab = q*sin(theta)
52    qc = q*cos(theta)
53    return NORM*KERNEL(qab, qc)**2
54
55
56def gauss_quad(q, n=150):
57    """
58    Compute the integral using gaussian quadrature for n = 20, 76 or 150.
59    """
[d327066]60    z, w = p_roots(n)
[4f611f1]61    theta = (THETA_HIGH-THETA_LOW)*(z + 1)/2 + THETA_LOW
62    sin_theta = abs(sin(theta))
63    Zq = kernel(q=q, theta=theta)
[d327066]64    return np.sum(Zq*w*sin_theta)*(THETA_HIGH-THETA_LOW)/2
[4f611f1]65
66
67def gridded_integrals(q, n=300):
68    """
69    Compute the integral on a regular grid using rectangular, trapezoidal,
70    simpsons, and romberg integration.  Romberg integration requires that
71    the grid be of size n = 2**k + 1.
72    """
73    theta = np.linspace(THETA_LOW, THETA_HIGH, n)
74    Zq = kernel(q=q, theta=theta)
75    Zq *= abs(sin(theta))
76    dx = theta[1]-theta[0]
[d327066]77    print("rect", n, np.sum(Zq)*dx*SCALE)
78    print("trapz", n, np.trapz(Zq, dx=dx)*SCALE)
79    print("simpson", n, simps(Zq, dx=dx)*SCALE)
80    print("romb", n, romb(Zq, dx=dx)*SCALE)
[4f611f1]81
82def scipy_romberg(q):
83    """
84    Compute the integral using romberg integration.  This function does not
85    complete in a reasonable time.  No idea if it is accurate.
86    """
87    evals = [0]
88    def outer(theta):
89        evals[0] += 1
90        return kernel(q, theta=theta)*abs(sin(theta))
[d327066]91    result = romberg(outer, THETA_LOW, THETA_HIGH, divmax=100)*SCALE
[4f611f1]92    print("scipy romberg", evals[0], result)
93
94def plot(q, n=300):
95    """
96    Plot the 2D surface that needs to be integrated in order to compute
97    the BCC S(q) at a particular q, dnn and d_factor.  *n* is the number
98    of points in the grid.
99    """
100    theta = np.linspace(THETA_LOW, THETA_HIGH, n)
101    Zq = kernel(q=q, theta=theta)
102    Zq *= abs(sin(theta))
[e5d7a60]103    pylab.semilogy(degrees(theta), np.fmax(Zq, 1.e-6), label="Q=%g"%q)
[d327066]104    pylab.title("%s I(q, theta) sin(theta)" % (KERNEL.__doc__,))
[4f611f1]105    pylab.xlabel("theta (degrees)")
106    pylab.ylabel("Iq 1/cm")
107
[a2fcbd8]108def Iq_trapz(q, n):
109    theta = np.linspace(THETA_LOW, THETA_HIGH, n)
110    Zq = kernel(q=q, theta=theta)
111    Zq *= abs(sin(theta))
112    dx = theta[1]-theta[0]
[d327066]113    return np.trapz(Zq, dx=dx)*SCALE
[a2fcbd8]114
115def plot_Iq(q, n, form="trapz"):
116    if form == "trapz":
117        I = np.array([Iq_trapz(qk, n) for qk in q])
118    elif form == "gauss":
119        I = np.array([gauss_quad(qk, n) for qk in q])
120    pylab.loglog(q, I, label="%s, n=%d"%(form, n))
121    pylab.xlabel("q (1/A)")
122    pylab.ylabel("Iq (1/cm)")
[d327066]123    pylab.title(KERNEL.__doc__ + " I(q) circular average")
124    return q, I
[a2fcbd8]125
[4f611f1]126NORM, KERNEL = make_cylinder(radius=10., length=100000.)
[d327066]127#NORM, KERNEL = make_cylinder(radius=10., length=50000.)
128#NORM, KERNEL = make_cylinder(radius=10., length=20000.)
[4f611f1]129#NORM, KERNEL = make_cylinder(radius=10., length=10000.)
[d327066]130#NORM, KERNEL = make_cylinder(radius=10., length=5000.)
131#NORM, KERNEL = make_cylinder(radius=10., length=1000.)
132#NORM, KERNEL = make_cylinder(radius=10., length=500.)
133#NORM, KERNEL = make_cylinder(radius=10., length=100.)
[4f611f1]134#NORM, KERNEL = make_cylinder(radius=10., length=30.)
135#NORM, KERNEL = make_sphere(radius=50.)
136
137if __name__ == "__main__":
138    Q = 0.8
[d327066]139    for n in (20, 76, 150, 300, 1000): #, 10000, 30000):
140        print("gauss", n, gauss_quad(Q, n=n))
141    for k in (8, 10, 13, 16, 19):
142        gridded_integrals(Q, n=2**k+1)
[4f611f1]143    #scipy_romberg(Q)
[e5d7a60]144    plot(0.5, n=2000)
145    plot(0.6, n=2000)
146    plot(0.8, n=2000)
147    pylab.legend()
[a2fcbd8]148    pylab.figure()
[d327066]149    #plot_Iq(np.logspace(-3, 0, 400), n=2**19+1, form="trapz")
150    q1, I1 = plot_Iq(np.logspace(-3, 0, 400), n=2**16+1, form="trapz")
151    #plot_Iq(np.logspace(-3, 0, 400), n=2**10+1, form="trapz")
[fac23b3]152    q2, I2 = plot_Iq(np.logspace(-3, 0, 400), n=1024, form="gauss")
[d327066]153    #plot_Iq(np.logspace(-3, 0, 400), n=300, form="gauss")
154    plot_Iq(np.logspace(-3, 0, 400), n=150, form="gauss")
155    plot_Iq(np.logspace(-3, 0, 400), n=76, form="gauss")
[a2fcbd8]156    pylab.legend()
[d327066]157    #pylab.figure()
158    #pylab.semilogx(q1, (I2 - I1)/I1)
[e5d7a60]159    pylab.show()
Note: See TracBrowser for help on using the repository browser.