[2e66ef5] | 1 | .. _Scripting_Interface: |
---|
| 2 | |
---|
| 3 | ******************* |
---|
| 4 | Scripting Interface |
---|
| 5 | ******************* |
---|
| 6 | |
---|
| 7 | Need some basic details here of how to load models and data via script, evaluate |
---|
| 8 | them at given parameter values and run bumps fits. |
---|
| 9 | |
---|
| 10 | The key functions are :func:`sasmodels.core.load_model` for loading the |
---|
| 11 | model definition and compiling the kernel and |
---|
[bd7630d] | 12 | :func:`sasmodels.data.load_data` for calling sasview to load the data. |
---|
[2e66ef5] | 13 | |
---|
[bd7630d] | 14 | Preparing data |
---|
| 15 | ============== |
---|
[2e66ef5] | 16 | |
---|
[bd7630d] | 17 | Usually 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 | |
---|
| 23 | You 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 | |
---|
| 28 | The :func:`sasmodels.data.set_beam_stop` method simply sets the *mask* |
---|
| 29 | attribute for the data. |
---|
| 30 | |
---|
| 31 | The data defines the resolution function and the q values to evaluate, so |
---|
| 32 | even if you simulating experiments prior to making measurements, you still |
---|
| 33 | need a data object for reference. Use :func:`sasmodels.data.empty_data1D` |
---|
| 34 | or :func:`sasmodels.data.empty_data2D` to create a container with a |
---|
| 35 | given $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 | |
---|
| 44 | To use a more realistic model of resolution, or to load data from a file |
---|
| 45 | format not understood by SasView, you can use :class:`sasmodels.data.Data1D` |
---|
| 46 | or :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 | |
---|
| 52 | For USANS data, use 1D data, but set *dxl* and *dxw* attributes to |
---|
| 53 | indicate slit resolution:: |
---|
| 54 | |
---|
| 55 | data.dxl = 0.117 |
---|
| 56 | |
---|
| 57 | See :func:`sasmodels.resolution.slit_resolution` for details. |
---|
| 58 | |
---|
| 59 | SESANS data is more complicated; if your SESANS format is not supported by |
---|
| 60 | SasView you need to define a number of attributes beyond *x*, *y*. For |
---|
| 61 | example:: |
---|
| 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 | |
---|
| 86 | The *data* module defines various data plotters as well. |
---|
| 87 | |
---|
| 88 | Using sasmodels directly |
---|
| 89 | ======================== |
---|
| 90 | |
---|
| 91 | Once you have a computational kernel and a data object, you can evaluate |
---|
| 92 | the model for various parameters using |
---|
| 93 | :class:`sasmodels.direct_model.DirectModel`. The resulting object *f* |
---|
| 94 | will be callable as *f(par=value, ...)*, returning the $I(q)$ for the $q$ |
---|
| 95 | values 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 | |
---|
| 109 | Polydispersity 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 | |
---|
| 116 | Using sasmodels through the bumps optimizer |
---|
| 117 | =========================================== |
---|
| 118 | |
---|
| 119 | Like DirectModel, you can wrap data and a kernel in a *bumps* model with |
---|
[2e66ef5] | 120 | class:`sasmodels.bumps_model.Model` and create an |
---|
[bd7630d] | 121 | class:`sasmodels.bumps_model.Experiment` that you can fit with the *bumps* |
---|
[2e66ef5] | 122 | interface. 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 | |
---|
| 163 | Assume that bumps has been installed and the bumps command is available. |
---|
| 164 | Maybe need to set the path to sasmodels/sasview |
---|
| 165 | using *PYTHONPATH=path/to/sasmodels:path/to/sasview/src*. |
---|
| 166 | To run the model use the *bumps* program:: |
---|
| 167 | |
---|
| 168 | $ bumps example/model.py --preview |
---|
| 169 | |
---|
[4aa5dce] | 170 | Note that bumps and sasmodels are included as part of the SasView |
---|
| 171 | distribution. On windows, bumps can be called from the cmd prompt |
---|
| 172 | as follows:: |
---|
| 173 | |
---|
| 174 | SasViewCom bumps.cli example/model.py --preview |
---|
| 175 | |
---|
[bd7630d] | 176 | Calling the computation kernel |
---|
| 177 | ============================== |
---|
[2e66ef5] | 178 | |
---|
| 179 | Getting a simple function that you can call on a set of q values and return |
---|
| 180 | a result is not so simple. Since the time critical use case (fitting) involves |
---|
| 181 | calling the function over and over with identical $q$ values, we chose to |
---|
| 182 | optimize the call by only transfering the $q$ values to the GPU once at the |
---|
| 183 | start of the fit. We do this by creating a :class:`sasmodels.kernel.Kernel` |
---|
| 184 | object 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 |
---|
| 187 | does depends on whether it is running as a DLL, as OpenCL or as a pure |
---|
| 188 | python kernel. Once the kernel is in hand, we can then marshal a set of |
---|
| 189 | parameters into a :class:`sasmodels.details.CallDetails` object and ship it to |
---|
| 190 | the kernel using the :func:`sansmodels.direct_model.call_kernel` function. An |
---|
| 191 | example should help, *example/cylinder_eval.py*:: |
---|
| 192 | |
---|
| 193 | from numpy import logspace |
---|
| 194 | from matplotlib import pyplot as plt |
---|
| 195 | from sasmodels.core import load_model |
---|
| 196 | from sasmodels.direct_model import call_kernel |
---|
| 197 | |
---|
| 198 | model = load_model('cylinder') |
---|
| 199 | q = logspace(-3, -1, 200) |
---|
| 200 | kernel = model.make_kernel([q]) |
---|
| 201 | Iq = call_kernel(kernel, dict(radius=200.)) |
---|
| 202 | plt.loglog(q, Iq) |
---|
[4aa5dce] | 203 | plt.show() |
---|
| 204 | |
---|
| 205 | On windows, this can be called from the cmd prompt using sasview as:: |
---|
| 206 | |
---|
| 207 | SasViewCom example/cylinder_eval.py |
---|