source: sasmodels/explore/beta/sasfit_compare.py @ 01c8d9e

core_shell_microgelsmagnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 01c8d9e was 01c8d9e, checked in by Suczewski <ges3@…>, 6 years ago

beta approximation, first pass

  • Property mode set to 100644
File size: 29.3 KB
Line 
1from __future__ import division, print_function
2# Make sasmodels available on the path
3import sys,os
4BETA_DIR = os.path.dirname(os.path.realpath(__file__))
5#SASMODELS_DIR = os.path.dirname(os.path.dirname(BETA_DIR))
6SASMODELS_DIR = r"C:\Source\sasmodels"
7sys.path.insert(0, SASMODELS_DIR)
8import os
9from collections import namedtuple
10
11from matplotlib import pyplot as plt
12import numpy as np
13from numpy import pi, sin, cos, sqrt, fabs
14from numpy.polynomial.legendre import leggauss
15from scipy.special import j1 as J1
16from numpy import inf
17from scipy.special import gammaln  # type: ignore
18
19Theory = namedtuple('Theory', 'Q F1 F2 P S I Seff Ibeta')
20Theory.__new__.__defaults__ = (None,) * len(Theory._fields)
21
22#Used to calculate F(q) for the cylinder, sphere, ellipsoid models
23def sas_sinx_x(x):
24    with np.errstate(all='ignore'):
25        retvalue = sin(x)/x
26    retvalue[x == 0.] = 1.
27    return retvalue
28
29def sas_2J1x_x(x):
30    with np.errstate(all='ignore'):
31        retvalue = 2*J1(x)/x
32    retvalue[x == 0] = 1.
33    return retvalue
34
35def sas_3j1x_x(x):
36    """return 3*j1(x)/x"""
37    retvalue = np.empty_like(x)
38    with np.errstate(all='ignore'):
39        # GSL bessel_j1 taylor expansion
40        index = (x < 0.25)
41        y = x[index]**2
42        c1 = -1.0/10.0
43        c2 =  1.0/280.0
44        c3 = -1.0/15120.0
45        c4 =  1.0/1330560.0
46        c5 = -1.0/172972800.0
47        retvalue[index] = 1.0 + y*(c1 + y*(c2 + y*(c3 + y*(c4 + y*c5))))
48        index = ~index
49        y = x[index]
50        retvalue[index] = 3*(sin(y) - y*cos(y))/y**3
51    retvalue[x == 0.] = 1.
52    return retvalue
53
54#Used to cross check my models with sasview models
55def build_model(model_name, q, **pars):
56    from sasmodels.core import load_model_info, build_model as build_sasmodel
57    from sasmodels.data import empty_data1D
58    from sasmodels.direct_model import DirectModel
59    model_info = load_model_info(model_name)
60    model = build_sasmodel(model_info, dtype='double!')
61    data = empty_data1D(q)
62    calculator = DirectModel(data, model,cutoff=0)
63    calculator.pars = pars.copy()
64    calculator.pars.setdefault('background', 0)
65    return calculator
66
67#gives the hardsphere structure factor that sasview uses
68def _hardsphere_simple(q, radius_effective, volfraction):
69    CUTOFFHS=0.05
70    if fabs(radius_effective) < 1.E-12:
71        HARDSPH=1.0
72        return HARDSPH
73    X = 1.0/( 1.0 -volfraction)
74    D= X*X
75    A= (1.+2.*volfraction)*D
76    A *=A
77    X=fabs(q*radius_effective*2.0)
78    if X < 5.E-06:
79        HARDSPH=1./A
80        return HARDSPH
81    X2 =X*X
82    B = (1.0 +0.5*volfraction)*D
83    B *= B
84    B *= -6.*volfraction
85    G=0.5*volfraction*A
86    if X < CUTOFFHS:
87        FF = 8.0*A +6.0*B + 4.0*G + ( -0.8*A -B/1.5 -0.5*G +(A/35. +0.0125*B +0.02*G)*X2)*X2
88        HARDSPH= 1./(1. + volfraction*FF )
89        return HARDSPH
90    X4=X2*X2
91    S, C = sin(X), cos(X)
92    FF=  (( G*( (4.*X2 -24.)*X*S -(X4 -12.*X2 +24.)*C +24. )/X2 + B*(2.*X*S -(X2-2.)*C -2.) )/X + A*(S-X*C))/X
93    HARDSPH= 1./(1. + 24.*volfraction*FF/X2 )
94    return HARDSPH
95
96def hardsphere_simple(q, radius_effective, volfraction):
97    SQ = [_hardsphere_simple(qk, radius_effective, volfraction) for qk in q]
98    return np.array(SQ)
99
100#Used in gaussian quadrature for polydispersity
101#returns values and the probability of those values based on gaussian distribution
102N_GAUSS = 35
103NSIGMA_GAUSS = 3
104def gaussian_distribution(center, sigma, lb, ub):
105    #3 standard deviations covers approx. 99.7%
106    if sigma != 0:
107        nsigmas = NSIGMA_GAUSS
108        x = np.linspace(center-sigma*nsigmas, center+sigma*nsigmas, num=N_GAUSS)
109        x= x[(x >= lb) & (x <= ub)]
110        px = np.exp((x-center)**2 / (-2.0 * sigma * sigma))
111        return x, px
112    else:
113        return np.array([center]), np.array([1])
114
115N_SCHULZ = 80
116NSIGMA_SCHULZ = 8
117def schulz_distribution(center, sigma, lb, ub):
118    if sigma != 0:
119        nsigmas = NSIGMA_SCHULZ
120        x = np.linspace(center-sigma*nsigmas, center+sigma*nsigmas, num=N_SCHULZ)
121        x= x[(x >= lb) & (x <= ub)]
122        R = x/center
123        z = (center/sigma)**2
124        arg = z*np.log(z) + (z-1)*np.log(R) - R*z - np.log(center) - gammaln(z)
125        px = np.exp(arg)
126        return x, px
127    else:
128        return np.array([center]), np.array([1])
129
130#returns the effective radius used in sasview
131def ER_ellipsoid(radius_polar, radius_equatorial):
132    ee = np.empty_like(radius_polar)
133    if radius_polar > radius_equatorial:
134        ee = (radius_polar**2 - radius_equatorial**2)/radius_polar**2
135    elif radius_polar < radius_equatorial:
136        ee = (radius_equatorial**2 - radius_polar**2) / radius_equatorial**2
137    else:
138        ee = 2*radius_polar
139    if (radius_polar * radius_equatorial != 0):
140        bd = 1.0 - ee
141        e1 = np.sqrt(ee)
142        b1 = 1.0 + np.arcsin(e1) / (e1*np.sqrt(bd))
143        bL = (1.0 + e1) / (1.0 - e1)
144        b2 = 1.0 + bd / 2 / e1 * np.log(bL)
145        delta = 0.75 * b1 * b2
146    ddd = np.zeros_like(radius_polar)
147    ddd = 2.0*(delta + 1.0)*radius_polar*radius_equatorial**2
148    return 0.5*ddd**(1.0 / 3.0)
149
150def ellipsoid_volume(radius_polar,radius_equatorial):
151    volume = (4./3.)*pi*radius_polar*radius_equatorial**2
152    return volume
153
154# F1 is F(q)
155# F2 is F(g)^2
156#IQM is I(q) with monodispersity
157#IQSM is I(q) with structure factor S(q) and monodispersity
158#IQBM is I(q) with Beta Approximation and monodispersity
159#SQ is monodisperse approach for structure factor
160#SQ_EFF is the effective structure factor from beta approx
161def ellipsoid_theta(q, radius_polar, radius_equatorial, sld, sld_solvent,
162                    volfraction=0, radius_effective=None):
163    #creates values z and corresponding probabilities w from legendre-gauss quadrature
164    volume = ellipsoid_volume(radius_polar, radius_equatorial)
165    z, w = leggauss(76)
166    F1 = np.zeros_like(q)
167    F2 = np.zeros_like(q)
168    #use a u subsition(u=cos) and then u=(z+1)/2 to change integration from
169    #0->2pi with respect to alpha to -1->1 with respect to z, allowing us to use
170    #legendre-gauss quadrature
171    for k, qk in enumerate(q):
172        r = sqrt(radius_equatorial**2*(1-((z+1)/2)**2)+radius_polar**2*((z+1)/2)**2)
173        form = (sld-sld_solvent)*volume*sas_3j1x_x(qk*r)
174        F2[k] = np.sum(w*form**2)
175        F1[k] = np.sum(w*form)
176    #the 1/2 comes from the change of variables mentioned above
177    F2 = F2/2.0
178    F1 = F1/2.0
179    if radius_effective is None:
180        radius_effective = ER_ellipsoid(radius_polar,radius_equatorial)
181    SQ = hardsphere_simple(q, radius_effective, volfraction)
182    SQ_EFF = 1 + F1**2/F2*(SQ - 1)
183    IQM = 1e-4*F2/volume
184    IQSM = volfraction*IQM*SQ
185    IQBM = volfraction*IQM*SQ_EFF
186    return Theory(Q=q, F1=F1, F2=F2, P=IQM, S=SQ, I=IQSM, Seff=SQ_EFF, Ibeta=IQBM)
187
188#IQD is I(q) polydispursed, IQSD is I(q)S(q) polydispursed, etc.
189#IQBD HAS NOT BEEN CROSS CHECKED AT ALL
190def ellipsoid_pe(q, radius_polar, radius_equatorial, sld, sld_solvent,
191                 radius_polar_pd=0.1, radius_equatorial_pd=0.1,
192                 radius_polar_pd_type='gaussian',
193                 radius_equatorial_pd_type='gaussian',
194                 volfraction=0, radius_effective=None,
195                 background=0, scale=1,
196                 norm='sasview'):
197    if norm not in ['sasview', 'sasfit', 'yun']:
198        raise TypeError("unknown norm "+norm)
199    if radius_polar_pd_type == 'gaussian':
200        Rp_val, Rp_prob = gaussian_distribution(radius_polar, radius_polar_pd*radius_polar, 0, inf)
201    elif radius_polar_pd_type == 'schulz':
202        Rp_val, Rp_prob = schulz_distribution(radius_polar, radius_polar_pd*radius_polar, 0, inf)
203    if radius_equatorial_pd_type == 'gaussian':
204        Re_val, Re_prob = gaussian_distribution(radius_equatorial, radius_equatorial_pd*radius_equatorial, 0, inf)
205    elif radius_equatorial_pd_type == 'schulz':
206        Re_val, Re_prob = schulz_distribution(radius_equatorial, radius_equatorial_pd*radius_equatorial, 0, inf)
207    total_weight = total_volume = 0
208    radius_eff = 0
209    F1, F2 = np.zeros_like(q), np.zeros_like(q)
210    for k, Rpk in enumerate(Rp_val):
211        for i, Rei in enumerate(Re_val):
212            theory = ellipsoid_theta(q,Rpk,Rei,sld,sld_solvent)
213            volume = ellipsoid_volume(Rpk, Rei)
214            weight = Rp_prob[k]*Re_prob[i]
215            total_weight += weight
216            total_volume += weight*volume
217            F1 += theory.F1*weight
218            F2 += theory.F2*weight
219            radius_eff += weight*ER_ellipsoid(Rpk,Rei)
220    F1 /= total_weight
221    F2 /= total_weight
222    average_volume = total_volume/total_weight
223    if radius_effective is None:
224        radius_effective = radius_eff/total_weight
225    print("this is the effective radius for pure python",radius_effective)
226    if norm == 'sasfit':
227        IQD = F2
228    elif norm == 'sasview':
229        # Note: internally, sasview uses F2/total_volume because:
230        #   average_volume = total_volume/total_weight
231        #   F2/total_weight / average_volume
232        #     = F2/total_weight / total_volume/total_weight
233        #     = F2/total_volume
234       
235        IQD = F2/average_volume*1e-4*volfraction
236        F1 *= 1e-2  # Yun is using sld in 1/A^2, not 1e-6/A^2
237        F2 *= 1e-4
238    elif norm == 'yun':
239        F1 *= 1e-6  # Yun is using sld in 1/A^2, not 1e-6/A^2
240        F2 *= 1e-12
241        IQD = F2/average_volume*1e8*volfraction
242    SQ = hardsphere_simple(q, radius_effective, volfraction)
243    beta = F1**2/F2
244    SQ_EFF = 1 + beta*(SQ - 1)
245    IQSD = IQD*SQ
246    IQBD = IQD*SQ_EFF
247    print("\n\n\n\n\n this is F1" + str(F1))
248
249    print("\n\n\n\n\n this is F2" + str(F2))
250    print("\n\n\n\n\n this is SQ" + str(SQ))   
251    return Theory(Q=q, F1=F1, F2=F2, P=IQD, S=SQ, I=IQSD, Seff=SQ_EFF, Ibeta=IQBD)
252
253#polydispersity for sphere
254def sphere_r(q,radius,sld,sld_solvent,
255             radius_pd=0.1, radius_pd_type='gaussian',
256             volfraction=0, radius_effective=None,
257             background=0, scale=1,
258             norm='sasview'):
259    if norm not in ['sasview', 'sasfit', 'yun']:
260        raise TypeError("unknown norm "+norm)
261    if radius_pd_type == 'gaussian':
262        radius_val, radius_prob = gaussian_distribution(radius, radius_pd*radius, 0, inf)
263    elif radius_pd_type == 'schulz':
264        radius_val, radius_prob = schulz_distribution(radius, radius_pd*radius, 0, inf)
265    total_weight = total_volume = 0
266    F1 = np.zeros_like(q)
267    F2 = np.zeros_like(q)
268    for k, rk in enumerate(radius_val):
269        volume = 4./3.*pi*rk**3
270        total_weight += radius_prob[k]
271        total_volume += radius_prob[k]*volume
272        form = (sld-sld_solvent)*volume*sas_3j1x_x(q*rk)
273        F2 += radius_prob[k]*form**2
274        F1 += radius_prob[k]*form
275    F1 /= total_weight
276    F2 /= total_weight
277    average_volume = total_volume/total_weight
278
279    if radius_effective is None:
280        radius_effective = radius
281    average_volume = total_volume/total_weight
282    if norm == 'sasfit':
283        IQD = F2
284    elif norm == 'sasview':
285        IQD = F2/average_volume*1e-4*volfraction
286    elif norm == 'yun':
287        F1 *= 1e-6  # Yun is using sld in 1/A^2, not 1e-6/A^2
288        F2 *= 1e-12
289        IQD = F2/average_volume*1e8*volfraction
290    SQ = hardsphere_simple(q, radius_effective, volfraction)
291    beta = F1**2/F2
292    SQ_EFF = 1 + beta*(SQ - 1)
293    IQSD = IQD*SQ
294    IQBD = IQD*SQ_EFF
295    return Theory(Q=q, F1=F1, F2=F2, P=IQD, S=SQ, I=IQSD, Seff=SQ_EFF, Ibeta=IQBD)
296
297###############################################################################
298###############################################################################
299###############################################################################
300##################                                           ##################
301##################                   TESTS                   ##################
302##################                                           ##################
303###############################################################################
304###############################################################################
305###############################################################################
306
307def popn(d, keys):
308    """
309    Splits a dict into two, with any key of *d* which is in *keys* removed
310    from *d* and added to *b*. Returns *b*.
311    """
312    b = {}
313    for k in keys:
314        try:
315            b[k] = d.pop(k)
316        except KeyError:
317            pass
318    return b
319
320def sasmodels_theory(q, Pname, **pars):
321    """
322    Call sasmodels to compute the model with and without a hard sphere
323    structure factor.
324    """
325    #mono_pars = {k: (0 if k.endswith('_pd') else v) for k, v in pars.items()}
326    Ppars = pars.copy()
327    Spars = popn(Ppars, ['radius_effective', 'volfraction'])
328    Ipars = pars.copy()
329
330    # Autofill npts and nsigmas for the given pd type
331    for k, v in pars.items():
332        if k.endswith("_pd_type"):
333            if v == "gaussian":
334                n, nsigmas = N_GAUSS, NSIGMA_GAUSS
335            elif v == "schulz":
336                n, nsigmas = N_SCHULZ, NSIGMA_SCHULZ
337            Ppars.setdefault(k.replace("_pd_type", "_pd_n"), n)
338            Ppars.setdefault(k.replace("_pd_type", "_pd_nsigma"), nsigmas)
339            Ipars.setdefault(k.replace("_pd_type", "_pd_n"), n)
340            Ipars.setdefault(k.replace("_pd_type", "_pd_nsigma"), nsigmas)
341
342   
343    #Ppars['scale'] = Spars.get('volfraction', 1)
344    P = build_model(Pname, q)
345    S = build_model("hardsphere", q)
346    I = build_model(Pname+"@hardsphere", q)
347    Pq = P(**Ppars)*pars.get('volfraction', 1)
348    Sq = S(**Spars)
349    Iq = I(**Ipars)
350    #Iq = Pq*Sq*pars.get('volfraction', 1)
351    #Sq = Iq/Pq
352    #Iq = None#= Sq = None
353    r=I._kernel.results
354    return Theory(Q=q, F1=None, F2=None, P=Pq, S=None, I=None, Seff=r[1], Ibeta=Iq)
355
356def compare(title, target, actual, fields='F1 F2 P S I Seff Ibeta'):
357    """
358    Plot fields in common between target and actual, along with relative error.
359    """
360    available = [s for s in fields.split()
361                 if getattr(target, s) is not None and getattr(actual, s) is not None]
362    rows = len(available)
363    for row, field in enumerate(available):
364        Q = target.Q
365        I1, I2 = getattr(target, field), getattr(actual, field)
366        plt.subplot(rows, 2, 2*row+1)
367        plt.loglog(Q, abs(I1), label="target "+field)
368        plt.loglog(Q, abs(I2), label="value "+field)
369        #plt.legend(loc="upper left", bbox_to_anchor=(1,1))
370        plt.legend(loc='lower left')
371        plt.subplot(rows, 2, 2*row+2)
372        plt.semilogx(Q, I2/I1 - 1, label="relative error")
373        #plt.semilogx(Q, I1/I2 - 1, label="relative error")
374    plt.tight_layout()
375    plt.suptitle(title)
376    plt.show()
377
378def data_file(name):
379    return os.path.join(BETA_DIR, 'data_files', name)
380
381def load_sasfit(path):
382    data = np.loadtxt(path, dtype=str, delimiter=';').T
383    data = np.vstack((map(float, v) for v in data[0:2]))
384    return data
385
386COMPARISON = {}  # Type: Dict[(str,str,str)] -> Callable[(), None]
387
388def compare_sasview_sphere(pd_type='schulz'):
389    q = np.logspace(-5, 0, 250)
390    model = 'sphere'
391    pars = dict(
392        radius=20,sld=4,sld_solvent=1,
393        background=0,
394        radius_pd=.1, radius_pd_type=pd_type,
395        volfraction=0.15,
396        #radius_effective=12.59921049894873,  # equivalent average sphere radius
397        )
398    target = sasmodels_theory(q, model, **pars)
399    actual = sphere_r(q, norm='sasview', **pars)
400    title = " ".join(("sasmodels", model, pd_type))
401    compare(title, target, actual)
402COMPARISON[('sasview','sphere','gaussian')] = lambda: compare_sasview_sphere(pd_type='gaussian')
403COMPARISON[('sasview','sphere','schulz')] = lambda: compare_sasview_sphere(pd_type='schulz')
404
405def compare_sasview_ellipsoid(pd_type='gaussian'):
406    q = np.logspace(-5, 0, 50)
407    model = 'ellipsoid'
408    pars = dict(
409        radius_polar=20,radius_equatorial=400,sld=4,sld_solvent=1,
410        background=0,
411        radius_polar_pd=.1, radius_polar_pd_type=pd_type,
412        radius_equatorial_pd=.1, radius_equatorial_pd_type=pd_type,
413        volfraction=0.15,
414        radius_effective=270.7543927018,
415        #radius_effective=12.59921049894873,
416        )
417    target = sasmodels_theory(q, model, beta_mode=1, **pars)
418    actual = ellipsoid_pe(q, norm='sasview', **pars)
419    print(actual)
420    title = " ".join(("sasmodels", model, pd_type))
421    compare(title, target, actual)
422COMPARISON[('sasview','ellipsoid','gaussian')] = lambda: compare_sasview_ellipsoid(pd_type='gaussian')
423COMPARISON[('sasview','ellipsoid','schulz')] = lambda: compare_sasview_ellipsoid(pd_type='schulz')
424
425def compare_yun_ellipsoid_mono():
426    pars = {
427        'radius_polar': 20, 'radius_polar_pd': 0, 'radius_polar_pd_type': 'gaussian',
428        'radius_equatorial': 10, 'radius_equatorial_pd': 0, 'radius_equatorial_pd_type': 'gaussian',
429        'sld': 2, 'sld_solvent': 1,
430        'volfraction': 0.15,
431        # Yun uses radius for same volume sphere for effective radius
432        # whereas sasview uses the average curvature.
433        'radius_effective': 12.59921049894873,
434    }
435
436    data = np.loadtxt(data_file('yun_ellipsoid.dat'),skiprows=2).T
437    Q = data[0]
438    F1 = data[1]
439    P = data[3]*pars['volfraction']
440    S = data[5]
441    Seff = data[6]
442    target = Theory(Q=Q, F1=F1, P=P, S=S, Seff=Seff)
443    actual = ellipsoid_pe(Q, norm='yun', **pars)
444    title = " ".join(("yun", "ellipsoid", "no pd"))
445    #compare(title, target, actual, fields="P S I Seff Ibeta")
446    compare(title, target, actual)
447COMPARISON[('yun','ellipsoid','gaussian')] = compare_yun_ellipsoid_mono
448COMPARISON[('yun','ellipsoid','schulz')] = compare_yun_ellipsoid_mono
449
450def compare_yun_sphere_gauss():
451    # Note: yun uses gauss limits from R0/10 to R0 + 5 sigma steps sigma/100
452    # With pd = 0.1, that's 14 sigma and 1400 points.
453    pars = {
454        'radius': 20, 'radius_pd': 0.1, 'radius_pd_type': 'gaussian',
455        'sld': 6, 'sld_solvent': 0,
456        'volfraction': 0.1,
457    }
458
459    data = np.loadtxt(data_file('testPolydisperseGaussianSphere.dat'),skiprows=2).T
460    Q = data[0]
461    F1 = data[1]
462    P = data[3]
463    S = data[5]
464    Seff = data[6]
465    target = Theory(Q=Q, F1=F1, P=P, S=S, Seff=Seff)
466    actual = sphere_r(Q, norm='yun', **pars)
467    title = " ".join(("yun", "sphere", "10% dispersion 10% Vf"))
468    compare(title, target, actual)
469    data = np.loadtxt(data_file('testPolydisperseGaussianSphere2.dat'),skiprows=2).T
470    pars.update(radius_pd=0.15)
471    Q = data[0]
472    F1 = data[1]
473    P = data[3]
474    S = data[5]
475    Seff = data[6]
476    target = Theory(Q=Q, F1=F1, P=P, S=S, Seff=Seff)
477    actual = sphere_r(Q, norm='yun', **pars)
478    title = " ".join(("yun", "sphere", "15% dispersion 10% Vf"))
479    compare(title, target, actual)
480COMPARISON[('yun','sphere','gaussian')] = compare_yun_sphere_gauss
481
482
483def compare_sasfit_sphere_gauss():
484    #N=1,s=2,X0=20,distr radius R=20,eta_core=4,eta_solv=1,.3
485    pars = {
486        'radius': 20, 'radius_pd': 0.1, 'radius_pd_type': 'gaussian',
487        'sld': 4, 'sld_solvent': 1,
488        'volfraction': 0.3,
489    }
490
491    Q, IQ = load_sasfit(data_file('sasfit_sphere_IQD.txt'))
492    Q, IQSD = load_sasfit(data_file('sasfit_sphere_IQSD.txt'))
493    Q, IQBD = load_sasfit(data_file('sasfit_sphere_IQBD.txt'))
494    Q, SQ = load_sasfit(data_file('sasfit_polydisperse_sphere_sq.txt'))
495    Q, SQ_EFF = load_sasfit(data_file('sasfit_polydisperse_sphere_sqeff.txt'))
496    target = Theory(Q=Q, F1=None, F2=None, P=IQ, S=SQ, I=IQSD, Seff=SQ_EFF, Ibeta=IQBD)
497    actual = sphere_r(Q, norm="sasfit", **pars)
498    title = " ".join(("sasfit", "sphere", "pd=10% gaussian"))
499    compare(title, target, actual)
500    #compare(title, target, actual, fields="P")
501COMPARISON[('sasfit','sphere','gaussian')] = compare_sasfit_sphere_gauss
502
503def compare_sasfit_sphere_schulz():
504    #radius=20,sld=4,sld_solvent=1,volfraction=0.3,radius_pd=0.1
505    #We have scaled the output from sasfit by 1e-4*volume*volfraction
506    #0.10050378152592121
507    pars = {
508        'radius': 20, 'radius_pd': 0.1, 'radius_pd_type': 'schulz',
509        'sld': 4, 'sld_solvent': 1,
510        'volfraction': 0.3,
511    }
512
513    Q, IQ = load_sasfit(data_file('richard_test.txt'))
514    Q, IQSD = load_sasfit(data_file('richard_test2.txt'))
515    Q, IQBD = load_sasfit(data_file('richard_test3.txt'))
516    target = Theory(Q=Q, F1=None, F2=None, P=IQ, S=None, I=IQSD, Seff=None, Ibeta=IQBD)
517    actual = sphere_r(Q, norm="sasfit", **pars)
518    title = " ".join(("sasfit", "sphere", "pd=10% schulz"))
519    compare(title, target, actual)
520COMPARISON[('sasfit','sphere','schulz')] = compare_sasfit_sphere_schulz
521
522def compare_sasfit_ellipsoid_schulz():
523    #polarradius=20, equatorialradius=10, sld=4,sld_solvent=1,volfraction=0.3,radius_polar_pd=0.1
524    #Effective radius =13.1353356684
525    #We have scaled the output from sasfit by 1e-4*volume*volfraction
526    #0.10050378152592121
527    pars = {
528        'radius_polar': 20, 'radius_polar_pd': 0.1, 'radius_polar_pd_type': 'schulz',
529        'radius_equatorial': 10, 'radius_equatorial_pd': 0., 'radius_equatorial_pd_type': 'schulz',
530        'sld': 4, 'sld_solvent': 1,
531        'volfraction': 0.3, 'radius_effective': 13.1353356684,
532    }
533
534    Q, IQ = load_sasfit(data_file('richard_test4.txt'))
535    Q, IQSD = load_sasfit(data_file('richard_test5.txt'))
536    Q, IQBD = load_sasfit(data_file('richard_test6.txt'))
537    target = Theory(Q=Q, F1=None, F2=None, P=IQ, S=None, I=IQSD, Seff=None, Ibeta=IQBD)
538    actual = ellipsoid_pe(Q, norm="sasfit", **pars)
539    title = " ".join(("sasfit", "ellipsoid", "pd=10% schulz"))
540    compare(title, target, actual)
541COMPARISON[('sasfit','ellipsoid','schulz')] = compare_sasfit_ellipsoid_schulz
542
543
544def compare_sasfit_ellipsoid_gaussian():
545    pars = {
546        'radius_polar': 20, 'radius_polar_pd': 0, 'radius_polar_pd_type': 'gaussian',
547        'radius_equatorial': 10, 'radius_equatorial_pd': 0, 'radius_equatorial_pd_type': 'gaussian',
548        'sld': 4, 'sld_solvent': 1,
549        'volfraction': 0, 'radius_effective': None,
550    }
551
552    #Rp=20,Re=10,eta_core=4,eta_solv=1
553    Q, PQ0 = load_sasfit(data_file('sasfit_ellipsoid_IQM.txt'))
554    pars.update(volfraction=0, radius_polar_pd=0.0, radius_equatorial_pd=0, radius_effective=None)
555    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
556    target = Theory(Q=Q, P=PQ0)
557    compare("sasfit ellipsoid no poly", target, actual); plt.show()
558
559    #N=1,s=2,X0=20,distr 10% polar Rp=20,Re=10,eta_core=4,eta_solv=1, no structure poly
560    Q, PQ_Rp10 = load_sasfit(data_file('sasfit_ellipsoid_IQD.txt'))
561    pars.update(volfraction=0, radius_polar_pd=0.1, radius_equatorial_pd=0.0, radius_effective=None)
562    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
563    target = Theory(Q=Q, P=PQ_Rp10)
564    compare("sasfit ellipsoid P(Q) 10% Rp", target, actual); plt.show()
565    #N=1,s=1,X0=10,distr 10% equatorial Rp=20,Re=10,eta_core=4,eta_solv=1, no structure poly
566    Q, PQ_Re10 = load_sasfit(data_file('sasfit_ellipsoid_IQD2.txt'))
567    pars.update(volfraction=0, radius_polar_pd=0.0, radius_equatorial_pd=0.1, radius_effective=None)
568    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
569    target = Theory(Q=Q, P=PQ_Re10)
570    compare("sasfit ellipsoid P(Q) 10% Re", target, actual); plt.show()
571    #N=1,s=6,X0=20,distr 30% polar Rp=20,Re=10,eta_core=4,eta_solv=1, no structure poly
572    Q, PQ_Rp30 = load_sasfit(data_file('sasfit_ellipsoid_IQD3.txt'))
573    pars.update(volfraction=0, radius_polar_pd=0.3, radius_equatorial_pd=0.0, radius_effective=None)
574    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
575    target = Theory(Q=Q, P=PQ_Rp30)
576    compare("sasfit ellipsoid P(Q) 30% Rp", target, actual); plt.show()
577    #N=1,s=3,X0=10,distr 30% equatorial Rp=20,Re=10,eta_core=4,eta_solv=1, no structure poly
578    Q, PQ_Re30 = load_sasfit(data_file('sasfit_ellipsoid_IQD4.txt'))
579    pars.update(volfraction=0, radius_polar_pd=0.0, radius_equatorial_pd=0.3, radius_effective=None)
580    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
581    target = Theory(Q=Q, P=PQ_Re30)
582    compare("sasfit ellipsoid P(Q) 30% Re", target, actual); plt.show()
583    #N=1,s=12,X0=20,distr 60% polar Rp=20,Re=10,eta_core=4,eta_solv=1, no structure poly
584    Q, PQ_Rp60 = load_sasfit(data_file('sasfit_ellipsoid_IQD5.txt'))
585    pars.update(volfraction=0, radius_polar_pd=0.6, radius_equatorial_pd=0.0, radius_effective=None)
586    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
587    target = Theory(Q=Q, P=PQ_Rp60)
588    compare("sasfit ellipsoid P(Q) 60% Rp", target, actual); plt.show()
589    #N=1,s=6,X0=10,distr 60% equatorial Rp=20,Re=10,eta_core=4,eta_solv=1, no structure poly
590    Q, PQ_Re60 = load_sasfit(data_file('sasfit_ellipsoid_IQD6.txt'))
591    pars.update(volfraction=0, radius_polar_pd=0.0, radius_equatorial_pd=0.6, radius_effective=None)
592    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
593    target = Theory(Q=Q, P=PQ_Re60)
594    compare("sasfit ellipsoid P(Q) 60% Re", target, actual); plt.show()
595
596    #N=1,s=2,X0=20,distr polar Rp=20,Re=10,eta_core=4,eta_solv=1, hardsphere ,13.1354236254,.15
597    Q, SQ = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sq.txt'))
598    Q, SQ_EFF = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sqeff.txt'))
599    pars.update(volfraction=0.15, radius_polar_pd=0.1, radius_equatorial_pd=0, radius_effective=13.1354236254)
600    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
601    target = Theory(Q=Q, S=SQ, Seff=SQ_EFF)
602    compare("sasfit ellipsoid P(Q) 10% Rp 15% Vf", target, actual); plt.show()
603    #N=1,s=6,X0=20,distr polar Rp=20,Re=10,eta_core=4,eta_solv=1, hardsphere ,13.0901197149,.15
604    Q, SQ = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sq2.txt'))
605    Q, SQ_EFF = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sqeff2.txt'))
606    pars.update(volfraction=0.15, radius_polar_pd=0.3, radius_equatorial_pd=0, radius_effective=13.0901197149)
607    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
608    target = Theory(Q=Q, S=SQ, Seff=SQ_EFF)
609    compare("sasfit ellipsoid P(Q) 30% Rp 15% Vf", target, actual); plt.show()
610    #N=1,s=12,X0=20,distr polar Rp=20,Re=10,eta_core=4,eta_solv=1, hardsphere ,13.336060917,.15
611    Q, SQ = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sq3.txt'))
612    Q, SQ_EFF = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sqeff3.txt'))
613    pars.update(volfraction=0.15, radius_polar_pd=0.6, radius_equatorial_pd=0, radius_effective=13.336060917)
614    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
615    target = Theory(Q=Q, S=SQ, Seff=SQ_EFF)
616    compare("sasfit ellipsoid P(Q) 60% Rp 15% Vf", target, actual); plt.show()
617
618    #N=1,s=2,X0=20,distr polar Rp=20,Re=10,eta_core=4,eta_solv=1, hardsphere ,13.1354236254,.3
619    Q, SQ = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sq4.txt'))
620    Q, SQ_EFF = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sqeff4.txt'))
621    pars.update(volfraction=0.3, radius_polar_pd=0.1, radius_equatorial_pd=0, radius_effective=13.1354236254)
622    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
623    target = Theory(Q=Q, S=SQ, Seff=SQ_EFF)
624    compare("sasfit ellipsoid P(Q) 10% Rp 30% Vf", target, actual); plt.show()
625    #N=1,s=6,X0=20,distr polar Rp=20,Re=10,eta_core=4,eta_solv=1, hardsphere ,13.0901197149,.3
626    Q, SQ = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sq5.txt'))
627    Q, SQ_EFF = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sqeff5.txt'))
628    pars.update(volfraction=0.3, radius_polar_pd=0.3, radius_equatorial_pd=0, radius_effective=13.0901197149)
629    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
630    target = Theory(Q=Q, S=SQ, Seff=SQ_EFF)
631    compare("sasfit ellipsoid P(Q) 30% Rp 30% Vf", target, actual); plt.show()
632    #N=1,s=12,X0=20,distr polar Rp=20,Re=10,eta_core=4,eta_solv=1, hardsphere ,13.336060917,.3
633    Q, SQ = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sq6.txt'))
634    Q, SQ_EFF = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sqeff6.txt'))
635    pars.update(volfraction=0.3, radius_polar_pd=0.6, radius_equatorial_pd=0, radius_effective=13.336060917)
636    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
637    target = Theory(Q=Q, S=SQ, Seff=SQ_EFF)
638    compare("sasfit ellipsoid P(Q) 60% Rp 30% Vf", target, actual); plt.show()
639
640    #N=1,s=2,X0=20,distr polar Rp=20,Re=10,eta_core=4,eta_solv=1, hardsphere ,13.1354236254,.6
641    Q, SQ = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sq7.txt'))
642    Q, SQ_EFF = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sqeff7.txt'))
643    pars.update(volfraction=0.6, radius_polar_pd=0.1, radius_equatorial_pd=0, radius_effective=13.1354236254)
644    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
645    target = Theory(Q=Q, S=SQ, Seff=SQ_EFF)
646    compare("sasfit ellipsoid P(Q) 10% Rp 60% Vf", target, actual); plt.show()
647    #N=1,s=6,X0=20,distr polar Rp=20,Re=10,eta_core=4,eta_solv=1, hardsphere ,13.0901197149,.6
648    Q, SQ = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sq8.txt'))
649    Q, SQ_EFF = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sqeff8.txt'))
650    pars.update(volfraction=0.6, radius_polar_pd=0.3, radius_equatorial_pd=0, radius_effective=13.0901197149)
651    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
652    target = Theory(Q=Q, S=SQ, Seff=SQ_EFF)
653    compare("sasfit ellipsoid P(Q) 30% Rp 60% Vf", target, actual); plt.show()
654    #N=1,s=12,X0=20,distr polar Rp=20,Re=10,eta_core=4,eta_solv=1, hardsphere ,13.336060917,.6
655    Q, SQ = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sq9.txt'))
656    Q, SQ_EFF = load_sasfit(data_file('sasfit_polydisperse_ellipsoid_sqeff9.txt'))
657    pars.update(volfraction=0.6, radius_polar_pd=0.6, radius_equatorial_pd=0, radius_effective=13.336060917)
658    actual = ellipsoid_pe(Q, norm='sasfit', **pars)
659    target = Theory(Q=Q, S=SQ, Seff=SQ_EFF)
660    compare("sasfit ellipsoid P(Q) 60% Rp 60% Vf", target, actual); plt.show()
661COMPARISON[('sasfit','ellipsoid','gaussian')] = compare_sasfit_ellipsoid_gaussian
662
663def main():
664    key = tuple(sys.argv[1:])
665    if key not in COMPARISON:
666        print("usage: sasfit_compare.py [sasview|sasfit|yun] [sphere|ellipsoid] [gaussian|schulz]")
667        return
668    comparison = COMPARISON[key]
669    comparison()
670
671if __name__ == "__main__":
672    main()
Note: See TracBrowser for help on using the repository browser.