Changes in / [4057e06:8064d5e] in sasmodels


Ignore:
Files:
6 added
6 deleted
3 edited

Legend:

Unmodified
Added
Removed
  • explore/beta/sasfit_compare.py

    r119073a r2a12351b  
    505505    } 
    506506 
    507     Q, IQ = load_sasfit(data_file('sasfit_sphere_schulz_IQD.txt')) 
    508     Q, IQSD = load_sasfit(data_file('sasfit_sphere_schulz_IQSD.txt')) 
    509     Q, IQBD = load_sasfit(data_file('sasfit_sphere_schulz_IQBD.txt')) 
     507    Q, IQ = load_sasfit(data_file('richard_test.txt')) 
     508    Q, IQSD = load_sasfit(data_file('richard_test2.txt')) 
     509    Q, IQBD = load_sasfit(data_file('richard_test3.txt')) 
    510510    target = Theory(Q=Q, F1=None, F2=None, P=IQ, S=None, I=IQSD, Seff=None, Ibeta=IQBD) 
    511511    actual = sphere_r(Q, norm="sasfit", **pars) 
     
    526526    } 
    527527 
    528     Q, IQ = load_sasfit(data_file('sasfit_ellipsoid_shulz_IQD.txt')) 
    529     Q, IQSD = load_sasfit(data_file('sasfit_ellipsoid_shulz_IQSD.txt')) 
    530     Q, IQBD = load_sasfit(data_file('sasfit_ellipsoid_shulz_IQBD.txt')) 
     528    Q, IQ = load_sasfit(data_file('richard_test4.txt')) 
     529    Q, IQSD = load_sasfit(data_file('richard_test5.txt')) 
     530    Q, IQBD = load_sasfit(data_file('richard_test6.txt')) 
    531531    target = Theory(Q=Q, F1=None, F2=None, P=IQ, S=None, I=IQSD, Seff=None, Ibeta=IQBD) 
    532532    actual = ellipsoid_pe(Q, norm="sasfit", **pars) 
  • sasmodels/jitter.py

    r275511c r7d97437  
    11#!/usr/bin/env python 
    2 # -*- coding: utf-8 -*- 
    32""" 
    43Jitter Explorer 
     
    65 
    76Application to explore orientation angle and angular dispersity. 
    8  
    9 From the command line:: 
    10  
    11     # Show docs 
    12     python -m sasmodels.jitter --help 
    13  
    14     # Guyou projection jitter, uniform over 20 degree theta and 10 in phi 
    15     python -m sasmodels.jitter --projection=guyou --dist=uniform --jitter=20,10,0 
    16  
    17 From a jupyter cell:: 
    18  
    19     import ipyvolume as ipv 
    20     from sasmodels import jitter 
    21     import importlib; importlib.reload(jitter) 
    22     jitter.set_plotter("ipv") 
    23  
    24     size = (10, 40, 100) 
    25     view = (20, 0, 0) 
    26  
    27     #size = (15, 15, 100) 
    28     #view = (60, 60, 0) 
    29  
    30     dview = (0, 0, 0) 
    31     #dview = (5, 5, 0) 
    32     #dview = (15, 180, 0) 
    33     #dview = (180, 15, 0) 
    34  
    35     projection = 'equirectangular' 
    36     #projection = 'azimuthal_equidistance' 
    37     #projection = 'guyou' 
    38     #projection = 'sinusoidal' 
    39     #projection = 'azimuthal_equal_area' 
    40  
    41     dist = 'uniform' 
    42     #dist = 'gaussian' 
    43  
    44     jitter.run(size=size, view=view, jitter=dview, dist=dist, projection=projection) 
    45     #filename = projection+('_theta' if dview[0] == 180 else '_phi' if dview[1] == 180 else '') 
    46     #ipv.savefig(filename+'.png') 
    477""" 
    488from __future__ import division, print_function 
     
    5010import argparse 
    5111 
     12try: # CRUFT: travis-ci does not support mpl_toolkits.mplot3d 
     13    import mpl_toolkits.mplot3d  # Adds projection='3d' option to subplot 
     14except ImportError: 
     15    pass 
     16 
     17import matplotlib as mpl 
     18import matplotlib.pyplot as plt 
     19from matplotlib.widgets import Slider 
    5220import numpy as np 
    5321from numpy import pi, cos, sin, sqrt, exp, degrees, radians 
    5422 
    55 def draw_beam(axes, view=(0, 0), alpha=0.5, steps=25): 
     23def draw_beam(axes, view=(0, 0)): 
    5624    """ 
    5725    Draw the beam going from source at (0, 0, 1) to detector at (0, 0, -1) 
    5826    """ 
    5927    #axes.plot([0,0],[0,0],[1,-1]) 
    60     #axes.scatter([0]*100,[0]*100,np.linspace(1, -1, 100), alpha=alpha) 
    61  
     28    #axes.scatter([0]*100,[0]*100,np.linspace(1, -1, 100), alpha=0.8) 
     29 
     30    steps = 25 
    6231    u = np.linspace(0, 2 * np.pi, steps) 
    63     v = np.linspace(-1, 1, 2) 
     32    v = np.linspace(-1, 1, steps) 
    6433 
    6534    r = 0.02 
     
    7342    points = Rz(phi)*Ry(theta)*points 
    7443    x, y, z = [v.reshape(shape) for v in points] 
    75     axes.plot_surface(x, y, z, color='yellow', alpha=alpha) 
    76  
    77     # TODO: draw endcaps on beam 
    78     ## Drawing tiny balls on the end will work 
    79     #draw_sphere(axes, radius=0.02, center=(0, 0, 1.3), color='yellow', alpha=alpha) 
    80     #draw_sphere(axes, radius=0.02, center=(0, 0, -1.3), color='yellow', alpha=alpha) 
    81     ## The following does not work 
    82     #triangles = [(0, i+1, i+2) for i in range(steps-2)] 
    83     #x_cap, y_cap = x[:, 0], y[:, 0] 
    84     #for z_cap in z[:, 0], z[:, -1]: 
    85     #    axes.plot_trisurf(x_cap, y_cap, z_cap, triangles, 
    86     #                      color='yellow', alpha=alpha) 
    87  
     44 
     45    axes.plot_surface(x, y, z, rstride=4, cstride=4, color='y', alpha=0.5) 
    8846 
    8947def draw_ellipsoid(axes, size, view, jitter, steps=25, alpha=1): 
     
    9755    x, y, z = transform_xyz(view, jitter, x, y, z) 
    9856 
    99     axes.plot_surface(x, y, z, color='w', alpha=alpha) 
     57    axes.plot_surface(x, y, z, rstride=4, cstride=4, color='w', alpha=alpha) 
    10058 
    10159    draw_labels(axes, view, jitter, [ 
     
    166124    return atoms 
    167125 
    168 def draw_box(axes, size, view): 
    169     a, b, c = size 
    170     x = a*np.array([+1, -1, +1, -1, +1, -1, +1, -1]) 
    171     y = b*np.array([+1, +1, -1, -1, +1, +1, -1, -1]) 
    172     z = c*np.array([+1, +1, +1, +1, -1, -1, -1, -1]) 
    173     x, y, z = transform_xyz(view, None, x, y, z) 
    174     def draw(i, j): 
    175         axes.plot([x[i],x[j]], [y[i], y[j]], [z[i], z[j]], color='black') 
    176     draw(0, 1) 
    177     draw(0, 2) 
    178     draw(0, 3) 
    179     draw(7, 4) 
    180     draw(7, 5) 
    181     draw(7, 6) 
    182  
    183 def draw_parallelepiped(axes, size, view, jitter, steps=None, 
    184                         color=(0.6, 1.0, 0.6), alpha=1): 
     126def draw_parallelepiped(axes, size, view, jitter, steps=None, alpha=1): 
    185127    """Draw a parallelepiped.""" 
    186128    a, b, c = size 
     
    200142 
    201143    x, y, z = transform_xyz(view, jitter, x, y, z) 
    202     axes.plot_trisurf(x, y, triangles=tri, Z=z, color=color, alpha=alpha, 
    203                       linewidth=0) 
    204  
    205     # Colour the c+ face of the box. 
     144    axes.plot_trisurf(x, y, triangles=tri, Z=z, color='w', alpha=alpha) 
     145 
     146    # Draw pink face on box. 
    206147    # Since I can't control face color, instead draw a thin box situated just 
    207148    # in front of the "c+" face.  Use the c face so that rotations about psi 
    208149    # rotate that face. 
    209     if 0: 
    210         color = (1, 0.6, 0.6)  # pink 
     150    if 1: 
    211151        x = a*np.array([+1, -1, +1, -1, +1, -1, +1, -1]) 
    212152        y = b*np.array([+1, +1, -1, -1, +1, +1, -1, -1]) 
    213153        z = c*np.array([+1, +1, +1, +1, -1, -1, -1, -1]) 
    214154        x, y, z = transform_xyz(view, jitter, x, y, abs(z)+0.001) 
    215         axes.plot_trisurf(x, y, triangles=tri, Z=z, color=color, alpha=alpha) 
     155        axes.plot_trisurf(x, y, triangles=tri, Z=z, color=[1, 0.6, 0.6], alpha=alpha) 
    216156 
    217157    draw_labels(axes, view, jitter, [ 
     
    224164    ]) 
    225165 
    226 def draw_sphere(axes, radius=0.5, steps=25, center=(0,0,0), color='w', alpha=1.): 
     166def draw_sphere(axes, radius=10., steps=100): 
    227167    """Draw a sphere""" 
    228168    u = np.linspace(0, 2 * np.pi, steps) 
    229169    v = np.linspace(0, np.pi, steps) 
    230170 
    231     x = radius * np.outer(np.cos(u), np.sin(v)) + center[0] 
    232     y = radius * np.outer(np.sin(u), np.sin(v)) + center[1] 
    233     z = radius * np.outer(np.ones(np.size(u)), np.cos(v)) + center[2] 
    234     axes.plot_surface(x, y, z, color=color, alpha=alpha) 
    235     #axes.plot_wireframe(x, y, z) 
    236  
    237 def draw_axes(axes, origin=(-1, -1, -1), length=(2, 2, 2)): 
    238     x, y, z = origin 
    239     dx, dy, dz = length 
    240     axes.plot([x, x+dx], [y, y], [z, z], color='black') 
    241     axes.plot([x, x], [y, y+dy], [z, z], color='black') 
    242     axes.plot([x, x], [y, y], [z, z+dz], color='black') 
    243  
    244 def draw_person_on_sphere(axes, view, height=0.5, radius=0.5): 
    245     limb_offset = height * 0.05 
    246     head_radius = height * 0.10 
    247     head_height = height - head_radius 
    248     neck_length = head_radius * 0.50 
    249     shoulder_height = height - 2*head_radius - neck_length 
    250     torso_length = shoulder_height * 0.55 
    251     torso_radius = torso_length * 0.30 
    252     leg_length = shoulder_height - torso_length 
    253     arm_length = torso_length * 0.90 
    254  
    255     def _draw_part(x, z): 
    256         y = np.zeros_like(x) 
    257         xp, yp, zp = transform_xyz(view, None, x, y, z + radius) 
    258         axes.plot(xp, yp, zp, color='k') 
    259  
    260     # circle for head 
    261     u = np.linspace(0, 2 * np.pi, 40) 
    262     x = head_radius * np.cos(u) 
    263     z = head_radius * np.sin(u) + head_height 
    264     _draw_part(x, z) 
    265  
    266     # rectangle for body 
    267     x = np.array([-torso_radius, torso_radius, torso_radius, -torso_radius, -torso_radius]) 
    268     z = np.array([0., 0, torso_length, torso_length, 0]) + leg_length 
    269     _draw_part(x, z) 
    270  
    271     # arms 
    272     x = np.array([-torso_radius - limb_offset, -torso_radius - limb_offset, -torso_radius]) 
    273     z = np.array([shoulder_height - arm_length, shoulder_height, shoulder_height]) 
    274     _draw_part(x, z) 
    275     _draw_part(-x, z) 
    276  
    277     # legs 
    278     x = np.array([-torso_radius + limb_offset, -torso_radius + limb_offset]) 
    279     z = np.array([0, leg_length]) 
    280     _draw_part(x, z) 
    281     _draw_part(-x, z) 
    282  
    283     limits = [-radius-height, radius+height] 
    284     axes.set_xlim(limits) 
    285     axes.set_ylim(limits) 
    286     axes.set_zlim(limits) 
    287     axes.set_axis_off() 
    288  
    289 def draw_jitter(axes, view, jitter, dist='gaussian', 
    290                 size=(0.1, 0.4, 1.0), 
    291                 draw_shape=draw_parallelepiped, 
    292                 projection='equirectangular', 
    293                 alpha=0.8, 
    294                 views=None): 
     171    x = radius * np.outer(np.cos(u), np.sin(v)) 
     172    y = radius * np.outer(np.sin(u), np.sin(v)) 
     173    z = radius * np.outer(np.ones(np.size(u)), np.cos(v)) 
     174    axes.plot_surface(x, y, z, rstride=4, cstride=4, color='w') 
     175 
     176def draw_jitter(axes, view, jitter, dist='gaussian', size=(0.1, 0.4, 1.0), 
     177                draw_shape=draw_parallelepiped): 
    295178    """ 
    296179    Represent jitter as a set of shapes at different orientations. 
    297180    """ 
    298     project, project_weight = get_projection(projection) 
    299  
    300181    # set max diagonal to 0.95 
    301182    scale = 0.95/sqrt(sum(v**2 for v in size)) 
    302183    size = tuple(scale*v for v in size) 
    303184 
     185    #np.random.seed(10) 
     186    #cloud = np.random.randn(10,3) 
     187    cloud = [ 
     188        [-1, -1, -1], 
     189        [-1, -1, +0], 
     190        [-1, -1, +1], 
     191        [-1, +0, -1], 
     192        [-1, +0, +0], 
     193        [-1, +0, +1], 
     194        [-1, +1, -1], 
     195        [-1, +1, +0], 
     196        [-1, +1, +1], 
     197        [+0, -1, -1], 
     198        [+0, -1, +0], 
     199        [+0, -1, +1], 
     200        [+0, +0, -1], 
     201        [+0, +0, +0], 
     202        [+0, +0, +1], 
     203        [+0, +1, -1], 
     204        [+0, +1, +0], 
     205        [+0, +1, +1], 
     206        [+1, -1, -1], 
     207        [+1, -1, +0], 
     208        [+1, -1, +1], 
     209        [+1, +0, -1], 
     210        [+1, +0, +0], 
     211        [+1, +0, +1], 
     212        [+1, +1, -1], 
     213        [+1, +1, +0], 
     214        [+1, +1, +1], 
     215    ] 
    304216    dtheta, dphi, dpsi = jitter 
    305     base = {'gaussian':3, 'rectangle':sqrt(3), 'uniform':1}[dist] 
    306     def steps(delta): 
    307         if views is None: 
    308             n = max(3, min(25, 2*int(base*delta/5))) 
    309         else: 
    310             n = views 
    311         return base*delta*np.linspace(-1, 1, n) if delta > 0 else [0.] 
    312     for theta in steps(dtheta): 
    313         for phi in steps(dphi): 
    314             for psi in steps(dpsi): 
    315                 w = project_weight(theta, phi, 1.0, 1.0) 
    316                 if w > 0: 
    317                     dview = project(theta, phi, psi) 
    318                     draw_shape(axes, size, view, dview, alpha=alpha) 
     217    if dtheta == 0: 
     218        cloud = [v for v in cloud if v[0] == 0] 
     219    if dphi == 0: 
     220        cloud = [v for v in cloud if v[1] == 0] 
     221    if dpsi == 0: 
     222        cloud = [v for v in cloud if v[2] == 0] 
     223    draw_shape(axes, size, view, [0, 0, 0], steps=100, alpha=0.8) 
     224    scale = {'gaussian':1, 'rectangle':1/sqrt(3), 'uniform':1/3}[dist] 
     225    for point in cloud: 
     226        delta = [scale*dtheta*point[0], scale*dphi*point[1], scale*dpsi*point[2]] 
     227        draw_shape(axes, size, view, delta, alpha=0.8) 
    319228    for v in 'xyz': 
    320229        a, b, c = size 
    321230        lim = np.sqrt(a**2 + b**2 + c**2) 
    322231        getattr(axes, 'set_'+v+'lim')([-lim, lim]) 
    323         #getattr(axes, v+'axis').label.set_text(v) 
     232        getattr(axes, v+'axis').label.set_text(v) 
    324233 
    325234PROJECTIONS = [ 
     
    329238    'azimuthal_equal_area', 
    330239] 
    331 def get_projection(projection): 
    332  
    333     """ 
     240def draw_mesh(axes, view, jitter, radius=1.2, n=11, dist='gaussian', 
     241              projection='equirectangular'): 
     242    """ 
     243    Draw the dispersion mesh showing the theta-phi orientations at which 
     244    the model will be evaluated. 
     245 
    334246    jitter projections 
    335247    <https://en.wikipedia.org/wiki/List_of_map_projections> 
     
    387299    # TODO: try Kent distribution instead of a gaussian warped by projection 
    388300 
     301    dist_x = np.linspace(-1, 1, n) 
     302    weights = np.ones_like(dist_x) 
     303    if dist == 'gaussian': 
     304        dist_x *= 3 
     305        weights = exp(-0.5*dist_x**2) 
     306    elif dist == 'rectangle': 
     307        # Note: uses sasmodels ridiculous definition of rectangle width 
     308        dist_x *= sqrt(3) 
     309    elif dist == 'uniform': 
     310        pass 
     311    else: 
     312        raise ValueError("expected dist to be gaussian, rectangle or uniform") 
     313 
    389314    if projection == 'equirectangular':  #define PROJECTION 1 
    390         def _project(theta_i, phi_j, psi): 
    391             latitude, longitude = theta_i, phi_j 
    392             return latitude, longitude, psi 
    393             #return Rx(phi_j)*Ry(theta_i) 
     315        def _rotate(theta_i, phi_j): 
     316            return Rx(phi_j)*Ry(theta_i) 
    394317        def _weight(theta_i, phi_j, w_i, w_j): 
    395318            return w_i*w_j*abs(cos(radians(theta_i))) 
    396319    elif projection == 'sinusoidal':  #define PROJECTION 2 
    397         def _project(theta_i, phi_j, psi): 
     320        def _rotate(theta_i, phi_j): 
    398321            latitude = theta_i 
    399322            scale = cos(radians(latitude)) 
    400323            longitude = phi_j/scale if abs(phi_j) < abs(scale)*180 else 0 
    401324            #print("(%+7.2f, %+7.2f) => (%+7.2f, %+7.2f)"%(theta_i, phi_j, latitude, longitude)) 
    402             return latitude, longitude, psi 
    403             #return Rx(longitude)*Ry(latitude) 
    404         def _project(theta_i, phi_j, w_i, w_j): 
     325            return Rx(longitude)*Ry(latitude) 
     326        def _weight(theta_i, phi_j, w_i, w_j): 
    405327            latitude = theta_i 
    406328            scale = cos(radians(latitude)) 
     
    408330            return active*w_i*w_j 
    409331    elif projection == 'guyou':  #define PROJECTION 3  (eventually?) 
    410         def _project(theta_i, phi_j, psi): 
     332        def _rotate(theta_i, phi_j): 
    411333            from .guyou import guyou_invert 
    412334            #latitude, longitude = guyou_invert([theta_i], [phi_j]) 
    413335            longitude, latitude = guyou_invert([phi_j], [theta_i]) 
    414             return latitude, longitude, psi 
    415             #return Rx(longitude[0])*Ry(latitude[0]) 
     336            return Rx(longitude[0])*Ry(latitude[0]) 
    416337        def _weight(theta_i, phi_j, w_i, w_j): 
    417338            return w_i*w_j 
    418     elif projection == 'azimuthal_equidistance': 
    419         # Note that calculates angles for Rz Ry rather than Rx Ry 
    420         def _project(theta_i, phi_j, psi): 
     339    elif projection == 'azimuthal_equidistance':  # Note: Rz Ry, not Rx Ry 
     340        def _rotate(theta_i, phi_j): 
    421341            latitude = sqrt(theta_i**2 + phi_j**2) 
    422342            longitude = degrees(np.arctan2(phi_j, theta_i)) 
    423343            #print("(%+7.2f, %+7.2f) => (%+7.2f, %+7.2f)"%(theta_i, phi_j, latitude, longitude)) 
    424             return latitude, longitude, psi-longitude, 'zyz' 
    425             #R = Rz(longitude)*Ry(latitude)*Rz(psi) 
    426             #return R_to_xyz(R) 
    427             #return Rz(longitude)*Ry(latitude) 
     344            return Rz(longitude)*Ry(latitude) 
    428345        def _weight(theta_i, phi_j, w_i, w_j): 
    429346            # Weighting for each point comes from the integral: 
     
    459376            return weight*w_i*w_j if latitude < 180 else 0 
    460377    elif projection == 'azimuthal_equal_area': 
    461         # Note that calculates angles for Rz Ry rather than Rx Ry 
    462         def _project(theta_i, phi_j, psi): 
     378        def _rotate(theta_i, phi_j): 
    463379            radius = min(1, sqrt(theta_i**2 + phi_j**2)/180) 
    464380            latitude = 180-degrees(2*np.arccos(radius)) 
    465381            longitude = degrees(np.arctan2(phi_j, theta_i)) 
    466382            #print("(%+7.2f, %+7.2f) => (%+7.2f, %+7.2f)"%(theta_i, phi_j, latitude, longitude)) 
    467             return latitude, longitude, psi, "zyz" 
    468             #R = Rz(longitude)*Ry(latitude)*Rz(psi) 
    469             #return R_to_xyz(R) 
    470             #return Rz(longitude)*Ry(latitude) 
     383            return Rz(longitude)*Ry(latitude) 
    471384        def _weight(theta_i, phi_j, w_i, w_j): 
    472385            latitude = sqrt(theta_i**2 + phi_j**2) 
     
    476389        raise ValueError("unknown projection %r"%projection) 
    477390 
    478     return _project, _weight 
    479  
    480 def R_to_xyz(R): 
    481     """ 
    482     Return phi, theta, psi Tait-Bryan angles corresponding to the given rotation matrix. 
    483  
    484     Extracting Euler Angles from a Rotation Matrix 
    485     Mike Day, Insomniac Games 
    486     https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2012/07/euler-angles1.pdf 
    487     Based on: Shoemake’s "Euler Angle Conversion", Graphics Gems IV, pp.  222-229 
    488     """ 
    489     phi = np.arctan2(R[1, 2], R[2, 2]) 
    490     theta = np.arctan2(-R[0, 2], np.sqrt(R[0, 0]**2 + R[0, 1]**2)) 
    491     psi = np.arctan2(R[0, 1], R[0, 0]) 
    492     return np.degrees(phi), np.degrees(theta), np.degrees(psi) 
    493  
    494 def draw_mesh(axes, view, jitter, radius=1.2, n=11, dist='gaussian', 
    495               projection='equirectangular'): 
    496     """ 
    497     Draw the dispersion mesh showing the theta-phi orientations at which 
    498     the model will be evaluated. 
    499     """ 
    500  
    501     _project, _weight = get_projection(projection) 
    502     def _rotate(theta, phi, z): 
    503         dview = _project(theta, phi, 0.) 
    504         if len(dview) == 4: # hack for zyz coords 
    505             return Rz(dview[1])*Ry(dview[0])*z 
    506         else: 
    507             return Rx(dview[1])*Ry(dview[0])*z 
    508  
    509  
    510     dist_x = np.linspace(-1, 1, n) 
    511     weights = np.ones_like(dist_x) 
    512     if dist == 'gaussian': 
    513         dist_x *= 3 
    514         weights = exp(-0.5*dist_x**2) 
    515     elif dist == 'rectangle': 
    516         # Note: uses sasmodels ridiculous definition of rectangle width 
    517         dist_x *= sqrt(3) 
    518     elif dist == 'uniform': 
    519         pass 
    520     else: 
    521         raise ValueError("expected dist to be gaussian, rectangle or uniform") 
    522  
    523391    # mesh in theta, phi formed by rotating z 
    524392    dtheta, dphi, dpsi = jitter 
    525393    z = np.matrix([[0], [0], [radius]]) 
    526     points = np.hstack([_rotate(theta_i, phi_j, z) 
     394    points = np.hstack([_rotate(theta_i, phi_j)*z 
    527395                        for theta_i in dtheta*dist_x 
    528396                        for phi_j in dphi*dist_x]) 
     
    602470    Points are stored in a 3 x n numpy matrix, not a numpy array or tuple. 
    603471    """ 
    604     if jitter is None: 
    605         return points 
    606     # Hack to deal with the fact that azimuthal_equidistance uses euler angles 
    607     if len(jitter) == 4: 
    608         dtheta, dphi, dpsi, _ = jitter 
    609         points = Rz(dphi)*Ry(dtheta)*Rz(dpsi)*points 
    610     else: 
    611         dtheta, dphi, dpsi = jitter 
    612         points = Rx(dphi)*Ry(dtheta)*Rz(dpsi)*points 
     472    dtheta, dphi, dpsi = jitter 
     473    points = Rx(dphi)*Ry(dtheta)*Rz(dpsi)*points 
    613474    return points 
    614475 
     
    620481    """ 
    621482    theta, phi, psi = view 
    622     points = Rz(phi)*Ry(theta)*Rz(psi)*points # viewing angle 
    623     #points = Rz(psi)*Ry(pi/2-theta)*Rz(phi)*points # 1-D integration angles 
    624     #points = Rx(phi)*Ry(theta)*Rz(psi)*points  # angular dispersion angle 
     483    points = Rz(phi)*Ry(theta)*Rz(psi)*points 
    625484    return points 
    626  
    627 def orient_relative_to_beam_quaternion(view, points): 
    628     """ 
    629     Apply the view transform to a set of points. 
    630  
    631     Points are stored in a 3 x n numpy matrix, not a numpy array or tuple. 
    632  
    633     This variant uses quaternions rather than rotation matrices for the 
    634     computation.  It works but it is not used because it doesn't solve 
    635     any problems.  The challenge of mapping theta/phi/psi to SO(3) does 
    636     not disappear by calculating the transform differently. 
    637     """ 
    638     theta, phi, psi = view 
    639     x, y, z = [1, 0, 0], [0, 1, 0], [0, 0, 1] 
    640     q = Quaternion(1, [0, 0, 0]) 
    641     ## Compose a rotation about the three axes by rotating 
    642     ## the unit vectors before applying the rotation. 
    643     #q = Quaternion.from_angle_axis(theta, q.rot(x)) * q 
    644     #q = Quaternion.from_angle_axis(phi, q.rot(y)) * q 
    645     #q = Quaternion.from_angle_axis(psi, q.rot(z)) * q 
    646     ## The above turns out to be equivalent to reversing 
    647     ## the order of application, so ignore it and use below. 
    648     q = q * Quaternion.from_angle_axis(theta, x) 
    649     q = q * Quaternion.from_angle_axis(phi, y) 
    650     q = q * Quaternion.from_angle_axis(psi, z) 
    651     ## Reverse the order by post-multiply rather than pre-multiply 
    652     #q = Quaternion.from_angle_axis(theta, x) * q 
    653     #q = Quaternion.from_angle_axis(phi, y) * q 
    654     #q = Quaternion.from_angle_axis(psi, z) * q 
    655     #print("axes psi", q.rot(np.matrix([x, y, z]).T)) 
    656     return q.rot(points) 
    657 #orient_relative_to_beam = orient_relative_to_beam_quaternion 
    658  
    659 # Simple stand-alone quaternion class 
    660 import numpy as np 
    661 from copy import copy 
    662 class Quaternion(object): 
    663     def __init__(self, w, r): 
    664          self.w = w 
    665          self.r = np.asarray(r, dtype='d') 
    666     @staticmethod 
    667     def from_angle_axis(theta, r): 
    668          theta = np.radians(theta)/2 
    669          r = np.asarray(r) 
    670          w = np.cos(theta) 
    671          r = np.sin(theta)*r/np.dot(r,r) 
    672          return Quaternion(w, r) 
    673     def __mul__(self, other): 
    674         if isinstance(other, Quaternion): 
    675             w = self.w*other.w - np.dot(self.r, other.r) 
    676             r = self.w*other.r + other.w*self.r + np.cross(self.r, other.r) 
    677             return Quaternion(w, r) 
    678     def rot(self, v): 
    679         v = np.asarray(v).T 
    680         use_transpose = (v.shape[-1] != 3) 
    681         if use_transpose: v = v.T 
    682         v = v + np.cross(2*self.r, np.cross(self.r, v) + self.w*v) 
    683         #v = v + 2*self.w*np.cross(self.r, v) + np.cross(2*self.r, np.cross(self.r, v)) 
    684         if use_transpose: v = v.T 
    685         return v.T 
    686     def conj(self): 
    687         return Quaternion(self.w, -self.r) 
    688     def inv(self): 
    689         return self.conj()/self.norm()**2 
    690     def norm(self): 
    691         return np.sqrt(self.w**2 + np.sum(self.r**2)) 
    692     def __str__(self): 
    693         return "%g%+gi%+gj%+gk"%(self.w, self.r[0], self.r[1], self.r[2]) 
    694 def test_qrot(): 
    695     # Define rotation of 60 degrees around an axis in y-z that is 60 degrees from y. 
    696     # The rotation axis is determined by rotating the point [0, 1, 0] about x. 
    697     ax = Quaternion.from_angle_axis(60, [1, 0, 0]).rot([0, 1, 0]) 
    698     q = Quaternion.from_angle_axis(60, ax) 
    699     # Set the point to be rotated, and its expected rotated position. 
    700     p = [1, -1, 2] 
    701     target = [(10+4*np.sqrt(3))/8, (1+2*np.sqrt(3))/8, (14-3*np.sqrt(3))/8] 
    702     #print(q, q.rot(p) - target) 
    703     assert max(abs(q.rot(p) - target)) < 1e-14 
    704 #test_qrot() 
    705 #import sys; sys.exit() 
    706485 
    707486# translate between number of dimension of dispersity and the number of 
     
    777556        vmin = vmax*10**-7 
    778557        #vmin, vmax = clipped_range(Iqxy, portion=portion, mode='top') 
    779     #vmin, vmax = Iqxy.min(), Iqxy.max() 
    780558    #print("range",(vmin,vmax)) 
    781559    #qx, qy = np.meshgrid(qx, qy) 
    782560    if 0: 
    783         from matplotlib import cm 
    784561        level = np.asarray(255*(Iqxy - vmin)/(vmax - vmin), 'i') 
    785562        level[level < 0] = 0 
    786563        colors = plt.get_cmap()(level) 
    787         #colors = cm.coolwarm(level) 
    788         #colors = cm.gist_yarg(level) 
    789         #colors = cm.Wistia(level) 
    790         colors[level<=0, 3] = 0.  # set floor to transparent 
    791         x, y = np.meshgrid(qx/qx.max(), qy/qy.max()) 
    792         axes.plot_surface(x, y, -1.1*np.ones_like(x), facecolors=colors) 
     564        axes.plot_surface(qx, qy, -1.1, rstride=1, cstride=1, facecolors=colors) 
    793565    elif 1: 
    794566        axes.contourf(qx/qx.max(), qy/qy.max(), Iqxy, zdir='z', offset=-1.1, 
     
    920692} 
    921693 
    922  
    923694def run(model_name='parallelepiped', size=(10, 40, 100), 
    924         view=(0, 0, 0), jitter=(0, 0, 0), 
    925695        dist='gaussian', mesh=30, 
    926696        projection='equirectangular'): 
     
    932702 
    933703    *size* gives the dimensions (a, b, c) of the shape. 
    934  
    935     *view* gives the initial view (theta, phi, psi) of the shape. 
    936  
    937     *view* gives the initial jitter (dtheta, dphi, dpsi) of the shape. 
    938704 
    939705    *dist* is the type of dispersition: gaussian, rectangle, or uniform. 
     
    955721    calculator, size = select_calculator(model_name, n=150, size=size) 
    956722    draw_shape = DRAW_SHAPES.get(model_name, draw_parallelepiped) 
    957     #draw_shape = draw_fcc 
    958723 
    959724    ## uncomment to set an independent the colour range for every view 
     
    961726    calculator.limits = None 
    962727 
    963     PLOT_ENGINE(calculator, draw_shape, size, view, jitter, dist, mesh, projection) 
    964  
    965 def mpl_plot(calculator, draw_shape, size, view, jitter, dist, mesh, projection): 
    966     # Note: travis-ci does not support mpl_toolkits.mplot3d, but this shouldn't be 
    967     # an issue since we are lazy-loading the package on a path that isn't tested. 
    968     import mpl_toolkits.mplot3d  # Adds projection='3d' option to subplot 
    969     import matplotlib as mpl 
    970     import matplotlib.pyplot as plt 
    971     from matplotlib.widgets import Slider 
    972      
     728    ## initial view 
     729    #theta, dtheta = 70., 10. 
     730    #phi, dphi = -45., 3. 
     731    #psi, dpsi = -45., 3. 
     732    theta, phi, psi = 0, 0, 0 
     733    dtheta, dphi, dpsi = 0, 0, 0 
     734 
    973735    ## create the plot window 
    974736    #plt.hold(True) 
     
    985747        pass 
    986748 
    987  
    988749    # CRUFT: use axisbg instead of facecolor for matplotlib<2 
    989750    facecolor_prop = 'facecolor' if mpl.__version__ > '2' else 'axisbg' 
     
    1001762    axes_dphi = plt.axes([0.75, 0.1, 0.15, 0.04], **props) 
    1002763    axes_dpsi = plt.axes([0.75, 0.05, 0.15, 0.04], **props) 
    1003  
    1004764    # Note: using ridiculous definition of rectangle distribution, whose width 
    1005765    # in sasmodels is sqrt(3) times the given width.  Divide by sqrt(3) to keep 
    1006766    # the maximum width to 90. 
    1007767    dlimit = DIST_LIMITS[dist] 
    1008     sdtheta = Slider(axes_dtheta, u'Δξ', 0, 2*dlimit, valinit=0) 
    1009     sdphi = Slider(axes_dphi, u'Δφ', 0, 2*dlimit, valinit=0) 
    1010     sdpsi = Slider(axes_dpsi, u'Δψ', 0, 2*dlimit, valinit=0) 
    1011  
    1012     ## initial view and jitter 
    1013     theta, phi, psi = view 
    1014     stheta.set_val(theta) 
    1015     sphi.set_val(phi) 
    1016     spsi.set_val(psi) 
    1017     dtheta, dphi, dpsi = jitter 
    1018     sdtheta.set_val(dtheta) 
    1019     sdphi.set_val(dphi) 
    1020     sdpsi.set_val(dpsi) 
     768    sdtheta = Slider(axes_dtheta, 'dTheta', 0, 2*dlimit, valinit=dtheta) 
     769    sdphi = Slider(axes_dphi, 'dPhi', 0, 2*dlimit, valinit=dphi) 
     770    sdpsi = Slider(axes_dpsi, 'dPsi', 0, 2*dlimit, valinit=dpsi) 
     771 
    1021772 
    1022773    ## callback to draw the new view 
     
    1026777        # set small jitter as 0 if multiple pd dims 
    1027778        dims = sum(v > 0 for v in jitter) 
    1028         limit = [0, 0.5, 5, 5][dims] 
     779        limit = [0, 0.5, 5][dims] 
    1029780        jitter = [0 if v < limit else v for v in jitter] 
    1030781        axes.cla() 
    1031  
    1032         ## Visualize as person on globe 
    1033         #draw_sphere(axes) 
    1034         #draw_person_on_sphere(axes, view) 
    1035  
    1036         ## Move beam instead of shape 
    1037         #draw_beam(axes, -view[:2]) 
    1038         #draw_jitter(axes, (0,0,0), (0,0,0), views=3) 
    1039  
    1040         ## Move shape and draw scattering 
    1041         draw_beam(axes, (0, 0), alpha=1.) 
    1042         draw_jitter(axes, view, jitter, dist=dist, size=size, alpha=1., 
    1043                     draw_shape=draw_shape, projection=projection, views=3) 
     782        draw_beam(axes, (0, 0)) 
     783        draw_jitter(axes, view, jitter, dist=dist, size=size, draw_shape=draw_shape) 
     784        #draw_jitter(axes, view, (0,0,0)) 
    1044785        draw_mesh(axes, view, jitter, dist=dist, n=mesh, projection=projection) 
    1045786        draw_scattering(calculator, axes, view, jitter, dist=dist) 
    1046  
    1047787        plt.gcf().canvas.draw() 
    1048788 
     
    1060800    ## go interactive 
    1061801    plt.show() 
    1062  
    1063  
    1064 def map_colors(z, kw): 
    1065     from matplotlib import cm 
    1066  
    1067     cmap = kw.pop('cmap', cm.coolwarm) 
    1068     alpha = kw.pop('alpha', None) 
    1069     vmin = kw.pop('vmin', z.min()) 
    1070     vmax = kw.pop('vmax', z.max()) 
    1071     c = kw.pop('c', None) 
    1072     color = kw.pop('color', c) 
    1073     if color is None: 
    1074         znorm = ((z - vmin) / (vmax - vmin)).clip(0, 1) 
    1075         color = cmap(znorm) 
    1076     elif isinstance(color, np.ndarray) and color.shape == z.shape: 
    1077         color = cmap(color) 
    1078     if alpha is None: 
    1079         if isinstance(color, np.ndarray): 
    1080             color = color[..., :3] 
    1081     else: 
    1082         color[..., 3] = alpha 
    1083     kw['color'] = color 
    1084  
    1085 def make_vec(*args): 
    1086     #return [np.asarray(v, 'd').flatten() for v in args] 
    1087     return [np.asarray(v, 'd') for v in args] 
    1088  
    1089 def make_image(z, kw): 
    1090     import PIL.Image 
    1091     from matplotlib import cm 
    1092  
    1093     cmap = kw.pop('cmap', cm.coolwarm) 
    1094  
    1095     znorm = (z-z.min())/z.ptp() 
    1096     c = cmap(znorm) 
    1097     c = c[..., :3] 
    1098     rgb = np.asarray(c*255, 'u1') 
    1099     image = PIL.Image.fromarray(rgb, mode='RGB') 
    1100     return image 
    1101  
    1102  
    1103 _IPV_MARKERS = { 
    1104     'o': 'sphere', 
    1105 } 
    1106 _IPV_COLORS = { 
    1107     'w': 'white', 
    1108     'k': 'black', 
    1109     'c': 'cyan', 
    1110     'm': 'magenta', 
    1111     'y': 'yellow', 
    1112     'r': 'red', 
    1113     'g': 'green', 
    1114     'b': 'blue', 
    1115 } 
    1116 def ipv_fix_color(kw): 
    1117     alpha = kw.pop('alpha', None) 
    1118     color = kw.get('color', None) 
    1119     if isinstance(color, str): 
    1120         color = _IPV_COLORS.get(color, color) 
    1121         kw['color'] = color 
    1122     if alpha is not None: 
    1123         color = kw['color'] 
    1124         #TODO: convert color to [r, g, b, a] if not already 
    1125         if isinstance(color, (tuple, list)): 
    1126             if len(color) == 3: 
    1127                 color = (color[0], color[1], color[2], alpha) 
    1128             else: 
    1129                 color = (color[0], color[1], color[2], alpha*color[3]) 
    1130             color = np.array(color) 
    1131         if isinstance(color, np.ndarray) and color.shape[-1] == 4: 
    1132             color[..., 3] = alpha 
    1133             kw['color'] = color 
    1134  
    1135 def ipv_set_transparency(kw, obj): 
    1136     color = kw.get('color', None) 
    1137     if (isinstance(color, np.ndarray) 
    1138             and color.shape[-1] == 4 
    1139             and (color[..., 3] != 1.0).any()): 
    1140         obj.material.transparent = True 
    1141         obj.material.side = "FrontSide" 
    1142  
    1143 def ipv_axes(): 
    1144     import ipyvolume as ipv 
    1145  
    1146     class Plotter: 
    1147         # transparency can be achieved by setting the following: 
    1148         #    mesh.color = [r, g, b, alpha] 
    1149         #    mesh.material.transparent = True 
    1150         #    mesh.material.side = "FrontSide" 
    1151         # smooth(ish) rotation can be achieved by setting: 
    1152         #    slide.continuous_update = True 
    1153         #    figure.animation = 0. 
    1154         #    mesh.material.x = x 
    1155         #    mesh.material.y = y 
    1156         #    mesh.material.z = z 
    1157         # maybe need to synchronize update of x/y/z to avoid shimmy when moving 
    1158         def plot(self, x, y, z, **kw): 
    1159             ipv_fix_color(kw) 
    1160             x, y, z = make_vec(x, y, z) 
    1161             ipv.plot(x, y, z, **kw) 
    1162         def plot_surface(self, x, y, z, **kw): 
    1163             facecolors = kw.pop('facecolors', None) 
    1164             if facecolors is not None: 
    1165                 kw['color'] = facecolors 
    1166             ipv_fix_color(kw) 
    1167             x, y, z = make_vec(x, y, z) 
    1168             h = ipv.plot_surface(x, y, z, **kw) 
    1169             ipv_set_transparency(kw, h) 
    1170             #h.material.side = "DoubleSide" 
    1171             return h 
    1172         def plot_trisurf(self, x, y, triangles=None, Z=None, **kw): 
    1173             kw.pop('linewidth', None) 
    1174             ipv_fix_color(kw) 
    1175             x, y, z = make_vec(x, y, Z) 
    1176             if triangles is not None: 
    1177                 triangles = np.asarray(triangles) 
    1178             h = ipv.plot_trisurf(x, y, z, triangles=triangles, **kw) 
    1179             ipv_set_transparency(kw, h) 
    1180             return h 
    1181         def scatter(self, x, y, z, **kw): 
    1182             x, y, z = make_vec(x, y, z) 
    1183             map_colors(z, kw) 
    1184             marker = kw.get('marker', None) 
    1185             kw['marker'] = _IPV_MARKERS.get(marker, marker) 
    1186             h = ipv.scatter(x, y, z, **kw) 
    1187             ipv_set_transparency(kw, h) 
    1188             return h 
    1189         def contourf(self, x, y, v, zdir='z', offset=0, levels=None, **kw): 
    1190             # Don't use contour for now (although we might want to later) 
    1191             self.pcolor(x, y, v, zdir='z', offset=offset, **kw) 
    1192         def pcolor(self, x, y, v, zdir='z', offset=0, **kw): 
    1193             x, y, v = make_vec(x, y, v) 
    1194             image = make_image(v, kw) 
    1195             xmin, xmax = x.min(), x.max() 
    1196             ymin, ymax = y.min(), y.max() 
    1197             x = np.array([[xmin, xmax], [xmin, xmax]]) 
    1198             y = np.array([[ymin, ymin], [ymax, ymax]]) 
    1199             z = x*0 + offset 
    1200             u = np.array([[0., 1], [0, 1]]) 
    1201             v = np.array([[0., 0], [1, 1]]) 
    1202             h = ipv.plot_mesh(x, y, z, u=u, v=v, texture=image, wireframe=False) 
    1203             ipv_set_transparency(kw, h) 
    1204             h.material.side = "DoubleSide" 
    1205             return h 
    1206         def text(self, *args, **kw): 
    1207             pass 
    1208         def set_xlim(self, limits): 
    1209             ipv.xlim(*limits) 
    1210         def set_ylim(self, limits): 
    1211             ipv.ylim(*limits) 
    1212         def set_zlim(self, limits): 
    1213             ipv.zlim(*limits) 
    1214         def set_axes_on(self): 
    1215             ipv.style.axis_on() 
    1216         def set_axis_off(self): 
    1217             ipv.style.axes_off() 
    1218     return Plotter() 
    1219  
    1220 def ipv_plot(calculator, draw_shape, size, view, jitter, dist, mesh, projection): 
    1221     import ipywidgets as widgets 
    1222     import ipyvolume as ipv 
    1223  
    1224     axes = ipv_axes() 
    1225  
    1226     def draw(view, jitter): 
    1227         camera = ipv.gcf().camera 
    1228         #print(ipv.gcf().__dict__.keys()) 
    1229         #print(dir(ipv.gcf())) 
    1230         ipv.figure(animation=0.)  # no animation when updating object mesh 
    1231  
    1232         # set small jitter as 0 if multiple pd dims 
    1233         dims = sum(v > 0 for v in jitter) 
    1234         limit = [0, 0.5, 5, 5][dims] 
    1235         jitter = [0 if v < limit else v for v in jitter] 
    1236  
    1237         ## Visualize as person on globe 
    1238         #draw_beam(axes, (0, 0)) 
    1239         #draw_sphere(axes) 
    1240         #draw_person_on_sphere(axes, view) 
    1241  
    1242         ## Move beam instead of shape 
    1243         #draw_beam(axes, view=(-view[0], -view[1])) 
    1244         #draw_jitter(axes, view=(0,0,0), jitter=(0,0,0)) 
    1245  
    1246         ## Move shape and draw scattering 
    1247         draw_beam(axes, (0, 0), steps=25) 
    1248         draw_jitter(axes, view, jitter, dist=dist, size=size, alpha=1.0, 
    1249                     draw_shape=draw_shape, projection=projection) 
    1250         draw_mesh(axes, view, jitter, dist=dist, n=mesh, radius=0.95, 
    1251                   projection=projection) 
    1252         draw_scattering(calculator, axes, view, jitter, dist=dist) 
    1253  
    1254         draw_axes(axes, origin=(-1, -1, -1.1)) 
    1255         ipv.style.box_off() 
    1256         ipv.style.axes_off() 
    1257         ipv.xyzlabel(" ", " ", " ") 
    1258  
    1259         ipv.gcf().camera = camera 
    1260         ipv.show() 
    1261  
    1262  
    1263     trange, prange = (-180., 180., 1.), (-180., 180., 1.) 
    1264     dtrange, dprange = (0., 180., 1.), (0., 180., 1.) 
    1265  
    1266     ## Super simple interfaca, but uses non-ascii variable namese 
    1267     # Ξ φ ψ Δξ Δφ Δψ 
    1268     #def update(**kw): 
    1269     #    view = kw['Ξ'], kw['φ'], kw['ψ'] 
    1270     #    jitter = kw['Δξ'], kw['Δφ'], kw['Δψ'] 
    1271     #    draw(view, jitter) 
    1272     #widgets.interact(update, Ξ=trange, φ=prange, ψ=prange, Δξ=dtrange, Δφ=dprange, Δψ=dprange) 
    1273  
    1274     def update(theta, phi, psi, dtheta, dphi, dpsi): 
    1275         draw(view=(theta, phi, psi), jitter=(dtheta, dphi, dpsi)) 
    1276  
    1277     def slider(name, slice, init=0.): 
    1278         return widgets.FloatSlider( 
    1279             value=init, 
    1280             min=slice[0], 
    1281             max=slice[1], 
    1282             step=slice[2], 
    1283             description=name, 
    1284             disabled=False, 
    1285             #continuous_update=True, 
    1286             continuous_update=False, 
    1287             orientation='horizontal', 
    1288             readout=True, 
    1289             readout_format='.1f', 
    1290             ) 
    1291     theta = slider(u'Ξ', trange, view[0]) 
    1292     phi = slider(u'φ', prange, view[1]) 
    1293     psi = slider(u'ψ', prange, view[2]) 
    1294     dtheta = slider(u'Δξ', dtrange, jitter[0]) 
    1295     dphi = slider(u'Δφ', dprange, jitter[1]) 
    1296     dpsi = slider(u'Δψ', dprange, jitter[2]) 
    1297     fields = { 
    1298         'theta': theta, 'phi': phi, 'psi': psi, 
    1299         'dtheta': dtheta, 'dphi': dphi, 'dpsi': dpsi, 
    1300     } 
    1301     ui = widgets.HBox([ 
    1302         widgets.VBox([theta, phi, psi]), 
    1303         widgets.VBox([dtheta, dphi, dpsi]) 
    1304     ]) 
    1305  
    1306     out = widgets.interactive_output(update, fields) 
    1307     display(ui, out) 
    1308  
    1309  
    1310 _ENGINES = { 
    1311     "matplotlib": mpl_plot, 
    1312     "mpl": mpl_plot, 
    1313     #"plotly": plotly_plot, 
    1314     "ipvolume": ipv_plot, 
    1315     "ipv": ipv_plot, 
    1316 } 
    1317 PLOT_ENGINE = _ENGINES["matplotlib"] 
    1318 def set_plotter(name): 
    1319     global PLOT_ENGINE 
    1320     PLOT_ENGINE = _ENGINES[name] 
    1321802 
    1322803def main(): 
     
    1330811    parser.add_argument('-s', '--size', type=str, default='10,40,100', 
    1331812                        help='a,b,c lengths') 
    1332     parser.add_argument('-v', '--view', type=str, default='0,0,0', 
    1333                         help='initial view angles') 
    1334     parser.add_argument('-j', '--jitter', type=str, default='0,0,0', 
    1335                         help='initial angular dispersion') 
    1336813    parser.add_argument('-d', '--distribution', choices=DISTRIBUTIONS, 
    1337814                        default=DISTRIBUTIONS[0], 
     
    1342819                        help='oriented shape') 
    1343820    opts = parser.parse_args() 
    1344     size = tuple(float(v) for v in opts.size.split(',')) 
    1345     view = tuple(float(v) for v in opts.view.split(',')) 
    1346     jitter = tuple(float(v) for v in opts.jitter.split(',')) 
    1347     run(opts.shape, size=size, view=view, jitter=jitter, 
     821    size = tuple(int(v) for v in opts.size.split(',')) 
     822    run(opts.shape, size=size, 
    1348823        mesh=opts.mesh, dist=opts.distribution, 
    1349824        projection=opts.projection) 
  • sasmodels/models/pearl_necklace.c

    r9b5fd42 r99658f6  
    4040    const double si = sas_sinx_x(q*A_s); 
    4141    const double omsi = 1.0 - si; 
    42     const double pow_si = pown(si, num_pearls); 
     42    const double pow_si = pow(si, num_pearls); 
    4343 
    4444    // form factor for num_pearls 
     
    8181radius_from_volume(double radius, double edge_sep, double thick_string, double fp_num_pearls) 
    8282{ 
     83    const int num_pearls = (int) fp_num_pearls +0.5; 
    8384    const double vol_tot = form_volume(radius, edge_sep, thick_string, fp_num_pearls); 
    8485    return cbrt(vol_tot/M_4PI_3); 
Note: See TracChangeset for help on using the changeset viewer.