Changeset cb038a2 in sasmodels for explore/bccpy.py
- Timestamp:
- Apr 17, 2017 12:54:31 PM (8 years ago)
- Branches:
- master, core_shell_microgels, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- 7e0b281
- Parents:
- 859567e
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
explore/bccpy.py
r859567e rcb038a2 1 """ 2 The current 1D calculations for BCC paracrystal are very wrong at low q, orders 3 of magnitude wrong. The integration fails to capture a very narrow, 4 very steep ridge. 5 6 Uncomment the plot() line at the bottom of the code to show an image of the 7 set of S(q, theta, phi) values that must be summed to form the 1D S(q=0.001) 8 for the BCC paracrystal form. Note particularly that this is a log scale 9 image spanning 10 orders of magnitude. This pattern repeats itself 8 times 10 over the entire 4 pi surface integral. 11 12 You can explore various integration options by uncommenting more lines. 13 Adaptive integration using scpy.integrate.dbsquad is very slow. Romberg 14 didn't even complete in the time I gave it. Accurate brute force calculation 15 requires a 4000x4000 grid to get enough precision. 16 17 We may need a specialized integrator for low q which can identify and integrate 18 the ridges properly. 19 20 This program need sasmodels on the path so it is inserted automatically, 21 assuming that the explore/bccpy.py is beside sasmodels/special.py in the 22 source tree. Run from the sasmodels directory using: 23 24 python explore/bccpy.py 25 """ 26 1 27 from __future__ import print_function, division 28 29 import os, sys 30 sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) 2 31 3 32 import numpy as np … … 11 40 from sasmodels.special import Gauss150Wt, Gauss150Z 12 41 13 def square(x):14 return x**215 16 42 Q = 0.001 17 43 DNN = 220. … … 22 48 23 49 def kernel(q, dnn, d_factor, theta, phi): 50 """ 51 S(q) kernel for paracrystal forms. 52 """ 24 53 qab = q*sin(theta) 25 54 qa = qab*cos(phi) … … 35 64 a3 = -qa + qc + qb 36 65 dcos = dnn/2 66 if 0: # fcc 67 a1 = qb + qa 68 a2 = qa + qc 69 a3 = qb + qc 70 dcos = dnn/2 37 71 38 72 arg = 0.5*square(dnn*d_factor)*(a1**2 + a2**2 + a3**2) … … 44 78 45 79 def scipy_dblquad(q=Q, dnn=DNN, d_factor=D_FACTOR): 80 """ 81 Compute the integral using scipy dblquad. This gets the correct answer 82 eventually, but it is slow. 83 """ 84 evals = [0] 46 85 def integrand(theta, phi): 86 evals[0] += 1 47 87 Sq = kernel(q=q, dnn=dnn, d_factor=d_factor, theta=theta, phi=phi) 48 88 return Sq*sin(theta) 49 return dblquad(integrand, 0, pi/2, lambda x: 0, lambda x: pi/2)[0]*8/(4*pi) 89 ans = dblquad(integrand, 0, pi/2, lambda x: 0, lambda x: pi/2)[0]*8/(4*pi) 90 print("dblquad evals =", evals[0]) 91 return ans 50 92 51 93 52 def scipy_romberg(q=Q, dnn=DNN, d_factor=D_FACTOR): 94 def scipy_romberg_2d(q=Q, dnn=DNN, d_factor=D_FACTOR): 95 """ 96 Compute the integral using romberg integration. This function does not 97 complete in a reasonable time. No idea if it is accurate. 98 """ 53 99 def inner(phi, theta): 54 100 return kernel(q=q, dnn=dnn, d_factor=d_factor, theta=theta, phi=phi) … … 58 104 59 105 106 def semi_romberg(q=Q, dnn=DNN, d_factor=D_FACTOR, n=100): 107 """ 108 Use 1D romberg integration in phi and regular simpsons rule in theta. 109 """ 110 evals = [0] 111 def inner(phi, theta): 112 evals[0] += 1 113 return kernel(q=q, dnn=dnn, d_factor=d_factor, theta=theta, phi=phi) 114 theta = np.linspace(0, pi/2, n) 115 f_phi = [romberg(inner, 0, pi/2, divmax=100, args=(t,)) 116 for t in theta] 117 ans = simps(sin(theta)*np.array(f_phi), dx=theta[1]-theta[0]) 118 print("semi romberg evals =", evals[0]) 119 return ans*8/(4*pi) 120 60 121 def gauss_quad(q=Q, dnn=DNN, d_factor=D_FACTOR, n=150): 122 """ 123 Compute the integral using gaussian quadrature for n = 20, 76 or 150. 124 """ 61 125 if n == 20: 62 126 z, w = Gauss20Z, Gauss20Wt … … 71 135 sin_theta = np.fmax(abs(sin(Atheta)), 1e-6) 72 136 Sq = kernel(q=q, dnn=dnn, d_factor=d_factor, theta=Atheta, phi=Aphi) 137 print("gauss %d evals ="%n, n**2) 73 138 return np.sum(Sq*Aw*sin_theta)*8/(4*pi) 74 139 75 140 76 141 def gridded_integrals(q=0.001, dnn=DNN, d_factor=D_FACTOR, n=300): 142 """ 143 Compute the integral on a regular grid using rectangular, trapezoidal, 144 simpsons, and romberg integration. Romberg integration requires that 145 the grid be of size n = 2**k + 1. 146 """ 77 147 theta = np.linspace(0, pi/2, n) 78 148 phi = np.linspace(0, pi/2, n) … … 85 155 print("simpson", n, simps(simps(Sq, dx=dx), dx=dy)*8/(4*pi)) 86 156 print("romb", n, romb(romb(Sq, dx=dx), dx=dy)*8/(4*pi)) 157 print("gridded %d evals ="%n, n**2) 87 158 88 159 def plot(q=0.001, dnn=DNN, d_factor=D_FACTOR, n=300): 89 #theta = np.linspace(0, pi, n) 90 #phi = np.linspace(0, 2*pi, n) 91 theta = np.linspace(0, pi/2, n) 92 phi = np.linspace(0, pi/2, n) 160 """ 161 Plot the 2D surface that needs to be integrated in order to compute 162 the BCC S(q) at a particular q, dnn and d_factor. *n* is the number 163 of points in the grid. 164 """ 165 theta = np.linspace(0, pi, n) 166 phi = np.linspace(0, 2*pi, n) 167 #theta = np.linspace(0, pi/2, n) 168 #phi = np.linspace(0, pi/2, n) 93 169 Atheta, Aphi = np.meshgrid(theta, phi) 94 170 Sq = kernel(q=Q, dnn=dnn, d_factor=d_factor, theta=Atheta, phi=Aphi) 95 171 Sq *= abs(sin(Atheta)) 96 172 pylab.pcolor(degrees(theta), degrees(phi), log10(np.fmax(Sq, 1.e-6))) 97 pylab.title("I(q) for q=%g"%q) 173 pylab.axis('tight') 174 pylab.title("BCC S(q) for q=%g, dnn=%g d_factor=%g" % (q, dnn, d_factor)) 98 175 pylab.xlabel("theta (degrees)") 99 176 pylab.ylabel("phi (degrees)") 100 177 cbar = pylab.colorbar() 101 cbar.set_label('log10 I(q)')178 cbar.set_label('log10 S(q)') 102 179 pylab.show() 103 180 104 181 if __name__ == "__main__": 105 print("gauss", 20, gauss_quad(n=20)) 106 print("gauss", 76, gauss_quad(n=76)) 107 print("gauss", 150, gauss_quad(n=150)) 108 print("dblquad", scipy_dblquad()) 109 gridded_integrals(n=2**8+1) 110 gridded_integrals(n=2**10+1) 111 gridded_integrals(n=2**13+1) 182 #print("gauss", 20, gauss_quad(n=20)) 183 #print("gauss", 76, gauss_quad(n=76)) 184 #print("gauss", 150, gauss_quad(n=150)) 185 #print("dblquad", scipy_dblquad()) 186 #print("semi romberg", semi_romberg()) 187 #gridded_integrals(n=2**8+1) 188 #gridded_integrals(n=2**10+1) 189 #gridded_integrals(n=2**13+1) 112 190 #print("romberg", scipy_romberg()) 113 #plot(n=300)191 plot(n=400)
Note: See TracChangeset
for help on using the changeset viewer.