source: sasmodels/doc/guide/scripting.rst @ 3709366

ticket-1257-vesicle-productticket_1156ticket_822_more_unit_tests
Last change on this file since 3709366 was 23df833, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

Document direct call to Fq in user guide

  • Property mode set to 100644
File size: 8.6 KB
RevLine 
[2e66ef5]1.. _Scripting_Interface:
2
3*******************
4Scripting Interface
5*******************
6
7Need some basic details here of how to load models and data via script, evaluate
8them at given parameter values and run bumps fits.
9
10The key functions are :func:`sasmodels.core.load_model` for loading the
11model definition and compiling the kernel and
[bd7630d]12:func:`sasmodels.data.load_data` for calling sasview to load the data.
[2e66ef5]13
[bd7630d]14Preparing data
15==============
[2e66ef5]16
[bd7630d]17Usually you will load data via the sasview loader, with the
18:func:`sasmodels.data.load_data` function.  For example::
19
20    from sasmodels.data import load_data
21    data = load_data("sasmodels/example/093191_201.dat")
22
23You may want to apply a data mask, such a beam stop, and trim high $q$::
24
25    from sasmodels.data import set_beam_stop
26    set_beam_stop(data, qmin, qmax)
27
28The :func:`sasmodels.data.set_beam_stop` method simply sets the *mask*
29attribute for the data.
30
31The data defines the resolution function and the q values to evaluate, so
32even if you simulating experiments prior to making measurements, you still
33need a data object for reference. Use :func:`sasmodels.data.empty_data1D`
34or :func:`sasmodels.data.empty_data2D` to create a container with a
35given $q$ and $\Delta q/q$.  For example::
36
37    import numpy as np
38    from sasmodels.data import empty_data1D
39
40    # 120 points logarithmically spaced from 0.005 to 0.2, with dq/q = 5%
41    q = np.logspace(np.log10(5e-3), np.log10(2e-1), 120)
42    data = empty_data1D(q, resolution=0.05)
43
44To use a more realistic model of resolution, or to load data from a file
45format not understood by SasView, you can use :class:`sasmodels.data.Data1D`
46or :class:`sasmodels.data.Data2D` directly.  The 1D data uses
47*x*, *y*, *dx* and *dy* for $x = q$ and $y = I(q)$, and 2D data uses
48*x*, *y*, *z*, *dx*, *dy*, *dz* for $x, y = qx, qy$ and $z = I(qx, qy)$.
49[Note: internally, the Data2D object uses SasView conventions,
50*qx_data*, *qy_data*, *data*, *dqx_data*, *dqy_data*, and *err_data*.]
51
52For USANS data, use 1D data, but set *dxl* and *dxw* attributes to
53indicate slit resolution::
54
55    data.dxl = 0.117
56
57See :func:`sasmodels.resolution.slit_resolution` for details.
58
59SESANS data is more complicated; if your SESANS format is not supported by
60SasView you need to define a number of attributes beyond *x*, *y*.  For
61example::
62
63    SElength = np.linspace(0, 2400, 61) # [A]
64    data = np.ones_like(SElength)
65    err_data = np.ones_like(SElength)*0.03
66
67    class Source:
68        wavelength = 6 # [A]
69        wavelength_unit = "A"
70    class Sample:
71        zacceptance = 0.1 # [A^-1]
72        thickness = 0.2 # [cm]
73
74    class SESANSData1D:
75        #q_zmax = 0.23 # [A^-1]
76        lam = 0.2 # [nm]
77        x = SElength
78        y = data
79        dy = err_data
80        sample = Sample()
81    data = SESANSData1D()
82
83    x, y = ... # create or load sesans
84    data = smd.Data
85
86The *data* module defines various data plotters as well.
87
88Using sasmodels directly
89========================
90
91Once you have a computational kernel and a data object, you can evaluate
92the model for various parameters using
93:class:`sasmodels.direct_model.DirectModel`.  The resulting object *f*
94will be callable as *f(par=value, ...)*, returning the $I(q)$ for the $q$
95values in the data.  For example::
96
97    import numpy as np
98    from sasmodels.data import empty_data1D
99    from sasmodels.core import load_model
100    from sasmodels.direct_model import DirectModel
101
102    # 120 points logarithmically spaced from 0.005 to 0.2, with dq/q = 5%
103    q = np.logspace(np.log10(5e-3), np.log10(2e-1), 120)
104    data = empty_data1D(q, resolution=0.05)
105    kernel = load_model("ellipsoid)
106    f = DirectModel(data, kernel)
107    Iq = f(radius_polar=100)
108
109Polydispersity information is set with special parameter names:
110
111    * *par_pd* for polydispersity width, $\Delta p/p$,
112    * *par_pd_n* for the number of points in the distribution,
113    * *par_pd_type* for the distribution type (as a string), and
114    * *par_pd_nsigmas* for the limits of the distribution.
115
116Using sasmodels through the bumps optimizer
117===========================================
118
119Like DirectModel, you can wrap data and a kernel in a *bumps* model with
[2e66ef5]120class:`sasmodels.bumps_model.Model` and create an
[bd7630d]121class:`sasmodels.bumps_model.Experiment` that you can fit with the *bumps*
[2e66ef5]122interface. Here is an example from the *example* directory such as
123*example/model.py*::
124
125    import sys
126    from bumps.names import *
127    from sasmodels.core import load_model
128    from sasmodels.bumps_model import Model, Experiment
129    from sasmodels.data import load_data, set_beam_stop, set_top
130
131    """ IMPORT THE DATA USED """
132    radial_data = load_data('DEC07267.DAT')
133    set_beam_stop(radial_data, 0.00669, outer=0.025)
134    set_top(radial_data, -.0185)
135
136    kernel = load_model("ellipsoid")
137
138    model = Model(kernel,
139        scale=0.08,
140        radius_polar=15, radius_equatorial=800,
141        sld=.291, sld_solvent=7.105,
142        background=0,
143        theta=90, phi=0,
144        theta_pd=15, theta_pd_n=40, theta_pd_nsigma=3,
145        radius_polar_pd=0.222296, radius_polar_pd_n=1, radius_polar_pd_nsigma=0,
146        radius_equatorial_pd=.000128, radius_equatorial_pd_n=1, radius_equatorial_pd_nsigma=0,
147        phi_pd=0, phi_pd_n=20, phi_pd_nsigma=3,
148        )
149
150    # SET THE FITTING PARAMETERS
151    model.radius_polar.range(15, 1000)
152    model.radius_equatorial.range(15, 1000)
153    model.theta_pd.range(0, 360)
154    model.background.range(0,1000)
155    model.scale.range(0, 10)
156
157    #cutoff = 0     # no cutoff on polydisperisity loops
158    #cutoff = 1e-5  # default cutoff
159    cutoff = 1e-3  # low precision cutoff
160    M = Experiment(data=radial_data, model=model, cutoff=cutoff)
161    problem = FitProblem(M)
162
163Assume that bumps has been installed and the bumps command is available.
164Maybe need to set the path to sasmodels/sasview
165using *PYTHONPATH=path/to/sasmodels:path/to/sasview/src*.
166To run the model use the *bumps* program::
167
168    $ bumps example/model.py --preview
169
[4aa5dce]170Note that bumps and sasmodels are included as part of the SasView
171distribution.  On windows, bumps can be called from the cmd prompt
172as follows::
173
174    SasViewCom bumps.cli example/model.py --preview
175
[bd7630d]176Calling the computation kernel
177==============================
[2e66ef5]178
179Getting a simple function that you can call on a set of q values and return
180a result is not so simple.  Since the time critical use case (fitting) involves
181calling the function over and over with identical $q$ values, we chose to
182optimize the call by only transfering the $q$ values to the GPU once at the
183start of the fit.  We do this by creating a :class:`sasmodels.kernel.Kernel`
184object from the :class:`sasmodels.kernel.KernelModel` returned from
185:func:`sasmodels.core.load_model` using the
186:meth:`sasmodels.kernel.KernelModel.make_kernel` method.  What it actual
187does depends on whether it is running as a DLL, as OpenCL or as a pure
188python kernel.  Once the kernel is in hand, we can then marshal a set of
189parameters into a :class:`sasmodels.details.CallDetails` object and ship it to
[23df833]190the kernel using the :func:`sansmodels.direct_model.call_kernel` function.  To
191accesses the underlying $<F(q)>$ and $<F^2(q)>$, use
192:func:`sasmodels.direct_model.call_Fq` instead.
[2e66ef5]193
[23df833]194The following example should
195help, *example/cylinder_eval.py*::
196
197    from numpy import logspace, sqrt
[2e66ef5]198    from matplotlib import pyplot as plt
199    from sasmodels.core import load_model
[23df833]200    from sasmodels.direct_model import call_kernel, call_Fq
[2e66ef5]201
202    model = load_model('cylinder')
203    q = logspace(-3, -1, 200)
204    kernel = model.make_kernel([q])
[23df833]205    pars = {'radius': 200, 'radius_pd': 0.1, 'scale': 2}
206    Iq = call_kernel(kernel, pars)
207    F, Fsq, Reff, V, Vratio = call_Fq(kernel, pars)
208
209    plt.loglog(q, Iq, label='2 I(q)')
210    plt.loglog(q, F**2/V, label='<F(q)>^2/V')
211    plt.loglog(q, Fsq/V, label='<F^2(q)>/V')
212    plt.xlabel('q (1/A)')
213    plt.ylabel('I(q) (1/cm)')
214    plt.title('Cylinder with radius 200.')
215    plt.legend()
[4aa5dce]216    plt.show()
217
[23df833]218.. figure:: direct_call.png
219
220    Comparison between $I(q)$, $<F(q)>$ and $<F^2(q)>$ for cylinder model.
221
222This compares $I(q)$ with $<F(q)>$ and $<F^2(q)>$ for a cylinder
223with *radius=200 +/- 20* and *scale=2*. Note that *call_Fq* does not
224include scale and background, nor does it normalize by the average volume.
225The definition of $F = \rho V \hat F$ scaled by the contrast and
226volume, compared to the canonical cylinder $\hat F$, with $\hat F(0) = 1$.
227Integrating over polydispersity and orientation, the returned values are
228$\sum_{r,w\in N(r_o, r_o/10)} \sum_\theta w F(q,r_o,\theta)\sin\theta$ and
229$\sum_{r,w\in N(r_o, r_o/10)} \sum_\theta w F^2(q,r_o,\theta)\sin\theta$.
230
231On windows, this example can be called from the cmd prompt using sasview as
232as the python interpreter::
[4aa5dce]233
234    SasViewCom example/cylinder_eval.py
Note: See TracBrowser for help on using the repository browser.