def main(Qstr): Q = float(Qstr) if shape == 'sphere': print("exact", NORM * sp.sas_3j1x_x(Q * RADIUS)**2) print("gauss-20", *gauss_quad_2d(Q, n=20)) print("gauss-76", *gauss_quad_2d(Q, n=76)) print("gauss-150", *gauss_quad_2d(Q, n=150)) print("gauss-500", *gauss_quad_2d(Q, n=500)) print("gauss-1025", *gauss_quad_2d(Q, n=1025)) print("gauss-2049", *gauss_quad_2d(Q, n=2049)) print("gauss-20 usub", *gauss_quad_usub(Q, n=20)) print("gauss-76 usub", *gauss_quad_usub(Q, n=76)) print("gauss-150 usub", *gauss_quad_usub(Q, n=150)) #gridded_2d(Q, n=2**8+1) gridded_2d(Q, n=2**10 + 1) #gridded_2d(Q, n=2**12+1) #gridded_2d(Q, n=2**15+1) if shape not in ('paracrystal', 'core_shell_parallelepiped'): # adaptive forms on models for which the calculations are fast enough print("dblquad", *scipy_dblquad_2d(Q)) print("semi-romberg-100", *semi_romberg_2d(Q, n=100)) print("romberg", *scipy_romberg_2d(Q)) with mp.workprec(100): print("mpmath", *mp_quad_2d(mp.mpf(Qstr), shape)) plot_2d(Q, n=200)
def sphere(qab, qc): q = sqrt(qab**2 + qc**2) return sas_3j1x_x(q * radius)
def Iq(q, sld, sld_shell, sld_poly, sld_solvent, radius, t_shell, poly_sig, C_infty, M0, Mn, nu, v): # Bond angles theta0 = 68.0 * pi / 180.0 # Kuhn length b = C_infty * 1.54 / cos(theta0 / 2.0) # Deg. of polymerization N = (Mn / M0) * cos(theta0 / 2.0) / C_infty # Volume of core regions: Rcoreshell = radius + t_shell Vcore = 4.0 / 3.0 * pi * radius**3 Vcoreshell = 4.0 / 3.0 * pi * (radius + t_shell)**3 # Number of grafted chains per core: Ng = poly_sig * 4.00 * pi * (0.1 * Rcoreshell) * (0.1 * Rcoreshell) Vtotal = Vcoreshell + Ng * N * v # One over excl. vol. parm.: onu = 1.0 / nu o2nu = 1.0 / 2.0 / nu # Propagator function: Ea = sas_sinx_x(q * (Rcoreshell)) # Polymer size variable Usub = (q * b)**2 * N**(2 * nu) / 6.0 # Form factor amplitude of core-shell sphere: with errstate(divide='ignore'): Fs = (sld - sld_shell) * Vcore * sas_3j1x_x(q * radius) + ( sld_shell - sld_solvent) * Vcoreshell * sas_3j1x_x(q * Rcoreshell) # Form factor amplitude of the polymer: with errstate(divide='ignore'): Fp = N * v * o2nu * power( Usub, -o2nu) * sas_gamma(o2nu) * sas_gammainc(o2nu, Usub) # Form factor of the polymer (Pp(q) is not simply Fp(q)^2!!): with errstate(divide='ignore'): Pp = (N * v)**2 * (onu * power(Usub, -o2nu) * sas_gamma(o2nu) * sas_gammainc(o2nu, Usub) - onu * power(Usub, -onu) * sas_gamma(onu) * sas_gammainc(onu, Usub)) # Combine all terms to form intensity: # # Term 1: Core-shell particle: inten = Fs * Fs # Term 2: Polymer inten = inten + Ng * (sld_poly - sld_solvent) * (sld_poly - sld_solvent) * Pp # Term 3: Particle/polymer crossterm: inten = inten + 2.0 * Ng * (sld_poly - sld_solvent) * Fs * Ea * Fp # Term 4: Polymer/polymer crossterm: inten = inten + Ng * (Ng - 1) * (sld_poly - sld_solvent) * ( sld_poly - sld_solvent) * Fp * Ea * Ea * Fp with errstate(divide='ignore'): inten = inten * 1.0e-4 / Vtotal return inten
def Iq(q, sld, sld_poly, sld_solvent, radius=60, poly_sig=0.50, rg=40, nu=0.5, v_poly=30): """ :param q: Input q-value :param sld: Core scattering length density :param sld_poly: Polymer scattering length density :param sld_solvent: Solvent scattering length density :param radius: Core radius :param poly_sig: Polymer grafting density :param rg: Grafted polymer radius of gyration :param nu: Grafted polymer excluded volume parameter :param v_poly: Volume of one polymer :return: Calculated intensity """ # Number of grafted chains per core: Ng = poly_sig * 4.00 * pi * (0.1 * radius) * (0.1 * radius) # Volume of core regions: Vcore = 4.0 / 3.0 * pi * radius**3 Vtotal = Vcore + Ng * v_poly # One over excl. vol. parm.: onu = 1.0 / nu o2nu = 1.0 / 2.0 / nu # Propagator function: Ea = sas_sinx_x(q * radius) # Polymer size variable Usub = (q * rg)**2 * (2.0 * nu + 1.0) * (2.0 * nu + 2.0) / 6.0 # Form factor amplitude of core-shell sphere: with errstate(divide='ignore'): Fs = 3.0 * (sld - sld_solvent) * Vcore * sas_3j1x_x(q * radius) # Form factor amplitude of the polymer: with errstate(divide='ignore'): Fp = o2nu * power(Usub, -o2nu) * sas_gamma(o2nu) * sas_gammainc( o2nu, Usub) # Form factor of the polymer (Pp(q) is not simply Fp(q)^2!!): with errstate(divide='ignore'): Pp = onu * power(Usub, -o2nu) * sas_gamma(o2nu) * sas_gammainc( o2nu, Usub) - onu * power( Usub, -onu) * sas_gamma(onu) * sas_gammainc(onu, Usub) # Combine all terms to form intensity: # # Term 1: Core-shell particle: inten = Fs * Fs # Term 2: Polymer inten = inten + Ng * v_poly * v_poly * (sld_poly - sld_solvent) * ( sld_poly - sld_solvent) * Pp # Term 3: Particle/polymer crossterm: inten = inten + 2.0 * Ng * v_poly * (sld_poly - sld_solvent) * Fs * Ea * Fp # Term 4: Polymer/polymer crossterm: inten = inten + Ng * (Ng - 1) * v_poly * v_poly * ( sld_poly - sld_solvent) * (sld_poly - sld_solvent) * Fp * Ea * Ea * Fp with errstate(divide='ignore'): inten = inten * 1.0e-6 * 1.0e-6 * 1.0e8 / Vtotal return inten
def main(): import argparse parser = argparse.ArgumentParser( description="asymmetric integration explorer", formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) parser.add_argument('-s', '--shape', choices=SHAPES, default='parallelepiped', help='oriented shape') parser.add_argument('-q', '--q_value', type=str, default='0.005', help='Q value to evaluate') parser.add_argument('pars', type=str, nargs='*', default=[], help='p=val for p in shape parameters') opts = parser.parse_args() pars = {k: v for par in opts.pars for k, v in [par.split('=')]} build_shape(opts.shape, **pars) Q = float(opts.q_value) if opts.shape == 'sphere': print("exact", NORM * sp.sas_3j1x_x(Q * RADIUS)**2) # Methods from quadpy, if quadpy is available # AlbrechtCollatz: [1-5] # BazantOh: 9, 11, 13 # HeoXu: 13, 15, 17, 19-[1-2], 21-[1-6], 23-[1-3], 25-[1-2], 27-[1-3], # 29, 31, 33, 35, 37, 39-[1-2] # FliegeMaier: 4, 9, 16, 25 # Lebedev: 3[a-c], 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 35, # 41, 47, 53, 59, 65, 71, 77 83, 89, 95, 101, 107, 113, 119, 125, 131 # McLaren: [1-10] # Stroud: U3 3-1, U3 5-[1-5], U3 7-[1-2], U3 8-1, U3 9-[1-3], # U3 11-[1-3], U3 14-1 quadpy_method(Q, "AlbrechtCollatz:5") quadpy_method(Q, "HeoXu:39-2") quadpy_method(Q, "FliegeMaier:25") quadpy_method(Q, "Lebedev:19") quadpy_method(Q, "Lebedev:131") quadpy_method(Q, "McLaren:10") quadpy_method(Q, "Stroud:U3 14-1") print("gauss-20 points=%d => %.15g" % gauss_quad_2d(Q, n=20)) print("gauss-76 points=%d => %.15g" % gauss_quad_2d(Q, n=76)) print("gauss-150 points=%d => %.15g" % gauss_quad_2d(Q, n=150)) print("gauss-500 points=%d => %.15g" % gauss_quad_2d(Q, n=500)) print("gauss-1025 points=%d => %.15g" % gauss_quad_2d(Q, n=1025)) print("gauss-2049 points=%d => %.15g" % gauss_quad_2d(Q, n=2049)) print("gauss-20 usub points=%d => %.15g" % gauss_quad_usub(Q, n=20)) print("gauss-76 usub points=%d => %.15g" % gauss_quad_usub(Q, n=76)) print("gauss-150 usub points=%d => %.15g" % gauss_quad_usub(Q, n=150)) #gridded_2d(Q, n=2**8+1) gridded_2d(Q, n=2**10 + 1) #gridded_2d(Q, n=2**12+1) #gridded_2d(Q, n=2**15+1) # adaptive forms on models for which the calculations are fast enough SLOW_SHAPES = { 'fcc_paracrystal', 'bcc_paracrystal', 'sc_paracrystal', 'core_shell_parallelepiped', } if opts.shape not in SLOW_SHAPES: print("dblquad", *scipy_dblquad_2d(Q)) print("semi-romberg-100", *semi_romberg_2d(Q, n=100)) print("romberg", *scipy_romberg_2d(Q)) with mp.workprec(100): print("mpmath", *mp_quad_2d(mp.mpf(opts.q_value))) plot_2d(Q, n=200)