Changeset 54bcd4a in sasmodels for sasmodels/models/spherical_sld.py


Ignore:
Timestamp:
Aug 4, 2016 2:48:37 PM (8 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
745b7bb
Parents:
bd49c79
Message:

spherical sld: simplify code so that it works on AMD GPUs

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/models/spherical_sld.py

    r4fd2c63 r54bcd4a  
    190190 
    191191import numpy as np 
    192 from numpy import inf 
     192from numpy import inf, expm1, sqrt 
     193from scipy.special import erf 
    193194 
    194195name = "spherical_sld" 
     
    200201category = "shape:sphere" 
    201202 
     203SHAPES = ["erf(|nu|*z)", "Rpow(z^|nu|)", "Lpow(z^|nu|)", 
     204          "Rexp(-|nu|z)", "Lexp(-|nu|z)"], 
     205 
    202206# pylint: disable=bad-whitespace, line-too-long 
    203207#            ["name", "units", default, [lower, upper], "type", "description"], 
    204 parameters = [["n_shells",          "",               1,      [0, 10],        "volume", "number of shells"], 
    205               ["npts_inter",        "",               35,     [0, inf],       "", "number of points in each sublayer Must be odd number"], 
    206               ["radius_core",       "Ang",            50.0,   [0, inf],       "volume", "intern layer thickness"], 
    207               ["sld_core",          "1e-6/Ang^2",     2.07,   [-inf, inf],    "sld", "sld function flat"], 
    208               ["sld_solvent",       "1e-6/Ang^2",     1.0,    [-inf, inf],    "sld", "sld function solvent"], 
    209               ["func_inter0",       "",               0,      [0, 5],         "", "Erf:0, RPower:1, LPower:2, RExp:3, LExp:4, Linear:5"], 
    210               ["thick_inter0",      "Ang",            50.0,   [0, inf],       "volume", "intern layer thickness for core layer"], 
    211               ["nu_inter0",         "",               2.5,    [-inf, inf],    "", "steepness parameter for core layer"], 
    212               ["sld_flat[n_shells]",      "1e-6/Ang^2",     4.06,   [-inf, inf],    "sld", "sld function flat"], 
    213               ["thick_flat[n_shells]",    "Ang",            100.0,  [0, inf],       "volume", "flat layer_thickness"], 
    214               ["func_inter[n_shells]",    "",               0,      [0, 5],         "", "Erf:0, RPower:1, LPower:2, RExp:3, LExp:4, Linear:5"], 
    215               ["thick_inter[n_shells]",   "Ang",            50.0,   [0, inf],       "volume", "intern layer thickness"], 
    216               ["nu_inter[n_shells]",      "",               2.5,    [-inf, inf],    "", "steepness parameter"], 
     208parameters = [["n_shells",             "",           1,      [1, 11],        "volume", "number of shells"], 
     209              ["sld_solvent",          "1e-6/Ang^2", 1.0,    [-inf, inf],    "sld", "solvent sld"], 
     210              ["sld[n_shells]",        "1e-6/Ang^2", 4.06,   [-inf, inf],    "sld", "sld of the shell"], 
     211              ["thickness[n_shells]",  "Ang",        100.0,  [0, inf],       "volume", "thickness shell"], 
     212              ["interface[n_shells]",  "Ang",        50.0,   [0, inf],       "volume", "thickness of the interface"], 
     213              ["shape[n_shells]",      "",           0,      SHAPES,         "", "interface shape"], 
     214              ["nu[n_shells]",         "",           2.5,    [0, inf],       "", "interface shape exponent"], 
     215              ["n_steps",              "",           35,     [0, inf],       "", "number of steps in each interface (must be an odd integer)"], 
    217216              ] 
    218217# pylint: enable=bad-whitespace, line-too-long 
    219 source = ["lib/polevl.c", "lib/sas_erf.c", "lib/librefl.c",  "lib/sph_j1c.c", "spherical_sld.c"] 
     218source = ["lib/polevl.c", "lib/sas_erf.c", "lib/sph_j1c.c", "spherical_sld.c"] 
    220219single = False  # TODO: fix low q behaviour 
    221220 
    222221profile_axes = ['Radius (A)', 'SLD (1e-6/A^2)'] 
    223 def profile(n_shells, radius_core,  sld_core,  sld_solvent, sld_flat, 
    224             thick_flat, func_inter, thick_inter, nu_inter, npts_inter): 
     222 
     223SHAPE_FUNCTIONS = [ 
     224    lambda z, nu: erf(nu/sqrt(2)*(2*z-1))/(2*erf(nu/sqrt(2))) + 0.5,  # erf 
     225    lambda z, nu: z**nu,                    # Rpow 
     226    lambda z, nu: 1 - (1-z)**nu,            # Lpow 
     227    lambda z, nu: expm1(-nu*z)/expm1(-nu),  # Rexp 
     228    lambda z, nu: expm1(nu*z)/expm1(nu),    # Lexp 
     229] 
     230 
     231def profile(n_shells, sld_solvent, sld, thickness, 
     232            interface, shape, nu, n_steps): 
    225233    """ 
    226234    Returns shape profile with x=radius, y=SLD. 
     
    228236 
    229237    z = [] 
    230     beta = [] 
     238    rho = [] 
    231239    z0 = 0 
    232240    # two sld points for core 
    233241    z.append(0) 
    234     beta.append(sld_core) 
    235     z.append(radius_core) 
    236     beta.append(sld_core) 
    237     z0 += radius_core 
    238  
    239     for i in range(1, n_shells+2): 
    240         dz = thick_inter[i-1]/npts_inter 
    241         # j=0 for interface, j=1 for flat layer 
    242         for j in range(0, 2): 
    243             # interation for sub-layers 
    244             for n_s in range(0, npts_inter+1): 
    245                 if j == 1: 
    246                     if i == n_shells+1: 
    247                         break 
    248                     # shift half sub thickness for the first point 
    249                     z0 -= dz#/2.0 
    250                     z.append(z0) 
    251                     #z0 -= dz/2.0 
    252                     z0 += thick_flat[i] 
    253                     sld_i = sld_flat[i] 
    254                     beta.append(sld_flat[i]) 
    255                     dz = 0 
    256                 else: 
    257                     nu = nu_inter[i-1] 
    258                     # decide which sld is which, sld_r or sld_l 
    259                     if i == 1: 
    260                         sld_l = sld_core 
    261                     else: 
    262                         sld_l = sld_flat[i-1] 
    263                     if i == n_shells+1: 
    264                         sld_r = sld_solvent 
    265                     else: 
    266                         sld_r = sld_flat[i] 
    267                     # get function type 
    268                     func_idx = func_inter[i-1] 
    269                     # calculate the sld 
    270                     sld_i = intersldfunc(func_idx, npts_inter, n_s, nu, 
    271                                             sld_l, sld_r) 
    272                 # append to the list 
    273                 z.append(z0) 
    274                 beta.append(sld_i) 
    275                 z0 += dz 
    276                 if j == 1: 
    277                     break 
    278     z.append(z0) 
    279     beta.append(sld_solvent) 
    280     z_ext = z0/5.0 
    281     z.append(z0+z_ext) 
    282     beta.append(sld_solvent) 
     242    rho.append(sld[0]) 
     243 
     244    for i in range(0, n_shells): 
     245        z0 += thickness[i] 
     246        z.append(z0) 
     247        rho.append(sld[i]) 
     248        dz = interface[i]/n_steps 
     249        sld_l = sld[i] 
     250        sld_r = sld[i+1] if i < n_shells-1 else sld_solvent 
     251        interface = SHAPE_FUNCTIONS[int(np.clip(shape[i], 0, len(SHAPES)-1))] 
     252        for step in range(1, n_steps+1): 
     253            portion = interface(float(step)/n_steps, max(abs(nu[i]), 1e-14)) 
     254            z0 += dz 
     255            z.append(z0) 
     256            rho.append((sld_r - sld_l)*portion + sld_l) 
     257    z.append(z0*1.2) 
     258    rho.append(sld_solvent) 
    283259    # return sld profile (r, beta) 
    284     return np.asarray(z), np.asarray(beta)*1e-6 
    285  
    286 def ER(n_shells, radius_core, thick_inter0, thick_inter, thick_flat): 
     260    return np.asarray(z), np.asarray(rho)*1e-6 
     261 
     262 
     263def ER(n_shells, thickness, interface): 
    287264    n_shells = int(n_shells) 
    288     total_thickness = thick_inter0 
    289     total_thickness += np.sum(thick_inter[:n_shells], axis=0) 
    290     total_thickness += np.sum(thick_flat[:n_shells], axis=0) 
    291     return total_thickness + radius_core 
     265    total = (np.sum(thickness[:n_shells], axis=1) 
     266             + np.sum(interface[:n_shells], axis=1)) 
     267    return total 
    292268 
    293269 
    294270demo = { 
    295     "n_shells": 4, 
    296     "npts_inter": 35.0, 
    297     "radius_core": 50.0, 
    298     "sld_core": 2.07, 
     271    "n_shells": 5, 
     272    "n_steps": 35.0, 
    299273    "sld_solvent": 1.0, 
    300     "thick_inter0": 50.0, 
    301     "func_inter0": 0, 
    302     "nu_inter0": 2.5, 
    303     "sld_flat":[4.0,3.5,4.0,3.5], 
    304     "thick_flat":[100.0,100.0,100.0,100.0], 
    305     "func_inter":[0,0,0,0], 
    306     "thick_inter":[50.0,50.0,50.0,50.0], 
    307     "nu_inter":[2.5,2.5,2.5,2.5], 
     274    "sld":[2.07,4.0,3.5,4.0,3.5], 
     275    "thickness":[50.0,100.0,100.0,100.0,100.0], 
     276    "interface":[50.0,50.0,50.0,50.0], 
     277    "shape": [0,0,0,0,0], 
     278    "nu":[2.5,2.5,2.5,2.5,2.5], 
    308279    } 
    309280 
     
    312283tests = [ 
    313284    # Accuracy tests based on content in test/utest_extra_models.py 
    314     [{"n_shells":4, 
    315         'npts_inter':35, 
    316         "radius_core":50.0, 
    317         "sld_core":2.07, 
     285    [{"n_shells": 5, 
     286        "n_steps": 35, 
    318287        "sld_solvent": 1.0, 
    319         "sld_flat":[4.0,3.5,4.0,3.5], 
    320         "thick_flat":[100.0,100.0,100.0,100.0], 
    321         "func_inter":[0,0,0,0], 
    322         "thick_inter":[50.0,50.0,50.0,50.0], 
    323         "nu_inter":[2.5,2.5,2.5,2.5] 
     288        "sld": [2.07, 4.0, 3.5, 4.0, 3.5], 
     289        "thickness": [50.0, 100.0, 100.0, 100.0, 100.0], 
     290        "interface": [50]*5, 
     291        "shape": [0]*5, 
     292        "nu": [2.5]*5, 
    324293    }, 0.001, 0.001], 
    325294] 
Note: See TracChangeset for help on using the changeset viewer.