Changes in / [1a8b91c:9b7fac6] in sasmodels
- Files:
-
- 1 added
- 1 deleted
- 22 edited
Legend:
- Unmodified
- Added
- Removed
-
.travis.yml
r5c36bf1 r335271e 6 6 env: 7 7 - PY=2.7 8 #- DEPLOY=True8 - DEPLOY=True 9 9 - os: linux 10 10 env: -
doc/guide/magnetism/magnetism.rst
rbefe905 r4f5afc9 39 39 40 40 .. math:: 41 -- &= ( 1-u_i)(1-u_f)\\42 -+ &= ( 1-u_i)(u_f)\\43 +- &= ( u_i)(1-u_f)\\44 ++ &= ( u_i)(u_f)41 -- &= ((1-u_i)(1-u_f))^{1/4} \\ 42 -+ &= ((1-u_i)(u_f))^{1/4} \\ 43 +- &= ((u_i)(1-u_f))^{1/4} \\ 44 ++ &= ((u_i)(u_f))^{1/4} 45 45 46 46 Ideally the experiment would measure the pure spin states independently and … … 104 104 | 2015-05-02 Steve King 105 105 | 2017-11-15 Paul Kienzle 106 | 2018-06-02 Adam Washington -
doc/guide/pd/polydispersity.rst
rd712a0f r29afc50 20 20 P(q) = \text{scale} \langle F^* F \rangle / V + \text{background} 21 21 22 where $F$ is the scattering amplitude and $\langle\cdot\rangle$ denotes an 23 average over the size distribution $f(x; \bar x, \sigma)$, giving 24 25 .. math:: 26 27 P(q) = \frac{\text{scale}}{V} \int_\mathbb{R} 28 f(x; \bar x, \sigma) F^2(q, x)\, dx + \text{background} 22 where $F$ is the scattering amplitude and $\langle\cdot\rangle$ denotes an 23 average over the size distribution. 29 24 30 25 Each distribution is characterized by a center value $\bar x$ or … … 46 41 with larger values of $N_\sigma$ required for heavier tailed distributions. 47 42 The scattering in general falls rapidly with $qr$ so the usual assumption 48 that $ f(r - 3\sigma_r)$ is tiny and therefore $f(r - 3\sigma_r)f(r - 3\sigma_r)$43 that $G(r - 3\sigma_r)$ is tiny and therefore $f(r - 3\sigma_r)G(r - 3\sigma_r)$ 49 44 will not contribute much to the average may not hold when particles are large. 50 45 This, too, will require increasing $N_\sigma$. … … 68 63 69 64 Additional distributions are under consideration. 70 71 .. note:: In 2009 IUPAC decided to introduce the new term 'dispersity' to replace72 the term 'polydispersity' (see `Pure Appl. Chem., (2009), 81(2),73 351-353 <http://media.iupac.org/publications/pac/2009/pdf/8102x0351.pdf>`_74 in order to make the terminology describing distributions of properties75 unambiguous. Throughout the SasView documentation we continue to use the76 term polydispersity because one of the consequences of the IUPAC change is77 that orientational polydispersity would not meet their new criteria (which78 requires dispersity to be dimensionless).79 65 80 66 Suggested Applications -
doc/guide/plugin.rst
rf796469 r7e6bc45e 822 822 823 823 :code:`source = ["lib/Si.c", ...]` 824 (`Si.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/ sas_Si.c>`_)824 (`Si.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/Si.c>`_) 825 825 826 826 sas_3j1x_x(x): -
example/model_ellipsoid_hayter_msa.py
r9a99993 r8a5f021 16 16 17 17 # DEFINE THE MODEL 18 kernel = load_model('ellipsoid @hayter_msa')18 kernel = load_model('ellipsoid*hayter_msa') 19 19 20 20 pars = dict(scale=6.4, background=0.06, sld=0.33, sld_solvent=2.15, radius_polar=14.0, -
sasmodels/compare.py
raf7a97c r5770493 107 107 -title="note" adds note to the plot title, after the model name 108 108 -weights shows weights plots for the polydisperse parameters 109 -profile shows the sld profile if the model has a plottable sld profile110 109 111 110 === output options === 112 111 -edit starts the parameter explorer 113 112 -help/-html shows the model docs instead of running the model 114 115 === environment variables ===116 -DSAS_MODELPATH=path sets directory containing custom models117 -DSAS_OPENCL=vendor:device|none sets the target OpenCL device118 -DXDG_CACHE_HOME=~/.cache sets the pyopencl cache root (linux only)119 -DSAS_COMPILER=tinycc|msvc|mingw|unix sets the DLL compiler120 -DSAS_OPENMP=1 turns on OpenMP for the DLLs121 -DSAS_DLL_PATH=path sets the path to the compiled modules122 113 123 114 The interpretation of quad precision depends on architecture, and may … … 654 645 655 646 def make_data(opts): 656 # type: (Dict[str, Any] , float) -> Tuple[Data, np.ndarray]647 # type: (Dict[str, Any]) -> Tuple[Data, np.ndarray] 657 648 """ 658 649 Generate an empty dataset, used with the model to set Q points … … 676 667 if opts['zero']: 677 668 q = np.hstack((0, q)) 678 # TODO: provide command line control of lambda and Delta lambda/lambda 679 #L, dLoL = 5, 0.14/np.sqrt(6) # wavelength and 14% triangular FWHM 680 L, dLoL = 0, 0 681 data = empty_data1D(q, resolution=res, L=L, dL=L*dLoL) 669 data = empty_data1D(q, resolution=res) 682 670 index = slice(None, None) 683 671 return data, index … … 784 772 dim = base._kernel.dim 785 773 plot_weights(model_info, get_mesh(model_info, base_pars, dim=dim)) 786 if opts['show_profile']:787 import pylab788 base, comp = opts['engines']789 base_pars, comp_pars = opts['pars']790 have_base = base._kernel.info.profile is not None791 have_comp = (792 comp is not None793 and comp._kernel.info.profile is not None794 and base_pars != comp_pars795 )796 if have_base or have_comp:797 pylab.figure()798 if have_base:799 plot_profile(base._kernel.info, **base_pars)800 if have_comp:801 plot_profile(comp._kernel.info, label='comp', **comp_pars)802 pylab.legend()803 774 if opts['plot']: 804 775 import matplotlib.pyplot as plt … … 806 777 return limits 807 778 808 def plot_profile(model_info, label='base', **args):809 # type: (ModelInfo, List[Tuple[float, np.ndarray, np.ndarray]]) -> None810 """811 Plot the profile returned by the model profile method.812 813 *model_info* defines model parameters, etc.814 815 *mesh* is a list of tuples containing (*value*, *dispersity*, *weights*)816 for each parameter, where (*dispersity*, *weights*) pairs are the817 distributions to be plotted.818 """819 import pylab820 821 args = dict((k, v) for k, v in args.items()822 if "_pd" not in k823 and ":" not in k824 and k not in ("background", "scale", "theta", "phi", "psi"))825 args = args.copy()826 827 args.pop('scale', 1.)828 args.pop('background', 0.)829 z, rho = model_info.profile(**args)830 #pylab.interactive(True)831 pylab.plot(z, rho, '-', label=label)832 pylab.grid(True)833 #pylab.show()834 835 836 837 779 def run_models(opts, verbose=False): 838 780 # type: (Dict[str, Any]) -> Dict[str, Any] … … 844 786 base_n, comp_n = opts['count'] 845 787 base_pars, comp_pars = opts['pars'] 846 base_data, comp_data = opts['data']788 data = opts['data'] 847 789 848 790 comparison = comp is not None … … 858 800 print("%s t=%.2f ms, intensity=%.0f" 859 801 % (base.engine, base_time, base_value.sum())) 860 _show_invalid( base_data, base_value)802 _show_invalid(data, base_value) 861 803 except ImportError: 862 804 traceback.print_exc() … … 870 812 print("%s t=%.2f ms, intensity=%.0f" 871 813 % (comp.engine, comp_time, comp_value.sum())) 872 _show_invalid( base_data, comp_value)814 _show_invalid(data, comp_value) 873 815 except ImportError: 874 816 traceback.print_exc() … … 924 866 have_base, have_comp = (base_value is not None), (comp_value is not None) 925 867 base, comp = opts['engines'] 926 base_data, comp_data = opts['data']868 data = opts['data'] 927 869 use_data = (opts['datafile'] is not None) and (have_base ^ have_comp) 928 870 929 871 # Plot if requested 930 872 view = opts['view'] 931 #view = 'log'932 873 if limits is None: 933 874 vmin, vmax = np.inf, -np.inf … … 943 884 if have_comp: 944 885 plt.subplot(131) 945 plot_theory( base_data, base_value, view=view, use_data=use_data, limits=limits)886 plot_theory(data, base_value, view=view, use_data=use_data, limits=limits) 946 887 plt.title("%s t=%.2f ms"%(base.engine, base_time)) 947 888 #cbar_title = "log I" … … 950 891 plt.subplot(132) 951 892 if not opts['is2d'] and have_base: 952 plot_theory( comp_data, base_value, view=view, use_data=use_data, limits=limits)953 plot_theory( comp_data, comp_value, view=view, use_data=use_data, limits=limits)893 plot_theory(data, base_value, view=view, use_data=use_data, limits=limits) 894 plot_theory(data, comp_value, view=view, use_data=use_data, limits=limits) 954 895 plt.title("%s t=%.2f ms"%(comp.engine, comp_time)) 955 896 #cbar_title = "log I" … … 967 908 err[err > cutoff] = cutoff 968 909 #err,errstr = base/comp,"ratio" 969 # Note: base_data only since base and comp have same q values (though 970 # perhaps different resolution), and we are plotting the difference 971 # at each q 972 plot_theory(base_data, None, resid=err, view=errview, use_data=use_data) 910 plot_theory(data, None, resid=err, view=errview, use_data=use_data) 973 911 plt.xscale('log' if view == 'log' and not opts['is2d'] else 'linear') 974 912 plt.legend(['P%d'%(k+1) for k in range(setnum+1)], loc='best') … … 1004 942 OPTIONS = [ 1005 943 # Plotting 1006 'plot', 'noplot', 1007 'weights', 'profile', 944 'plot', 'noplot', 'weights', 1008 945 'linear', 'log', 'q4', 1009 946 'rel', 'abs', … … 1121 1058 1122 1059 invalid = [o[1:] for o in flags 1123 if not (o[1:] in NAME_OPTIONS 1124 or any(o.startswith('-%s='%t) for t in VALUE_OPTIONS) 1125 or o.startswith('-D'))] 1060 if o[1:] not in NAME_OPTIONS 1061 and not any(o.startswith('-%s='%t) for t in VALUE_OPTIONS)] 1126 1062 if invalid: 1127 1063 print("Invalid options: %s"%(", ".join(invalid))) … … 1139 1075 'qmax' : 0.05, 1140 1076 'nq' : 128, 1141 'res' : '0.0',1077 'res' : 0.0, 1142 1078 'noise' : 0.0, 1143 1079 'accuracy' : 'Low', … … 1160 1096 'count' : '1', 1161 1097 'show_weights' : False, 1162 'show_profile' : False,1163 1098 'sphere' : 0, 1164 1099 'ngauss' : '0', … … 1180 1115 elif arg.startswith('-q='): 1181 1116 opts['qmin'], opts['qmax'] = [float(v) for v in arg[3:].split(':')] 1182 elif arg.startswith('-res='): opts['res'] = arg[5:]1117 elif arg.startswith('-res='): opts['res'] = float(arg[5:]) 1183 1118 elif arg.startswith('-noise='): opts['noise'] = float(arg[7:]) 1184 1119 elif arg.startswith('-sets='): opts['sets'] = int(arg[6:]) … … 1221 1156 elif arg == '-default': opts['use_demo'] = False 1222 1157 elif arg == '-weights': opts['show_weights'] = True 1223 elif arg == '-profile': opts['show_profile'] = True1224 1158 elif arg == '-html': opts['html'] = True 1225 1159 elif arg == '-help': opts['html'] = True 1226 elif arg.startswith('-D'):1227 var, val = arg[2:].split('=')1228 os.environ[var] = val1229 1160 # pylint: enable=bad-whitespace,C0321 1230 1161 … … 1242 1173 if opts['qmin'] is None: 1243 1174 opts['qmin'] = 0.001*opts['qmax'] 1175 if opts['datafile'] is not None: 1176 data = load_data(os.path.expanduser(opts['datafile'])) 1177 else: 1178 data, _ = make_data(opts) 1244 1179 1245 1180 comparison = any(PAR_SPLIT in v for v in values) … … 1281 1216 opts['cutoff'] = [float(opts['cutoff'])]*2 1282 1217 1283 if PAR_SPLIT in opts['res']: 1284 opts['res'] = [float(k) for k in opts['res'].split(PAR_SPLIT, 2)] 1285 comparison = True 1286 else: 1287 opts['res'] = [float(opts['res'])]*2 1288 1289 if opts['datafile'] is not None: 1290 data = load_data(os.path.expanduser(opts['datafile'])) 1291 else: 1292 # Hack around the fact that make_data doesn't take a pair of resolutions 1293 res = opts['res'] 1294 opts['res'] = res[0] 1295 data0, _ = make_data(opts) 1296 if res[0] != res[1]: 1297 opts['res'] = res[1] 1298 data1, _ = make_data(opts) 1299 else: 1300 data1 = data0 1301 opts['res'] = res 1302 data = data0, data1 1303 1304 base = make_engine(model_info[0], data[0], opts['engine'][0], 1218 base = make_engine(model_info[0], data, opts['engine'][0], 1305 1219 opts['cutoff'][0], opts['ngauss'][0]) 1306 1220 if comparison: 1307 comp = make_engine(model_info[1], data [1], opts['engine'][1],1221 comp = make_engine(model_info[1], data, opts['engine'][1], 1308 1222 opts['cutoff'][1], opts['ngauss'][1]) 1309 1223 else: … … 1462 1376 path = os.path.dirname(info.filename) 1463 1377 url = "file://" + path.replace("\\", "/")[2:] + "/" 1464 rst2html.view_html_ wxapp(html, url)1378 rst2html.view_html_qtapp(html, url) 1465 1379 1466 1380 def explore(opts): -
sasmodels/core.py
r4341dd4 r3221de0 37 37 if CUSTOM_MODEL_PATH == "": 38 38 CUSTOM_MODEL_PATH = joinpath(os.path.expanduser("~"), ".sasmodels", "custom_models") 39 #if not os.path.isdir(CUSTOM_MODEL_PATH):40 #os.makedirs(CUSTOM_MODEL_PATH)39 if not os.path.isdir(CUSTOM_MODEL_PATH): 40 os.makedirs(CUSTOM_MODEL_PATH) 41 41 42 42 # TODO: refactor composite model support -
sasmodels/data.py
r1a8c11c rd86f0fc 36 36 37 37 import numpy as np # type: ignore 38 from numpy import sqrt, sin, cos, pi39 38 40 39 # pylint: disable=unused-import … … 302 301 303 302 304 def empty_data1D(q, resolution=0.0 , L=0., dL=0.):303 def empty_data1D(q, resolution=0.0): 305 304 # type: (np.ndarray, float) -> Data1D 306 r"""305 """ 307 306 Create empty 1D data using the given *q* as the x value. 308 307 309 rms *resolution* $\Delta q/q$ defaults to 0%. If wavelength *L* and rms 310 wavelength divergence *dL* are defined, then *resolution* defines 311 rms $\Delta \theta/\theta$ for the lowest *q*, with $\theta$ derived from 312 $q = 4\pi/\lambda \sin(\theta)$. 308 *resolution* dq/q defaults to 5%. 313 309 """ 314 310 … … 317 313 Iq, dIq = None, None 318 314 q = np.asarray(q) 319 if L != 0 and resolution != 0: 320 theta = np.arcsin(q*L/(4*pi)) 321 dtheta = theta[0]*resolution 322 ## Solving Gaussian error propagation from 323 ## Dq^2 = (dq/dL)^2 DL^2 + (dq/dtheta)^2 Dtheta^2 324 ## gives 325 ## (Dq/q)^2 = (DL/L)**2 + (Dtheta/tan(theta))**2 326 ## Take the square root and multiply by q, giving 327 ## Dq = (4*pi/L) * sqrt((sin(theta)*dL/L)**2 + (cos(theta)*dtheta)**2) 328 dq = (4*pi/L) * sqrt((sin(theta)*dL/L)**2 + (cos(theta)*dtheta)**2) 329 else: 330 dq = resolution * q 331 332 data = Data1D(q, Iq, dx=dq, dy=dIq) 315 data = Data1D(q, Iq, dx=resolution * q, dy=dIq) 333 316 data.filename = "fake data" 334 317 return data … … 503 486 # Note: masks merge, so any masked theory points will stay masked, 504 487 # and the data mask will be added to it. 505 #mtheory = masked_array(theory, data.mask.copy()) 506 theory_x = data.x[~data.mask] 507 mtheory = masked_array(theory) 488 mtheory = masked_array(theory, data.mask.copy()) 508 489 mtheory[~np.isfinite(mtheory)] = masked 509 490 if view is 'log': 510 491 mtheory[mtheory <= 0] = masked 511 plt.plot( theory_x, scale*mtheory, '-')492 plt.plot(data.x, scale*mtheory, '-') 512 493 all_positive = all_positive and (mtheory > 0).all() 513 494 some_present = some_present or (mtheory.count() > 0) … … 545 526 546 527 if use_resid: 547 theory_x = data.x[~data.mask] 548 mresid = masked_array(resid) 528 mresid = masked_array(resid, data.mask.copy()) 549 529 mresid[~np.isfinite(mresid)] = masked 550 530 some_present = (mresid.count() > 0) … … 552 532 if num_plots > 1: 553 533 plt.subplot(1, num_plots, use_calc + 2) 554 plt.plot( theory_x, mresid, '.')534 plt.plot(data.x, mresid, '.') 555 535 plt.xlabel("$q$/A$^{-1}$") 556 536 plt.ylabel('residuals') -
sasmodels/direct_model.py
r1a8c11c rd18d6dd 250 250 qmax = getattr(data, 'qmax', np.inf) 251 251 accuracy = getattr(data, 'accuracy', 'Low') 252 index = (data.mask == 0)& (q >= qmin) & (q <= qmax)252 index = ~data.mask & (q >= qmin) & (q <= qmax) 253 253 if data.data is not None: 254 254 index &= ~np.isnan(data.data) … … 263 263 elif self.data_type == 'Iq': 264 264 index = (data.x >= data.qmin) & (data.x <= data.qmax) 265 mask = getattr(data, 'mask', None)266 if mask is not None:267 index &= (mask == 0)268 265 if data.y is not None: 269 266 index &= ~np.isnan(data.y) -
sasmodels/jitter.py
r1198f90 rb3703f5 774 774 # set small jitter as 0 if multiple pd dims 775 775 dims = sum(v > 0 for v in jitter) 776 limit = [0, 0 .5, 5][dims]776 limit = [0, 0, 0.5, 5][dims] 777 777 jitter = [0 if v < limit else v for v in jitter] 778 778 axes.cla() -
sasmodels/kernel_iq.c
r7c35fda rdc6f601 83 83 in_spin = clip(in_spin, 0.0, 1.0); 84 84 out_spin = clip(out_spin, 0.0, 1.0); 85 // Previous version of this function took the square root of the weights, 86 // under the assumption that 87 // 85 // Note: sasview 3.1 scaled all slds by sqrt(weight) and assumed that 88 86 // w*I(q, rho1, rho2, ...) = I(q, sqrt(w)*rho1, sqrt(w)*rho2, ...) 89 // 90 // However, since the weights are applied to the final intensity and 91 // are not interned inside the I(q) function, we want the full 92 // weight and not the square root. Any function using 93 // set_spin_weights as part of calculating an amplitude will need to 94 // manually take that square root, but there is currently no such 95 // function. 96 weight[0] = (1.0-in_spin) * (1.0-out_spin); // dd 97 weight[1] = (1.0-in_spin) * out_spin; // du 98 weight[2] = in_spin * (1.0-out_spin); // ud 99 weight[3] = in_spin * out_spin; // uu 87 // which is likely to be the case for simple models. 88 weight[0] = sqrt((1.0-in_spin) * (1.0-out_spin)); // dd 89 weight[1] = sqrt((1.0-in_spin) * out_spin); // du.real 90 weight[2] = sqrt(in_spin * (1.0-out_spin)); // ud.real 91 weight[3] = sqrt(in_spin * out_spin); // uu 100 92 weight[4] = weight[1]; // du.imag 101 93 weight[5] = weight[2]; // ud.imag -
sasmodels/kerneldll.py
r1a3559f rbf94e6e 99 99 pass 100 100 # pylint: enable=unused-import 101 102 if "SAS_DLL_PATH" in os.environ:103 SAS_DLL_PATH = os.environ["SAS_DLL_PATH"]104 else:105 # Assume the default location of module DLLs is in .sasmodels/compiled_models.106 SAS_DLL_PATH = os.path.join(os.path.expanduser("~"), ".sasmodels", "compiled_models")107 101 108 102 if "SAS_COMPILER" in os.environ: … … 129 123 # add openmp support if not running on a mac 130 124 if sys.platform != "darwin": 131 # OpenMP seems to be broken on gcc 5.4.0 (ubuntu 16.04.9) 132 # Shut it off for all unix until we can investigate. 133 #CC.append("-fopenmp") 134 pass 125 CC.append("-fopenmp") 135 126 def compile_command(source, output): 136 127 """unix compiler command""" … … 167 158 return CC + [source, "-o", output, "-lm"] 168 159 160 # Assume the default location of module DLLs is in .sasmodels/compiled_models. 161 DLL_PATH = os.path.join(os.path.expanduser("~"), ".sasmodels", "compiled_models") 162 169 163 ALLOW_SINGLE_PRECISION_DLLS = True 170 164 … … 203 197 return path 204 198 205 return joinpath( SAS_DLL_PATH, basename)199 return joinpath(DLL_PATH, basename) 206 200 207 201 … … 212 206 exist yet if it hasn't been compiled. 213 207 """ 214 return os.path.join( SAS_DLL_PATH, dll_name(model_info, dtype))208 return os.path.join(DLL_PATH, dll_name(model_info, dtype)) 215 209 216 210 … … 231 225 models are not allowed as DLLs. 232 226 233 Set *sasmodels.kerneldll.SAS_DLL_PATH* to the compiled dll output path. 234 Alternatively, set the environment variable *SAS_DLL_PATH*. 227 Set *sasmodels.kerneldll.DLL_PATH* to the compiled dll output path. 235 228 The default is in ~/.sasmodels/compiled_models. 236 229 """ … … 251 244 if need_recompile: 252 245 # Make sure the DLL path exists 253 if not os.path.exists( SAS_DLL_PATH):254 os.makedirs( SAS_DLL_PATH)246 if not os.path.exists(DLL_PATH): 247 os.makedirs(DLL_PATH) 255 248 basename = splitext(os.path.basename(dll))[0] + "_" 256 249 system_fd, filename = tempfile.mkstemp(suffix=".c", prefix=basename) -
sasmodels/models/core_shell_parallelepiped.c
rdbf1a60 re077231 59 59 60 60 // outer integral (with gauss points), integration limits = 0, 1 61 // substitute d_cos_alpha for sin_alpha d_alpha62 61 double outer_sum = 0; //initialize integral 63 62 for( int i=0; i<GAUSS_N; i++) { 64 63 const double cos_alpha = 0.5 * ( GAUSS_Z[i] + 1.0 ); 65 64 const double mu = half_q * sqrt(1.0-cos_alpha*cos_alpha); 65 66 // inner integral (with gauss points), integration limits = 0, pi/2 66 67 const double siC = length_c * sas_sinx_x(length_c * cos_alpha * half_q); 67 68 const double siCt = tC * sas_sinx_x(tC * cos_alpha * half_q); 68 69 // inner integral (with gauss points), integration limits = 0, 170 // substitute beta = PI/2 u (so 2/PI * d_(PI/2 * beta) = d_beta)71 69 double inner_sum = 0.0; 72 70 for(int j=0; j<GAUSS_N; j++) { 73 const double u= 0.5 * ( GAUSS_Z[j] + 1.0 );71 const double beta = 0.5 * ( GAUSS_Z[j] + 1.0 ); 74 72 double sin_beta, cos_beta; 75 SINCOS(M_PI_2* u, sin_beta, cos_beta);73 SINCOS(M_PI_2*beta, sin_beta, cos_beta); 76 74 const double siA = length_a * sas_sinx_x(length_a * mu * sin_beta); 77 75 const double siB = length_b * sas_sinx_x(length_b * mu * cos_beta); … … 93 91 inner_sum += GAUSS_W[j] * f * f; 94 92 } 95 // now complete change of inner integration variable (1-0)/(1-(-1))= 0.596 93 inner_sum *= 0.5; 97 94 // now sum up the outer integral 98 95 outer_sum += GAUSS_W[i] * inner_sum; 99 96 } 100 // now complete change of outer integration variable (1-0)/(1-(-1))= 0.5101 97 outer_sum *= 0.5; 102 98 -
sasmodels/models/core_shell_parallelepiped.py
rf89ec96 r97be877 4 4 5 5 Calculates the form factor for a rectangular solid with a core-shell structure. 6 The thickness and the scattering length density of the shell or "rim" can be 7 different on each (pair) of faces. The three dimensions of the core of the 8 parallelepiped (strictly here a cuboid) may be given in *any* size order as 9 long as the particles are randomly oriented (i.e. take on all possible 10 orientations see notes on 2D below). To avoid multiple fit solutions, 11 especially with Monte-Carlo fit methods, it may be advisable to restrict their 12 ranges. There may be a number of closely similar "best fits", so some trial and 13 error, or fixing of some dimensions at expected values, may help. 6 The thickness and the scattering length density of the shell or 7 "rim" can be different on each (pair) of faces. 14 8 15 9 The form factor is normalized by the particle volume $V$ such that … … 17 11 .. math:: 18 12 19 I(q) = \frac{\text{scale}}{V} \langle P(q,\alpha,\beta) \rangle 20 + \text{background} 13 I(q) = \text{scale}\frac{\langle f^2 \rangle}{V} + \text{background} 21 14 22 15 where $\langle \ldots \rangle$ is an average over all possible orientations 23 of the rectangular solid, and the usual $\Delta \rho^2 \ V^2$ term cannot be 24 pulled out of the form factor term due to the multiple slds in the model. 25 26 The core of the solid is defined by the dimensions $A$, $B$, $C$ here shown 27 such that $A < B < C$. 28 29 .. figure:: img/parallelepiped_geometry.jpg 30 31 Core of the core shell parallelepiped with the corresponding definition 32 of sides. 33 16 of the rectangular solid. 17 18 The function calculated is the form factor of the rectangular solid below. 19 The core of the solid is defined by the dimensions $A$, $B$, $C$ such that 20 $A < B < C$. 21 22 .. image:: img/core_shell_parallelepiped_geometry.jpg 34 23 35 24 There are rectangular "slabs" of thickness $t_A$ that add to the $A$ dimension 36 25 (on the $BC$ faces). There are similar slabs on the $AC$ $(=t_B)$ and $AB$ 37 $(=t_C)$ faces. The projection in the $AB$ plane is 38 39 .. figure:: img/core_shell_parallelepiped_projection.jpg 40 41 AB cut through the core-shell parallelipiped showing the cross secion of 42 four of the six shell slabs. As can be seen, this model leaves **"gaps"** 43 at the corners of the solid. 44 45 46 The total volume of the solid is thus given as 26 $(=t_C)$ faces. The projection in the $AB$ plane is then 27 28 .. image:: img/core_shell_parallelepiped_projection.jpg 29 30 The volume of the solid is 47 31 48 32 .. math:: 49 33 50 34 V = ABC + 2t_ABC + 2t_BAC + 2t_CAB 35 36 **meaning that there are "gaps" at the corners of the solid.** 51 37 52 38 The intensity calculated follows the :ref:`parallelepiped` model, with the 53 39 core-shell intensity being calculated as the square of the sum of the 54 amplitudes of the core and the slabs on the edges. The scattering amplitude is 55 computed for a particular orientation of the core-shell parallelepiped with 56 respect to the scattering vector and then averaged over all possible 57 orientations, where $\alpha$ is the angle between the $z$ axis and the $C$ axis 58 of the parallelepiped, and $\beta$ is the angle between the projection of the 59 particle in the $xy$ detector plane and the $y$ axis. 60 61 .. math:: 62 63 P(q)=\frac {\int_{0}^{\pi/2}\int_{0}^{\pi/2}F^2(q,\alpha,\beta) \ sin\alpha 64 \ d\alpha \ d\beta} {\int_{0}^{\pi/2} \ sin\alpha \ d\alpha \ d\beta} 65 66 and 67 68 .. math:: 69 70 F(q,\alpha,\beta) 40 amplitudes of the core and the slabs on the edges. 41 42 the scattering amplitude is computed for a particular orientation of the 43 core-shell parallelepiped with respect to the scattering vector and then 44 averaged over all possible orientations, where $\alpha$ is the angle between 45 the $z$ axis and the $C$ axis of the parallelepiped, $\beta$ is 46 the angle between projection of the particle in the $xy$ detector plane 47 and the $y$ axis. 48 49 .. math:: 50 51 F(Q) 71 52 &= (\rho_\text{core}-\rho_\text{solvent}) 72 53 S(Q_A, A) S(Q_B, B) S(Q_C, C) \\ 73 54 &+ (\rho_\text{A}-\rho_\text{solvent}) 74 \left[S(Q_A, A+2t_A) - S(Q_A, A)\right] S(Q_B, B) S(Q_C, C) \\55 \left[S(Q_A, A+2t_A) - S(Q_A, Q)\right] S(Q_B, B) S(Q_C, C) \\ 75 56 &+ (\rho_\text{B}-\rho_\text{solvent}) 76 57 S(Q_A, A) \left[S(Q_B, B+2t_B) - S(Q_B, B)\right] S(Q_C, C) \\ … … 82 63 .. math:: 83 64 84 S(Q _X, L) = L \frac{\sin (\tfrac{1}{2} Q_X L)}{\tfrac{1}{2} Q_XL}65 S(Q, L) = L \frac{\sin \tfrac{1}{2} Q L}{\tfrac{1}{2} Q L} 85 66 86 67 and … … 88 69 .. math:: 89 70 90 Q_A &= q\sin\alpha \sin\beta \\91 Q_B &= q\sin\alpha \cos\beta \\92 Q_C &= q\cos\alpha71 Q_A &= \sin\alpha \sin\beta \\ 72 Q_B &= \sin\alpha \cos\beta \\ 73 Q_C &= \cos\alpha 93 74 94 75 95 76 where $\rho_\text{core}$, $\rho_\text{A}$, $\rho_\text{B}$ and $\rho_\text{C}$ 96 are the scattering length sof the parallelepiped core, and the rectangular77 are the scattering length of the parallelepiped core, and the rectangular 97 78 slabs of thickness $t_A$, $t_B$ and $t_C$, respectively. $\rho_\text{solvent}$ 98 79 is the scattering length of the solvent. 99 80 100 .. note::101 102 the code actually implements two substitutions: $d(cos\alpha)$ is103 substituted for -$sin\alpha \ d\alpha$ (note that in the104 :ref:`parallelepiped` code this is explicitly implemented with105 $\sigma = cos\alpha$), and $\beta$ is set to $\beta = u \pi/2$ so that106 $du = \pi/2 \ d\beta$. Thus both integrals go from 0 to 1 rather than 0107 to $\pi/2$.108 109 81 FITTING NOTES 110 82 ~~~~~~~~~~~~~ 111 83 112 #. There are many parameters in this model. Hold as many fixed as possible with 113 known values, or you will certainly end up at a solution that is unphysical. 114 115 #. The 2nd virial coefficient of the core_shell_parallelepiped is calculated 116 based on the the averaged effective radius $(=\sqrt{(A+2t_A)(B+2t_B)/\pi})$ 117 and length $(C+2t_C)$ values, after appropriately sorting the three 118 dimensions to give an oblate or prolate particle, to give an effective radius 119 for $S(q)$ when $P(q) * S(q)$ is applied. 120 121 #. For 2d data the orientation of the particle is required, described using 122 angles $\theta$, $\phi$ and $\Psi$ as in the diagrams below, where $\theta$ 123 and $\phi$ define the orientation of the director in the laboratry reference 124 frame of the beam direction ($z$) and detector plane ($x-y$ plane), while 125 the angle $\Psi$ is effectively the rotational angle around the particle 126 $C$ axis. For $\theta = 0$ and $\phi = 0$, $\Psi = 0$ corresponds to the 127 $B$ axis oriented parallel to the y-axis of the detector with $A$ along 128 the x-axis. For other $\theta$, $\phi$ values, the order of rotations 129 matters. In particular, the parallelepiped must first be rotated $\theta$ 130 degrees in the $x-z$ plane before rotating $\phi$ degrees around the $z$ 131 axis (in the $x-y$ plane). Applying orientational distribution to the 132 particle orientation (i.e `jitter` to one or more of these angles) can get 133 more confusing as `jitter` is defined **NOT** with respect to the laboratory 134 frame but the particle reference frame. It is thus highly recmmended to 135 read :ref:`orientation` for further details of the calculation and angular 136 dispersions. 137 138 .. note:: For 2d, constraints must be applied during fitting to ensure that the 139 order of sides chosen is not altered, and hence that the correct definition 140 of angles is preserved. For the default choice shown here, that means 141 ensuring that the inequality $A < B < C$ is not violated, The calculation 142 will not report an error, but the results may be not correct. 84 If the scale is set equal to the particle volume fraction, $\phi$, the returned 85 value is the scattered intensity per unit volume, $I(q) = \phi P(q)$. However, 86 **no interparticle interference effects are included in this calculation.** 87 88 There are many parameters in this model. Hold as many fixed as possible with 89 known values, or you will certainly end up at a solution that is unphysical. 90 91 The returned value is in units of |cm^-1|, on absolute scale. 92 93 NB: The 2nd virial coefficient of the core_shell_parallelepiped is calculated 94 based on the the averaged effective radius $(=\sqrt{(A+2t_A)(B+2t_B)/\pi})$ 95 and length $(C+2t_C)$ values, after appropriately sorting the three dimensions 96 to give an oblate or prolate particle, to give an effective radius, 97 for $S(Q)$ when $P(Q) * S(Q)$ is applied. 98 99 For 2d data the orientation of the particle is required, described using 100 angles $\theta$, $\phi$ and $\Psi$ as in the diagrams below, for further 101 details of the calculation and angular dispersions see :ref:`orientation`. 102 The angle $\Psi$ is the rotational angle around the *long_c* axis. For example, 103 $\Psi = 0$ when the *short_b* axis is parallel to the *x*-axis of the detector. 104 105 For 2d, constraints must be applied during fitting to ensure that the 106 inequality $A < B < C$ is not violated, and hence the correct definition 107 of angles is preserved. The calculation will not report an error, 108 but the results may be not correct. 143 109 144 110 .. figure:: img/parallelepiped_angle_definition.png 145 111 146 112 Definition of the angles for oriented core-shell parallelepipeds. 147 Note that rotation $\theta$, initially in the $x -z$ plane, is carried113 Note that rotation $\theta$, initially in the $xz$ plane, is carried 148 114 out first, then rotation $\phi$ about the $z$ axis, finally rotation 149 $\Psi$ is now around the $C$ axis of the particle. The neutron or X-ray150 beam is along the $z$ axis and the detecotr defines the $x-y$ plane.115 $\Psi$ is now around the axis of the cylinder. The neutron or X-ray 116 beam is along the $z$ axis. 151 117 152 118 .. figure:: img/parallelepiped_angle_projection.png … … 154 120 Examples of the angles for oriented core-shell parallelepipeds against the 155 121 detector plane. 156 157 158 Validation159 ----------160 161 Cross-checked against hollow rectangular prism and rectangular prism for equal162 thickness overlapping sides, and by Monte Carlo sampling of points within the163 shape for non-uniform, non-overlapping sides.164 165 122 166 123 References … … 178 135 179 136 * **Author:** NIST IGOR/DANSE **Date:** pre 2010 180 * **Converted to sasmodels by:** Miguel Gonzale z**Date:** February 26, 2016137 * **Converted to sasmodels by:** Miguel Gonzales **Date:** February 26, 2016 181 138 * **Last Modified by:** Paul Kienzle **Date:** October 17, 2017 182 * **Last Reviewed by:** Paul Butler **Date:** May 24, 2018 - documentation 183 updated 139 * Cross-checked against hollow rectangular prism and rectangular prism for 140 equal thickness overlapping sides, and by Monte Carlo sampling of points 141 within the shape for non-uniform, non-overlapping sides. 184 142 """ 185 143 -
sasmodels/models/core_shell_sphere.py
rdc76240 r2d81cfe 21 21 .. math:: 22 22 23 F (q) = \frac{3}{V_s}\left[23 F^2(q) = \frac{3}{V_s}\left[ 24 24 V_c(\rho_c-\rho_s)\frac{\sin(qr_c)-qr_c\cos(qr_c)}{(qr_c)^3} + 25 25 V_s(\rho_s-\rho_\text{solv})\frac{\sin(qr_s)-qr_s\cos(qr_s)}{(qr_s)^3} -
sasmodels/models/guinier.py
rc9fc873 r2d81cfe 7 7 .. math:: 8 8 9 I(q) = \text{scale} \cdot \exp{\left[ \frac{-Q^2 R_g^2}{3} \right]}9 I(q) = \text{scale} \cdot \exp{\left[ \frac{-Q^2R_g^2}{3} \right]} 10 10 + \text{background} 11 11 … … 19 19 20 20 .. math:: q = \sqrt{q_x^2 + q_y^2} 21 22 In scattering, the radius of gyration $R_g$ quantifies the objects's23 distribution of SLD (not mass density, as in mechanics) from the objects's24 SLD centre of mass. It is defined by25 26 .. math:: R_g^2 = \frac{\sum_i\rho_i\left(r_i-r_0\right)^2}{\sum_i\rho_i}27 28 where $r_0$ denotes the object's SLD centre of mass and $\rho_i$ is the SLD at29 a point $i$.30 31 Notice that $R_g^2$ may be negative (since SLD can be negative), which happens32 when a form factor $P(Q)$ is increasing with $Q$ rather than decreasing. This33 can occur for core/shell particles, hollow particles, or for composite34 particles with domains of different SLDs in a solvent with an SLD close to the35 average match point. (Alternatively, this might be regarded as there being an36 internal inter-domain "structure factor" within a single particle which gives37 rise to a peak in the scattering).38 39 To specify a negative value of $R_g^2$ in SasView, simply give $R_g$ a negative40 value ($R_g^2$ will be evaluated as $R_g |R_g|$). Note that the physical radius41 of gyration, of the exterior of the particle, will still be large and positive.42 It is only the apparent size from the small $Q$ data that will give a small or43 negative value of $R_g^2$.44 21 45 22 References … … 65 42 66 43 # ["name", "units", default, [lower, upper], "type","description"], 67 parameters = [["rg", "Ang", 60.0, [ -inf, inf], "", "Radius of Gyration"]]44 parameters = [["rg", "Ang", 60.0, [0, inf], "", "Radius of Gyration"]] 68 45 69 46 Iq = """ 70 double exponent = fabs(rg)*rg*q*q/3.0;47 double exponent = rg*rg*q*q/3.0; 71 48 double value = exp(-exponent); 72 49 return value; … … 89 66 90 67 # parameters for demo 91 demo = dict(scale=1.0, background=0.001, rg=60.0)68 demo = dict(scale=1.0, rg=60.0) 92 69 93 70 # parameters for unit tests -
sasmodels/models/mass_surface_fractal.py
r7994359 r2d81cfe 39 39 The surface ( $D_s$ ) and mass ( $D_m$ ) fractal dimensions are only 40 40 valid if $0 < surface\_dim < 6$ , $0 < mass\_dim < 6$ , and 41 $(surface\_dim + mass\_dim ) < 6$ . 42 Older versions of sasview may have the default primary particle radius 43 larger than the cluster radius, this was an error, also present in the 44 Schmidt review paper below. The primary particle should be the smaller 45 as described in the original Hurd et.al. who also point out that 46 polydispersity in the primary particle sizes may affect their 47 apparent surface fractal dimension. 48 41 $(surface\_dim + mass\_dim ) < 6$ . 42 49 43 50 44 References 51 45 ---------- 52 46 53 .. [#] P Schmidt, *J Appl. Cryst.*, 24 (1991) 414-435 Equation(19) 54 .. [#] A J Hurd, D W Schaefer, J E Martin, *Phys. Rev. A*, 55 35 (1987) 2361-2364 Equation(2) 47 P Schmidt, *J Appl. Cryst.*, 24 (1991) 414-435 Equation(19) 56 48 57 Authorship and Verification 58 ---------------------------- 59 60 * **Converted to sasmodels by:** Piotr Rozyczko **Date:** Jan 20, 2016 61 * **Last Reviewed by:** Richard Heenan **Date:** May 30, 2018 49 A J Hurd, D W Schaefer, J E Martin, *Phys. Rev. A*, 50 35 (1987) 2361-2364 Equation(2) 62 51 """ 63 52 … … 78 67 rg_primary = rg 79 68 background = background 69 Ref: Schmidt, J Appl Cryst, eq(19), (1991), 24, 414-435 80 70 Hurd, Schaefer, Martin, Phys Rev A, eq(2),(1987),35, 2361-2364 81 71 Note that 0 < Ds< 6 and 0 < Dm < 6. … … 88 78 ["fractal_dim_mass", "", 1.8, [0.0, 6.0], "", "Mass fractal dimension"], 89 79 ["fractal_dim_surf", "", 2.3, [0.0, 6.0], "", "Surface fractal dimension"], 90 ["rg_cluster", "Ang", 4000., [0.0, inf], "", "Cluster radius of gyration"],91 ["rg_primary", "Ang", 86.7, [0.0, inf], "", "Primary particle radius of gyration"],80 ["rg_cluster", "Ang", 86.7, [0.0, inf], "", "Cluster radius of gyration"], 81 ["rg_primary", "Ang", 4000., [0.0, inf], "", "Primary particle radius of gyration"], 92 82 ] 93 83 # pylint: enable=bad-whitespace, line-too-long … … 117 107 fractal_dim_mass=1.8, 118 108 fractal_dim_surf=2.3, 119 rg_cluster= 4000.0,120 rg_primary= 86.7)109 rg_cluster=86.7, 110 rg_primary=4000.0) 121 111 122 112 tests = [ 123 113 124 # Accuracy tests based on content in test/utest_other_models.py All except first, changed so rg_cluster is the larger, RKH 30 May 2018125 [{'fractal_dim_mass': 1.8,114 # Accuracy tests based on content in test/utest_other_models.py 115 [{'fractal_dim_mass': 1.8, 126 116 'fractal_dim_surf': 2.3, 127 117 'rg_cluster': 86.7, … … 133 123 [{'fractal_dim_mass': 3.3, 134 124 'fractal_dim_surf': 1.0, 135 'rg_cluster': 4000.0,136 'rg_primary': 90.0,137 }, 0.001, 0. 0932516614456],125 'rg_cluster': 90.0, 126 'rg_primary': 4000.0, 127 }, 0.001, 0.18562699016], 138 128 139 129 [{'fractal_dim_mass': 1.3, 140 'fractal_dim_surf': 2.0,141 'rg_cluster': 2000.0,142 'rg_primary': 90.0,130 'fractal_dim_surf': 1.0, 131 'rg_cluster': 90.0, 132 'rg_primary': 2000.0, 143 133 'background': 0.8, 144 }, 0.001, 1. 28296431786],134 }, 0.001, 1.16539753641], 145 135 146 136 [{'fractal_dim_mass': 2.3, 147 'fractal_dim_surf': 3.1,148 'rg_cluster': 1000.0,149 'rg_primary': 30.0,137 'fractal_dim_surf': 1.0, 138 'rg_cluster': 90.0, 139 'rg_primary': 1000.0, 150 140 'scale': 10.0, 151 141 'background': 0.0, 152 }, 0.051, 0.00 333804044899],142 }, 0.051, 0.000169548800377], 153 143 ] -
sasmodels/models/parallelepiped.c
rdbf1a60 r108e70e 38 38 inner_total += GAUSS_W[j] * square(si1 * si2); 39 39 } 40 // now complete change of inner integration variable (1-0)/(1-(-1))= 0.541 40 inner_total *= 0.5; 42 41 … … 44 43 outer_total += GAUSS_W[i] * inner_total * si * si; 45 44 } 46 // now complete change of outer integration variable (1-0)/(1-(-1))= 0.547 45 outer_total *= 0.5; 48 46 -
sasmodels/models/parallelepiped.py
rf89ec96 ref07e95 2 2 # Note: model title and parameter table are inserted automatically 3 3 r""" 4 The form factor is normalized by the particle volume. 5 For information about polarised and magnetic scattering, see 6 the :ref:`magnetism` documentation. 7 4 8 Definition 5 9 ---------- 6 10 7 This model calculates the scattering from a rectangular solid 8 (:numref:`parallelepiped-image`). 9 If you need to apply polydispersity, see also :ref:`rectangular-prism`. For 10 information about polarised and magnetic scattering, see 11 the :ref:`magnetism` documentation. 11 This model calculates the scattering from a rectangular parallelepiped 12 (\:numref:`parallelepiped-image`\). 13 If you need to apply polydispersity, see also :ref:`rectangular-prism`. 12 14 13 15 .. _parallelepiped-image: … … 19 21 20 22 The three dimensions of the parallelepiped (strictly here a cuboid) may be 21 given in *any* size order as long as the particles are randomly oriented (i.e. 22 take on all possible orientations see notes on 2D below). To avoid multiple fit 23 solutions, especially with Monte-Carlo fit methods, it may be advisable to 24 restrict their ranges. There may be a number of closely similar "best fits", so 25 some trial and error, or fixing of some dimensions at expected values, may 26 help. 27 28 The form factor is normalized by the particle volume and the 1D scattering 29 intensity $I(q)$ is then calculated as: 23 given in *any* size order. To avoid multiple fit solutions, especially 24 with Monte-Carlo fit methods, it may be advisable to restrict their ranges. 25 There may be a number of closely similar "best fits", so some trial and 26 error, or fixing of some dimensions at expected values, may help. 27 28 The 1D scattering intensity $I(q)$ is calculated as: 30 29 31 30 .. Comment by Miguel Gonzalez: … … 40 39 41 40 I(q) = \frac{\text{scale}}{V} (\Delta\rho \cdot V)^2 42 \left< P(q, \alpha , \beta) \right> + \text{background}41 \left< P(q, \alpha) \right> + \text{background} 43 42 44 43 where the volume $V = A B C$, the contrast is defined as 45 $\Delta\rho = \rho_\text{p} - \rho_\text{solvent}$, $P(q, \alpha, \beta)$ 46 is the form factor corresponding to a parallelepiped oriented 47 at an angle $\alpha$ (angle between the long axis C and $\vec q$), and $\beta$ 48 (the angle between the projection of the particle in the $xy$ detector plane 49 and the $y$ axis) and the averaging $\left<\ldots\right>$ is applied over all 50 orientations. 44 $\Delta\rho = \rho_\text{p} - \rho_\text{solvent}$, 45 $P(q, \alpha)$ is the form factor corresponding to a parallelepiped oriented 46 at an angle $\alpha$ (angle between the long axis C and $\vec q$), 47 and the averaging $\left<\ldots\right>$ is applied over all orientations. 51 48 52 49 Assuming $a = A/B < 1$, $b = B /B = 1$, and $c = C/B > 1$, the 53 form factor is given by (Mittelbach and Porod, 1961 [#Mittelbach]_)50 form factor is given by (Mittelbach and Porod, 1961) 54 51 55 52 .. math:: … … 69 66 \mu &= qB 70 67 71 where substitution of $\sigma = cos\alpha$ and $\beta = \pi/2 \ u$ have been 72 applied. 73 74 For **oriented** particles, the 2D scattering intensity, $I(q_x, q_y)$, is 75 given as: 76 77 .. math:: 78 79 I(q_x, q_y) = \frac{\text{scale}}{V} (\Delta\rho \cdot V)^2 P(q_x, q_y) 68 The scattering intensity per unit volume is returned in units of |cm^-1|. 69 70 NB: The 2nd virial coefficient of the parallelepiped is calculated based on 71 the averaged effective radius, after appropriately sorting the three 72 dimensions, to give an oblate or prolate particle, $(=\sqrt{AB/\pi})$ and 73 length $(= C)$ values, and used as the effective radius for 74 $S(q)$ when $P(q) \cdot S(q)$ is applied. 75 76 For 2d data the orientation of the particle is required, described using 77 angles $\theta$, $\phi$ and $\Psi$ as in the diagrams below, for further details 78 of the calculation and angular dispersions see :ref:`orientation` . 79 80 .. Comment by Miguel Gonzalez: 81 The following text has been commented because I think there are two 82 mistakes. Psi is the rotational angle around C (but I cannot understand 83 what it means against the q plane) and psi=0 corresponds to a||x and b||y. 84 85 The angle $\Psi$ is the rotational angle around the $C$ axis against 86 the $q$ plane. For example, $\Psi = 0$ when the $B$ axis is parallel 87 to the $x$-axis of the detector. 88 89 The angle $\Psi$ is the rotational angle around the $C$ axis. 90 For $\theta = 0$ and $\phi = 0$, $\Psi = 0$ corresponds to the $B$ axis 91 oriented parallel to the y-axis of the detector with $A$ along the x-axis. 92 For other $\theta$, $\phi$ values, the parallelepiped has to be first rotated 93 $\theta$ degrees in the $z-x$ plane and then $\phi$ degrees around the $z$ axis, 94 before doing a final rotation of $\Psi$ degrees around the resulting $C$ axis 95 of the particle to obtain the final orientation of the parallelepiped. 96 97 .. _parallelepiped-orientation: 98 99 .. figure:: img/parallelepiped_angle_definition.png 100 101 Definition of the angles for oriented parallelepiped, shown with $A<B<C$. 102 103 .. figure:: img/parallelepiped_angle_projection.png 104 105 Examples of the angles for an oriented parallelepiped against the 106 detector plane. 107 108 On introducing "Orientational Distribution" in the angles, "distribution of 109 theta" and "distribution of phi" parameters will appear. These are actually 110 rotations about axes $\delta_1$ and $\delta_2$ of the parallelepiped, 111 perpendicular to the $a$ x $c$ and $b$ x $c$ faces. (When $\theta = \phi = 0$ 112 these are parallel to the $Y$ and $X$ axes of the instrument.) The third 113 orientation distribution, in $\psi$, is about the $c$ axis of the particle, 114 perpendicular to the $a$ x $b$ face. Some experimentation may be required to 115 understand the 2d patterns fully as discussed in :ref:`orientation` . 116 117 For a given orientation of the parallelepiped, the 2D form factor is 118 calculated as 119 120 .. math:: 121 122 P(q_x, q_y) = \left[\frac{\sin(\tfrac{1}{2}qA\cos\alpha)}{(\tfrac{1}{2}qA\cos\alpha)}\right]^2 123 \left[\frac{\sin(\tfrac{1}{2}qB\cos\beta)}{(\tfrac{1}{2}qB\cos\beta)}\right]^2 124 \left[\frac{\sin(\tfrac{1}{2}qC\cos\gamma)}{(\tfrac{1}{2}qC\cos\gamma)}\right]^2 125 126 with 127 128 .. math:: 129 130 \cos\alpha &= \hat A \cdot \hat q, \\ 131 \cos\beta &= \hat B \cdot \hat q, \\ 132 \cos\gamma &= \hat C \cdot \hat q 133 134 and the scattering intensity as: 135 136 .. math:: 137 138 I(q_x, q_y) = \frac{\text{scale}}{V} V^2 \Delta\rho^2 P(q_x, q_y) 80 139 + \text{background} 81 140 … … 89 148 with scale being the volume fraction. 90 149 91 Where $P(q_x, q_y)$ for a given orientation of the form factor is calculated as92 93 .. math::94 95 P(q_x, q_y) = \left[\frac{\sin(\tfrac{1}{2}qA\cos\alpha)}{(\tfrac{1}96 {2}qA\cos\alpha)}\right]^297 \left[\frac{\sin(\tfrac{1}{2}qB\cos\beta)}{(\tfrac{1}98 {2}qB\cos\beta)}\right]^299 \left[\frac{\sin(\tfrac{1}{2}qC\cos\gamma)}{(\tfrac{1}100 {2}qC\cos\gamma)}\right]^2101 102 with103 104 .. math::105 106 \cos\alpha &= \hat A \cdot \hat q, \\107 \cos\beta &= \hat B \cdot \hat q, \\108 \cos\gamma &= \hat C \cdot \hat q109 110 111 FITTING NOTES112 ~~~~~~~~~~~~~113 114 #. The 2nd virial coefficient of the parallelepiped is calculated based on115 the averaged effective radius, after appropriately sorting the three116 dimensions, to give an oblate or prolate particle, $(=\sqrt{AB/\pi})$ and117 length $(= C)$ values, and used as the effective radius for118 $S(q)$ when $P(q) \cdot S(q)$ is applied.119 120 #. For 2d data the orientation of the particle is required, described using121 angles $\theta$, $\phi$ and $\Psi$ as in the diagrams below, where $\theta$122 and $\phi$ define the orientation of the director in the laboratry reference123 frame of the beam direction ($z$) and detector plane ($x-y$ plane), while124 the angle $\Psi$ is effectively the rotational angle around the particle125 $C$ axis. For $\theta = 0$ and $\phi = 0$, $\Psi = 0$ corresponds to the126 $B$ axis oriented parallel to the y-axis of the detector with $A$ along127 the x-axis. For other $\theta$, $\phi$ values, the order of rotations128 matters. In particular, the parallelepiped must first be rotated $\theta$129 degrees in the $x-z$ plane before rotating $\phi$ degrees around the $z$130 axis (in the $x-y$ plane). Applying orientational distribution to the131 particle orientation (i.e `jitter` to one or more of these angles) can get132 more confusing as `jitter` is defined **NOT** with respect to the laboratory133 frame but the particle reference frame. It is thus highly recmmended to134 read :ref:`orientation` for further details of the calculation and angular135 dispersions.136 137 .. note:: For 2d, constraints must be applied during fitting to ensure that the138 order of sides chosen is not altered, and hence that the correct definition139 of angles is preserved. For the default choice shown here, that means140 ensuring that the inequality $A < B < C$ is not violated, The calculation141 will not report an error, but the results may be not correct.142 143 .. _parallelepiped-orientation:144 145 .. figure:: img/parallelepiped_angle_definition.png146 147 Definition of the angles for oriented parallelepiped, shown with $A<B<C$.148 149 .. figure:: img/parallelepiped_angle_projection.png150 151 Examples of the angles for an oriented parallelepiped against the152 detector plane.153 154 .. Comment by Paul Butler155 I am commenting this section out as we are trying to minimize the amount of156 oritentational detail here and encourage the user to go to the full157 orientation documentation so that changes can be made in just one place.158 below is the commented paragrah:159 On introducing "Orientational Distribution" in the angles, "distribution of160 theta" and "distribution of phi" parameters will appear. These are actually161 rotations about axes $\delta_1$ and $\delta_2$ of the parallelepiped,162 perpendicular to the $a$ x $c$ and $b$ x $c$ faces. (When $\theta = \phi = 0$163 these are parallel to the $Y$ and $X$ axes of the instrument.) The third164 orientation distribution, in $\psi$, is about the $c$ axis of the particle,165 perpendicular to the $a$ x $b$ face. Some experimentation may be required to166 understand the 2d patterns fully as discussed in :ref:`orientation` .167 168 150 169 151 Validation … … 174 156 angles. 175 157 158 176 159 References 177 160 ---------- 178 161 179 .. [#Mittelbach] P Mittelbach and G Porod, *Acta Physica Austriaca*, 180 14 (1961) 185-211 181 .. [#]R Nayuk and K Huber, *Z. Phys. Chem.*, 226 (2012) 837-854162 P Mittelbach and G Porod, *Acta Physica Austriaca*, 14 (1961) 185-211 163 164 R Nayuk and K Huber, *Z. Phys. Chem.*, 226 (2012) 837-854 182 165 183 166 Authorship and Verification … … 186 169 * **Author:** NIST IGOR/DANSE **Date:** pre 2010 187 170 * **Last Modified by:** Paul Kienzle **Date:** April 05, 2017 188 * **Last Reviewed by:** Miguel Gonzales and Paul Butler **Date:** May 24, 189 2018 - documentation updated 171 * **Last Reviewed by:** Richard Heenan **Date:** April 06, 2017 190 172 """ 191 173 -
sasmodels/resolution.py
r0b9c6df r2d81cfe 20 20 MINIMUM_RESOLUTION = 1e-8 21 21 MINIMUM_ABSOLUTE_Q = 0.02 # relative to the minimum q in the data 22 PINHOLE_N_SIGMA = 2.5 # From: Barker & Pedersen 1995 JAC23 22 24 23 class Resolution(object): … … 66 65 *q_calc* is the list of points to calculate, or None if this should 67 66 be estimated from the *q* and *q_width*. 68 69 *nsigma* is the width of the resolution function. Should be 2.5. 70 See :func:`pinhole_resolution` for details. 71 """ 72 def __init__(self, q, q_width, q_calc=None, nsigma=PINHOLE_N_SIGMA): 67 """ 68 def __init__(self, q, q_width, q_calc=None, nsigma=3): 73 69 #*min_step* is the minimum point spacing to use when computing the 74 70 #underlying model. It should be on the order of … … 86 82 87 83 # Protect against models which are not defined for very low q. Limit 88 # the smallest q value evaluated to 0.02*min. Note that negative q 89 # values are trimmed even for broad resolution. Although not possible 90 # from the geometry, they may appear since we are using a truncated 91 # gaussian to represent resolution rather than a skew distribution. 84 # the smallest q value evaluated (in absolute) to 0.02*min 92 85 cutoff = MINIMUM_ABSOLUTE_Q*np.min(self.q) 93 self.q_calc = self.q_calc[ self.q_calc>= cutoff]86 self.q_calc = self.q_calc[abs(self.q_calc) >= cutoff] 94 87 95 88 # Build weight matrix from calculated q values 96 89 self.weight_matrix = pinhole_resolution( 97 self.q_calc, self.q, np.maximum(q_width, MINIMUM_RESOLUTION) ,98 nsigma=nsigma)90 self.q_calc, self.q, np.maximum(q_width, MINIMUM_RESOLUTION)) 91 self.q_calc = abs(self.q_calc) 99 92 100 93 def apply(self, theory): … … 108 101 *q* points at which the data is measured. 109 102 110 * qx_width* slit width in qx111 112 * qy_width* slit height in qy103 *dqx* slit width in qx 104 105 *dqy* slit height in qy 113 106 114 107 *q_calc* is the list of points to calculate, or None if this should … … 161 154 162 155 163 def pinhole_resolution(q_calc, q, q_width , nsigma=PINHOLE_N_SIGMA):164 r"""156 def pinhole_resolution(q_calc, q, q_width): 157 """ 165 158 Compute the convolution matrix *W* for pinhole resolution 1-D data. 166 159 … … 169 162 *W*, the resolution smearing can be computed using *dot(W,q)*. 170 163 171 Note that resolution is limited to $\pm 2.5 \sigma$.[1] The true resolution172 function is a broadened triangle, and does not extend over the entire173 range $(-\infty, +\infty)$. It is important to impose this limitation174 since some models fall so steeply that the weighted value in gaussian175 tails would otherwise dominate the integral.176 177 164 *q_calc* must be increasing. *q_width* must be greater than zero. 178 179 [1] Barker, J. G., and J. S. Pedersen. 1995. Instrumental Smearing Effects180 in Radially Symmetric Small-Angle Neutron Scattering by Numerical and181 Analytical Methods. Journal of Applied Crystallography 28 (2): 105--14.182 https://doi.org/10.1107/S0021889894010095.183 165 """ 184 166 # The current algorithm is a midpoint rectangle rule. In the test case, … … 188 170 cdf = erf((edges[:, None] - q[None, :]) / (sqrt(2.0)*q_width)[None, :]) 189 171 weights = cdf[1:] - cdf[:-1] 190 # Limit q range to +/- 2.5 sigma191 qhigh = q + nsigma*q_width192 #qlow = q - nsigma*q_width # linear limits193 qlow = q*q/qhigh # log limits194 weights[q_calc[:, None] < qlow[None, :]] = 0.195 weights[q_calc[:, None] > qhigh[None, :]] = 0.196 172 weights /= np.sum(weights, axis=0)[None, :] 197 173 return weights … … 518 494 519 495 520 def gaussian(q, q0, dq , nsigma=2.5):521 """ 522 Return the truncatedGaussian resolution function.496 def gaussian(q, q0, dq): 497 """ 498 Return the Gaussian resolution function. 523 499 524 500 *q0* is the center, *dq* is the width and *q* are the points to evaluate. 525 501 """ 526 # Calculate the density of the tails; the resulting gaussian needs to be 527 # scaled by this amount in ordere to integrate to 1.0 528 two_tail_density = 2 * (1 + erf(-nsigma/sqrt(2)))/2 529 return exp(-0.5*((q-q0)/dq)**2)/(sqrt(2*pi)*dq)/(1-two_tail_density) 502 return exp(-0.5*((q-q0)/dq)**2)/(sqrt(2*pi)*dq) 530 503 531 504 … … 585 558 586 559 587 def romberg_pinhole_1d(q, q_width, form, pars, nsigma= 2.5):560 def romberg_pinhole_1d(q, q_width, form, pars, nsigma=5): 588 561 """ 589 562 Romberg integration for pinhole resolution. … … 705 678 np.testing.assert_equal(output, self.y) 706 679 707 # TODO: turn pinhole/slit demos into tests708 709 @unittest.skip("suppress comparison with old version; pinhole calc changed")710 680 def test_pinhole(self): 711 681 """ … … 716 686 theory = 12.0-1000.0*resolution.q_calc 717 687 output = resolution.apply(theory) 718 # Note: answer came from output of previous run. Non-integer719 # values at ends come from the fact that q_calc does not720 # extend beyond q, and so the weights don't balance.721 688 answer = [ 722 10.4 7037734, 9.86925860,723 9., 8., 7., 6., 5., 4.,724 3.13074140, 2.52962266,689 10.44785079, 9.84991299, 8.98101708, 690 7.99906585, 6.99998311, 6.00001689, 691 5.00093415, 4.01898292, 3.15008701, 2.55214921, 725 692 ] 726 693 np.testing.assert_allclose(output, answer, atol=1e-8) … … 765 732 self._compare(q, output, answer, 1e-6) 766 733 767 @unittest.skip("suppress comparison with old version; pinhole calc changed")768 734 def test_pinhole(self): 769 735 """ … … 780 746 self._compare(q, output, answer, 3e-4) 781 747 782 @unittest.skip("suppress comparison with old version; pinhole calc changed")783 748 def test_pinhole_romberg(self): 784 749 """ … … 796 761 # 2*np.pi/pars['radius']/200) 797 762 #tol = 0.001 798 ## The default 2.5sigma and no extra points gets 1%763 ## The default 3 sigma and no extra points gets 1% 799 764 q_calc = None # type: np.ndarray 800 765 tol = 0.01 … … 1115 1080 1116 1081 if isinstance(resolution, Slit1D): 1117 width, height = resolution. qx_width, resolution.qy_width1082 width, height = resolution.dqx, resolution.dqy 1118 1083 Iq_romb = romberg_slit_1d(resolution.q, width, height, model, pars) 1119 1084 else: -
sasmodels/rst2html.py
r1fbadb2 r2d81cfe 56 56 # others don't work properly with math_output! 57 57 if math_output == "mathjax": 58 # TODO: this is copied from docs/conf.py; there should be only one 59 mathjax_path = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML" 60 settings = {"math_output": math_output + " " + mathjax_path} 58 settings = {"math_output": math_output} 61 59 else: 62 60 settings = {"math-output": math_output} -
sasmodels/sasview_model.py
rd533590 r05df1de 686 686 self._intermediate_results = getattr(calculator, 'results', None) 687 687 calculator.release() 688 #self._model.release()688 self._model.release() 689 689 return result 690 690 … … 719 719 720 720 def set_dispersion(self, parameter, dispersion): 721 # type: (str, weights.Dispersion) -> None721 # type: (str, weights.Dispersion) -> Dict[str, Any] 722 722 """ 723 723 Set the dispersion object for a model parameter … … 742 742 self.dispersion[parameter] = dispersion.get_pars() 743 743 else: 744 raise ValueError("%r is not a dispersity or orientation parameter" 745 % parameter) 744 raise ValueError("%r is not a dispersity or orientation parameter") 746 745 747 746 def _dispersion_mesh(self):
Note: See TracChangeset
for help on using the changeset viewer.