Changeset 6cff473 in sasmodels
- Timestamp:
- Apr 4, 2017 11:31:53 AM (8 years ago)
- Branches:
- master, core_shell_microgels, costrafo411, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- f68e2a5
- Parents:
- cb0dc22 (diff), a769b54 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - git-author:
- Andrew Jackson <andrew.jackson@…> (04/04/17 11:31:53)
- git-committer:
- GitHub <noreply@…> (04/04/17 11:31:53)
- Files:
-
- 1 added
- 45 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/compare.py
rf72d70a r6cff473 30 30 31 31 import sys 32 import os 32 33 import math 33 34 import datetime … … 40 41 from . import kerneldll 41 42 from . import exception 42 from .data import plot_theory, empty_data1D, empty_data2D 43 from .data import plot_theory, empty_data1D, empty_data2D, load_data 43 44 from .direct_model import DirectModel 44 45 from .convert import revert_name, revert_pars, constrain_new_to_old … … 85 86 -html shows the model docs instead of running the model 86 87 -title="note" adds note to the plot title, after the model name 88 -data="path" uses q, dq from the data file 87 89 88 90 Any two calculation engines can be selected for comparison: … … 747 749 comp = opts['engines'][1] if have_comp else None 748 750 data = opts['data'] 751 use_data = have_base ^ have_comp 749 752 750 753 # Plot if requested … … 763 766 if have_base: 764 767 if have_comp: plt.subplot(131) 765 plot_theory(data, base_value, view=view, use_data= False, limits=limits)768 plot_theory(data, base_value, view=view, use_data=use_data, limits=limits) 766 769 plt.title("%s t=%.2f ms"%(base.engine, base_time)) 767 770 #cbar_title = "log I" … … 769 772 if have_base: plt.subplot(132) 770 773 if not opts['is2d'] and have_base: 771 plot_theory(data, base_value, view=view, use_data= False, limits=limits)772 plot_theory(data, comp_value, view=view, use_data= False, limits=limits)774 plot_theory(data, base_value, view=view, use_data=use_data, limits=limits) 775 plot_theory(data, comp_value, view=view, use_data=use_data, limits=limits) 773 776 plt.title("%s t=%.2f ms"%(comp.engine, comp_time)) 774 777 #cbar_title = "log I" … … 784 787 err[err>cutoff] = cutoff 785 788 #err,errstr = base/comp,"ratio" 786 plot_theory(data, None, resid=err, view=errview, use_data= False)789 plot_theory(data, None, resid=err, view=errview, use_data=use_data) 787 790 if view == 'linear': 788 791 plt.xscale('linear') … … 834 837 VALUE_OPTIONS = [ 835 838 # Note: random is both a name option and a value option 836 'cutoff', 'random', 'nq', 'res', 'accuracy', 'title', 839 'cutoff', 'random', 'nq', 'res', 'accuracy', 'title', 'data', 837 840 ] 838 841 … … 951 954 'html' : False, 952 955 'title' : None, 956 'data' : None, 953 957 } 954 958 engines = [] … … 971 975 elif arg.startswith('-cutoff='): opts['cutoff'] = float(arg[8:]) 972 976 elif arg.startswith('-random='): opts['seed'] = int(arg[8:]) 973 elif arg.startswith('-title'): opts['title'] = arg[7:] 977 elif arg.startswith('-title='): opts['title'] = arg[7:] 978 elif arg.startswith('-data='): opts['data'] = arg[6:] 974 979 elif arg == '-random': opts['seed'] = np.random.randint(1000000) 975 980 elif arg == '-preset': opts['seed'] = -1 … … 1112 1117 1113 1118 # Create the computational engines 1114 data, _ = make_data(opts) 1119 if opts['data'] is not None: 1120 data = load_data(os.path.expanduser(opts['data'])) 1121 else: 1122 data, _ = make_data(opts) 1115 1123 if n1: 1116 1124 base = make_engine(model_info, data, engines[0], opts['cutoff']) -
sasmodels/data.py
r40a87fa ra769b54 54 54 if data is None: 55 55 raise IOError("Data %r could not be loaded" % filename) 56 if hasattr(data, 'x'): 57 data.qmin, data.qmax = data.x.min(), data.x.max() 58 data.mask = (np.isnan(data.y) if data.y is not None 59 else np.zeros_like(data.x, dtype='bool')) 56 60 return data 57 61 … … 348 352 # data, but they already handle the masking and graph markup already, so 349 353 # do not repeat. 350 if hasattr(data, ' lam'):354 if hasattr(data, 'isSesans') and data.isSesans: 351 355 _plot_result_sesans(data, None, None, use_data=True, limits=limits) 352 356 elif hasattr(data, 'qx_data'): … … 376 380 *Iq_calc* is the raw theory values without resolution smearing 377 381 """ 378 if hasattr(data, ' lam'):382 if hasattr(data, 'isSesans') and data.isSesans: 379 383 _plot_result_sesans(data, theory, resid, use_data=True, limits=limits) 380 384 elif hasattr(data, 'qx_data'): -
sasmodels/direct_model.py
rb397165 ra769b54 192 192 193 193 # interpret data 194 if hasattr(data, ' lam'):194 if hasattr(data, 'isSesans') and data.isSesans: 195 195 self.data_type = 'sesans' 196 196 elif hasattr(data, 'qx_data'): -
doc/ref/index.rst
rc34a31f r9f12fbe 10 10 refs.rst 11 11 gpu/gpu_computations.rst 12 gpu/opencl_installation.rst 12 13 magnetism/magnetism.rst 13 14 sesans/sans_to_sesans.rst -
example/fit.py
r1182da5 rf4b36fa 24 24 % section) 25 25 data = radial_data if section != "tangential" else tan_data 26 phi = 0 if section != "tangential" else 90 26 theta = 89.9 if section != "tangential" else 0 27 phi = 90 27 28 kernel = load_model(name, dtype="single") 28 29 cutoff = 1e-3 … … 30 31 if name == "ellipsoid": 31 32 model = Model(kernel, 32 scale=0.08, 33 r _polar=15, r_equatorial=800,33 scale=0.08, background=35, 34 radius_polar=15, radius_equatorial=800, 34 35 sld=.291, sld_solvent=7.105, 35 background=0, 36 theta=90, phi=phi, 37 theta_pd=15, theta_pd_n=40, theta_pd_nsigma=3, 38 r_polar_pd=0.222296, r_polar_pd_n=1, r_polar_pd_nsigma=0, 39 r_equatorial_pd=.000128, r_equatorial_pd_n=1, r_equatorial_pd_nsigma=0, 36 theta=theta, phi=phi, 37 theta_pd=0, theta_pd_n=0, theta_pd_nsigma=3, 40 38 phi_pd=0, phi_pd_n=20, phi_pd_nsigma=3, 39 radius_polar_pd=0.222296, radius_polar_pd_n=1, radius_polar_pd_nsigma=0, 40 radius_equatorial_pd=.000128, radius_equatorial_pd_n=1, radius_equatorial_pd_nsigma=0, 41 41 ) 42 42 43 44 43 # SET THE FITTING PARAMETERS 45 model.r_polar.range(15, 1000) 46 model.r_equatorial.range(15, 1000) 47 model.theta_pd.range(0, 360) 44 model.radius_polar.range(15, 1000) 45 model.radius_equatorial.range(15, 1000) 46 #model.theta.range(0, 90) 47 #model.theta_pd.range(0,10) 48 model.phi_pd.range(0,20) 49 model.phi.range(0, 180) 48 50 model.background.range(0,1000) 49 51 model.scale.range(0, 10) 50 52 51 53 52 53 54 elif name == "lamellar": 54 55 model = Model(kernel, 55 scale=0.08, 56 scale=0.08, background=0.003, 56 57 thickness=19.2946, 57 58 sld=5.38,sld_sol=7.105, 58 background=0.003,59 59 thickness_pd= 0.37765, thickness_pd_n=10, thickness_pd_nsigma=3, 60 60 ) 61 62 61 63 62 # SET THE FITTING PARAMETERS … … 77 76 radius_pd=.0084, radius_pd_n=10, radius_pd_nsigma=3, 78 77 length_pd=0.493, length_pd_n=10, length_pd_nsigma=3, 79 phi_pd=0, phi_pd_n=5 ,phi_pd_nsigma=3,)78 phi_pd=0, phi_pd_n=5 phi_pd_nsigma=3,) 80 79 """ 81 80 pars = dict( 82 81 scale=.01, background=35, 83 82 sld=.291, sld_solvent=5.77, 84 radius=250, length=178, 85 theta=90, phi=phi, 83 radius=250, length=178, 86 84 radius_pd=0.1, radius_pd_n=5, radius_pd_nsigma=3, 87 85 length_pd=0.1,length_pd_n=5, length_pd_nsigma=3, 88 theta_pd=10, theta_pd_n=50, theta_pd_nsigma=3, 89 phi_pd=0, phi_pd_n=10, phi_pd_nsigma=3) 86 theta=theta, phi=phi, 87 theta_pd=0, theta_pd_n=0, theta_pd_nsigma=3, 88 phi_pd=10, phi_pd_n=20, phi_pd_nsigma=3) 90 89 model = Model(kernel, **pars) 91 90 … … 93 92 model.radius.range(1, 500) 94 93 model.length.range(1, 5000) 95 model.theta.range(-90,100)96 model. theta_pd.range(0, 30)97 model. theta_pd_n = model.theta_pd + 594 #model.theta.range(0, 90) 95 model.phi.range(0, 180) 96 model.phi_pd.range(0, 30) 98 97 model.radius_pd.range(0, 1) 99 model.length_pd.range(0, 2)98 model.length_pd.range(0, 1) 100 99 model.scale.range(0, 10) 101 100 model.background.range(0, 100) … … 104 103 elif name == "core_shell_cylinder": 105 104 model = Model(kernel, 106 scale= .031, radius=19.5, thickness=30, length=22, 107 sld_core=7.105, sld_shell=.291, sdl_solvent=7.105, 108 background=0, theta=0, phi=phi, 109 105 scale= .031, background=0, 106 radius=19.5, thickness=30, length=22, 107 sld_core=7.105, sld_shell=.291, sld_solvent=7.105, 110 108 radius_pd=0.26, radius_pd_n=10, radius_pd_nsigma=3, 111 109 length_pd=0.26, length_pd_n=10, length_pd_nsigma=3, 112 110 thickness_pd=1, thickness_pd_n=1, thickness_pd_nsigma=1, 113 theta_pd=1, theta_pd_n=10, theta_pd_nsigma=3, 114 phi_pd=0.1, phi_pd_n=1, phi_pd_nsigma=1, 111 theta=theta, phi=phi, 112 theta_pd=1, theta_pd_n=1, theta_pd_nsigma=3, 113 phi_pd=0, phi_pd_n=20, phi_pd_nsigma=3, 115 114 ) 116 115 117 116 # SET THE FITTING PARAMETERS 118 #model.radius.range(115, 1000)119 #model.length.range(0, 2500)117 model.radius.range(115, 1000) 118 model.length.range(0, 2500) 120 119 #model.thickness.range(18, 38) 121 120 #model.thickness_pd.range(0, 1) 122 121 #model.phi.range(0, 90) 122 model.phi_pd.range(0,20) 123 123 #model.radius_pd.range(0, 1) 124 124 #model.length_pd.range(0, 1) … … 131 131 elif name == "capped_cylinder": 132 132 model = Model(kernel, 133 scale=.08, radius=20, cap_radius=40, length=400, 133 scale=.08, background=35, 134 radius=20, cap_radius=40, length=400, 134 135 sld=1, sld_solvent=6.3, 135 background=0, theta=0, phi=phi,136 136 radius_pd=.1, radius_pd_n=5, radius_pd_nsigma=3, 137 137 cap_radius_pd=.1, cap_radius_pd_n=5, cap_radius_pd_nsigma=3, 138 138 length_pd=.1, length_pd_n=1, length_pd_nsigma=0, 139 theta_pd=.1, theta_pd_n=1, theta_pd_nsigma=0, 140 phi_pd=.1, phi_pd_n=1, phi_pd_nsigma=0, 139 theta=theta, phi=phi, 140 theta_pd=0, theta_pd_n=1, theta_pd_nsigma=0, 141 phi_pd=10, phi_pd_n=20, phi_pd_nsigma=0, 141 142 ) 142 143 144 model.radius.range(115, 1000) 145 model.length.range(0, 2500) 146 #model.thickness.range(18, 38) 147 #model.thickness_pd.range(0, 1) 148 #model.phi.range(0, 90) 149 model.phi_pd.range(0,20) 150 #model.radius_pd.range(0, 1) 151 #model.length_pd.range(0, 1) 152 #model.theta_pd.range(0, 360) 153 #model.background.range(0,5) 143 154 model.scale.range(0, 1) 144 155 … … 146 157 elif name == "triaxial_ellipsoid": 147 158 model = Model(kernel, 148 scale=0.08, req_minor=15, req_major=20, rpolar=500, 159 scale=0.08, background=35, 160 radius_equat_minor=15, radius_equat_major=20, radius_polar=500, 149 161 sld=7.105, solvent_sld=.291, 150 background=5, theta=0, phi=phi, psi=0, 162 radius_equat_minor_pd=.1, radius_equat_minor_pd_n=1, radius_equat_minor_pd_nsigma=0, 163 radius_equat_major_pd=.1, radius_equat_major_pd_n=1, radius_equat_major_pd_nsigma=0, 164 radius_polar_pd=.1, radius_polar_pd_n=1, radius_polar_pd_nsigma=0, 165 theta=theta, phi=phi, psi=0, 151 166 theta_pd=20, theta_pd_n=40, theta_pd_nsigma=3, 152 167 phi_pd=.1, phi_pd_n=1, phi_pd_nsigma=0, 153 168 psi_pd=30, psi_pd_n=1, psi_pd_nsigma=0, 154 req_minor_pd=.1, req_minor_pd_n=1, req_minor_pd_nsigma=0,155 req_major_pd=.1, req_major_pd_n=1, req_major_pd_nsigma=0,156 rpolar_pd=.1, rpolar_pd_n=1, rpolar_pd_nsigma=0,157 169 ) 158 170 159 171 # SET THE FITTING PARAMETERS 160 model.r eq_minor.range(15, 1000)161 model.r eq_major.range(15, 1000)162 #model.r polar.range(15, 1000)172 model.radius_equat_minor.range(15, 1000) 173 model.radius_equat_major.range(15, 1000) 174 #model.radius_polar.range(15, 1000) 163 175 #model.background.range(0,1000) 164 176 #model.theta_pd.range(0, 360) … … 173 185 M = Experiment(data=data, model=model) 174 186 if section == "both": 175 tan_model = Model(model. kernel, **model.parameters())187 tan_model = Model(model.sasmodel, **model.parameters()) 176 188 tan_model.phi = model.phi - 90 177 189 tan_model.cutoff = cutoff -
sasmodels/compare_many.py
r424fe00 rf72d70a 106 106 header = ('\n"Model","%s","Count","%d","Dimension","%s"' 107 107 % (name, N, "2D" if is_2d else "1D")) 108 if not mono: header += ',"Cutoff",%g'%(cutoff,) 108 if not mono: 109 header += ',"Cutoff",%g'%(cutoff,) 109 110 print(header) 110 111 … … 161 162 max_diff = [0] 162 163 for k in range(N): 163 print(" %s %d"%(name, k), file=sys.stderr)164 print("Model %s %d"%(name, k+1), file=sys.stderr) 164 165 seed = np.random.randint(1e6) 165 166 pars_i = randomize_pars(model_info, pars, seed) 166 167 constrain_pars(model_info, pars_i) 167 constrain_new_to_old(model_info, pars_i) 168 if 'sasview' in (base, comp): 169 constrain_new_to_old(model_info, pars_i) 168 170 if mono: 169 171 pars_i = suppress_pd(pars_i) … … 187 189 Print the command usage string. 188 190 """ 189 print("usage: compare_many.py MODEL COUNT (1dNQ|2dNQ) (CUTOFF|mono) (single|double|quad)") 191 print("usage: compare_many.py MODEL COUNT (1dNQ|2dNQ) (CUTOFF|mono) (single|double|quad)", 192 file=sys.stderr) 190 193 191 194 … … 204 207 print("""\ 205 208 206 MODEL is the model name of the model or "all" for all the models 207 in alphabetical order. 209 MODEL is the model name of the model or one of the model types listed in 210 sasmodels.core.list_models (all, py, c, double, single, opencl, 1d, 2d, 211 nonmagnetic, magnetic). Model types can be combined, such as 2d+single. 208 212 209 213 COUNT is the number of randomly generated parameter sets to try. A value … … 220 224 below the cutoff will be ignored. Use "mono" for monodisperse models. The 221 225 choice of polydisperse parameters, and the number of points in the distribution 222 is set in compare.py defaults for each model. 226 is set in compare.py defaults for each model. Polydispersity is given in the 227 "demo" attribute of each model. 223 228 224 229 PRECISION is the floating point precision to use for comparisons. If two 225 precisions are given, then compare one to the other, ignoring sasview. 230 precisions are given, then compare one to the other. Precision is one of 231 fast, single, double for GPU or single!, double!, quad! for DLL. If no 232 precision is given, then use single and double! respectively. 226 233 227 234 Available models: … … 233 240 Main program. 234 241 """ 235 if len(argv) not in ( 5, 6):242 if len(argv) not in (3, 4, 5, 6): 236 243 print_help() 237 244 return 238 245 239 model = argv[0] 240 if not (model in MODELS) and (model != "all"): 241 print('Bad model %s. Use "all" or one of:'%model) 246 target = argv[0] 247 try: 248 model_list = [target] if target in MODELS else core.list_models(target) 249 except ValueError: 250 print('Bad model %s. Use model type or one of:' % target, file=sys.stderr) 242 251 print_models() 252 print('model types: all, py, c, double, single, opencl, 1d, 2d, nonmagnetic, magnetic') 243 253 return 244 254 try: … … 247 257 assert argv[2][1] == 'd' 248 258 Nq = int(argv[2][2:]) 249 mono = argv[3] == 'mono'259 mono = len(argv) <= 3 or argv[3] == 'mono' 250 260 cutoff = float(argv[3]) if not mono else 0 251 base = argv[4] 252 comp = argv[5] if len(argv) > 5 else " sasview"261 base = argv[4] if len(argv) > 4 else "single" 262 comp = argv[5] if len(argv) > 5 else "double!" 253 263 except Exception: 254 264 traceback.print_exc() … … 258 268 data, index = make_data({'qmax':1.0, 'is2d':is2D, 'nq':Nq, 'res':0., 259 269 'accuracy': 'Low', 'view':'log', 'zero': False}) 260 model_list = [model] if model != "all" else MODELS261 270 for model in model_list: 262 271 compare_instance(model, data, index, N=count, mono=mono, -
sasmodels/conversion_table.py
r790b16bb r0c2da4b 549 549 "radius": "core_radius", 550 550 "sld_solvent": "core_sld", 551 "n_ pairs": "n_pairs",551 "n_shells": "n_pairs", 552 552 "thick_shell": "s_thickness", 553 553 "sld": "shell_sld", -
sasmodels/core.py
r52e9a45 r5124c969 69 69 * magnetic: models with an sld 70 70 * nommagnetic: models without an sld 71 """ 72 if kind and kind not in KINDS: 71 72 For multiple conditions, combine with plus. For example, *c+single+2d* 73 would return all oriented models implemented in C which can be computed 74 accurately with single precision arithmetic. 75 """ 76 if kind and any(k not in KINDS for k in kind.split('+')): 73 77 raise ValueError("kind not in " + ", ".join(KINDS)) 74 78 files = sorted(glob(joinpath(generate.MODEL_PATH, "[a-zA-Z]*.py"))) 75 79 available_models = [basename(f)[:-3] for f in files] 76 selected = [name for name in available_models if _matches(name, kind)] 80 if kind and '+' in kind: 81 all_kinds = kind.split('+') 82 condition = lambda name: all(_matches(name, k) for k in all_kinds) 83 else: 84 condition = lambda name: _matches(name, kind) 85 selected = [name for name in available_models if condition(name)] 77 86 78 87 return selected -
sasmodels/model_test.py
r479d0f3 r598857b 97 97 is_py = callable(model_info.Iq) 98 98 99 # Some OpenCL drivers seem to be flaky, and are not producing the 100 # expected result. Since we don't have known test values yet for 101 # all of our models, we are instead going to compare the results 102 # for the 'smoke test' (that is, evaluation at q=0.1 for the default 103 # parameters just to see that the model runs to completion) between 104 # the OpenCL and the DLL. To do this, we define a 'stash' which is 105 # shared between OpenCL and DLL tests. This is just a list. If the 106 # list is empty (which it will be when DLL runs, if the DLL runs 107 # first), then the results are appended to the list. If the list 108 # is not empty (which it will be when OpenCL runs second), the results 109 # are compared to the results stored in the first element of the list. 110 # This is a horrible stateful hack which only makes sense because the 111 # test suite is thrown away after being run once. 112 stash = [] 113 99 114 if is_py: # kernel implemented in python 100 115 test_name = "Model: %s, Kernel: python"%model_name … … 103 118 test_method_name, 104 119 platform="dll", # so that 105 dtype="double") 120 dtype="double", 121 stash=stash) 106 122 suite.addTest(test) 107 123 else: # kernel implemented in C 124 125 # test using dll if desired 126 if 'dll' in loaders or not core.HAVE_OPENCL: 127 test_name = "Model: %s, Kernel: dll"%model_name 128 test_method_name = "test_%s_dll" % model_info.id 129 test = ModelTestCase(test_name, model_info, 130 test_method_name, 131 platform="dll", 132 dtype="double", 133 stash=stash) 134 suite.addTest(test) 135 108 136 # test using opencl if desired and available 109 137 if 'opencl' in loaders and core.HAVE_OPENCL: … … 116 144 test = ModelTestCase(test_name, model_info, 117 145 test_method_name, 118 platform="ocl", dtype=None) 146 platform="ocl", dtype=None, 147 stash=stash) 119 148 #print("defining", test_name) 120 suite.addTest(test)121 122 # test using dll if desired123 if 'dll' in loaders or not core.HAVE_OPENCL:124 test_name = "Model: %s, Kernel: dll"%model_name125 test_method_name = "test_%s_dll" % model_info.id126 test = ModelTestCase(test_name, model_info,127 test_method_name,128 platform="dll",129 dtype="double")130 149 suite.addTest(test) 131 150 … … 144 163 """ 145 164 def __init__(self, test_name, model_info, test_method_name, 146 platform, dtype ):147 # type: (str, ModelInfo, str, str, DType ) -> None165 platform, dtype, stash): 166 # type: (str, ModelInfo, str, str, DType, List[Any]) -> None 148 167 self.test_name = test_name 149 168 self.info = model_info 150 169 self.platform = platform 151 170 self.dtype = dtype 171 self.stash = stash # container for the results of the first run 152 172 153 173 setattr(self, test_method_name, self.run_all) … … 167 187 #({}, (0.0, 0.0), None), 168 188 # test vector form 169 ({}, [0. 1]*2, [None]*2),189 ({}, [0.001, 0.01, 0.1], [None]*3), 170 190 ({}, [(0.1, 0.1)]*2, [None]*2), 171 191 # test that ER/VR will run if they exist … … 174 194 ] 175 195 176 tests = s elf.info.tests196 tests = smoke_tests + self.info.tests 177 197 try: 178 198 model = build_model(self.info, dtype=self.dtype, 179 199 platform=self.platform) 180 for test in smoke_tests + tests: 181 self.run_one(model, test) 182 183 if not tests and self.platform == "dll": 184 ## Uncomment the following to make forgetting the test 185 ## values an error. Only do so for the "dll" tests 186 ## to reduce noise from both opencl and dll, and because 187 ## python kernels use platform="dll". 188 #raise Exception("No test cases provided") 189 pass 200 results = [self.run_one(model, test) for test in tests] 201 if self.stash: 202 for test, target, actual in zip(tests, self.stash[0], results): 203 assert np.all(abs(target-actual) < 5e-5*abs(actual)),\ 204 "GPU/CPU comparison expected %s but got %s for %s"%(target, actual, test[0]) 205 else: 206 self.stash.append(results) 207 208 # Check for missing tests. Only do so for the "dll" tests 209 # to reduce noise from both opencl and dll, and because 210 # python kernels use platform="dll". 211 if self.platform == "dll": 212 missing = [] 213 ## Uncomment the following to require test cases 214 #missing = self._find_missing_tests() 215 if missing: 216 raise ValueError("Missing tests for "+", ".join(missing)) 190 217 191 218 except: 192 219 annotate_exception(self.test_name) 193 220 raise 221 222 def _find_missing_tests(self): 223 # type: () -> None 224 """make sure there are 1D, 2D, ER and VR tests as appropriate""" 225 model_has_VR = callable(self.info.VR) 226 model_has_ER = callable(self.info.ER) 227 model_has_1D = True 228 model_has_2D = any(p.type == 'orientation' 229 for p in self.info.parameters.kernel_parameters) 230 231 # Lists of tests that have a result that is not None 232 single = [test for test in self.info.tests 233 if not isinstance(test[2], list) and test[2] is not None] 234 tests_has_VR = any(test[1] == 'VR' for test in single) 235 tests_has_ER = any(test[1] == 'ER' for test in single) 236 tests_has_1D_single = any(isinstance(test[1], float) for test in single) 237 tests_has_2D_single = any(isinstance(test[1], tuple) for test in single) 238 239 multiple = [test for test in self.info.tests 240 if isinstance(test[2], list) 241 and not all(result is None for result in test[2])] 242 tests_has_1D_multiple = any(isinstance(test[1][0], float) 243 for test in multiple) 244 tests_has_2D_multiple = any(isinstance(test[1][0], tuple) 245 for test in multiple) 246 247 missing = [] 248 if model_has_VR and not tests_has_VR: 249 missing.append("VR") 250 if model_has_ER and not tests_has_ER: 251 missing.append("ER") 252 if model_has_1D and not (tests_has_1D_single or tests_has_1D_multiple): 253 missing.append("1D") 254 if model_has_2D and not (tests_has_2D_single or tests_has_2D_multiple): 255 missing.append("2D") 256 257 return missing 194 258 195 259 def run_one(self, model, test): … … 207 271 208 272 if x[0] == 'ER': 209 actual = [call_ER(model.info, pars)]273 actual = np.array([call_ER(model.info, pars)]) 210 274 elif x[0] == 'VR': 211 actual = [call_VR(model.info, pars)]275 actual = np.array([call_VR(model.info, pars)]) 212 276 elif isinstance(x[0], tuple): 213 277 qx, qy = zip(*x) … … 238 302 'f(%s); expected:%s; actual:%s' 239 303 % (xi, yi, actual_yi)) 304 return actual 240 305 241 306 return ModelTestCase -
sasmodels/modelinfo.py
r85fe7f8 r9c44b7b 230 230 defined as a sublist with the following elements: 231 231 232 *name* is the name that will be used in the call to the kernel 233 function and the name that will be displayed to the user. Names 232 *name* is the name that will be displayed to the user. Names 234 233 should be lower case, with words separated by underscore. If 235 acronyms are used, the whole acronym should be upper case. 234 acronyms are used, the whole acronym should be upper case. For vector 235 parameters, the name will be followed by *[len]* where *len* is an 236 integer length of the vector, or the name of the parameter which 237 controls the length. The attribute *id* will be created from name 238 without the length. 236 239 237 240 *units* should be one of *degrees* for angles, *Ang* for lengths, … … 603 606 # Using the call_parameters table, we already have expanded forms 604 607 # for each of the vector parameters; put them in a lookup table 605 expanded_pars = dict((p.name, p) for p in self.call_parameters) 608 # Note: p.id and p.name are currently identical for the call parameters 609 expanded_pars = dict((p.id, p) for p in self.call_parameters) 606 610 607 611 def append_group(name): … … 730 734 info.docs = kernel_module.__doc__ 731 735 info.category = getattr(kernel_module, 'category', None) 732 info.single = getattr(kernel_module, 'single', True)733 info.opencl = getattr(kernel_module, 'opencl', True)734 736 info.structure_factor = getattr(kernel_module, 'structure_factor', False) 735 737 info.profile_axes = getattr(kernel_module, 'profile_axes', ['x', 'y']) … … 745 747 info.profile = getattr(kernel_module, 'profile', None) # type: ignore 746 748 info.sesans = getattr(kernel_module, 'sesans', None) # type: ignore 749 # Default single and opencl to True for C models. Python models have callable Iq. 750 info.opencl = getattr(kernel_module, 'opencl', not callable(info.Iq)) 751 info.single = getattr(kernel_module, 'single', not callable(info.Iq)) 747 752 748 753 # multiplicity info -
sasmodels/models/core_multi_shell.c
r925ad6e rc3ccaec 8 8 } 9 9 10 double 11 form_volume(double core_radius, double n, double thickness[]); 12 double 13 form_volume(double core_radius, double n, double thickness[]) 10 static double 11 form_volume(double core_radius, double fp_n, double thickness[]) 14 12 { 15 13 double r = core_radius; 14 int n = (int)(fp_n+0.5); 16 15 for (int i=0; i < n; i++) { 17 16 r += thickness[i]; … … 20 19 } 21 20 22 double21 static double 23 22 Iq(double q, double core_sld, double core_radius, 24 double solvent_sld, double num_shells, double sld[], double thickness[]); 25 double 26 Iq(double q, double core_sld, double core_radius, 27 double solvent_sld, double num_shells, double sld[], double thickness[]) 23 double solvent_sld, double fp_n, double sld[], double thickness[]) 28 24 { 29 const int n = (int) ceil(num_shells);25 const int n = (int)(fp_n+0.5); 30 26 double f, r, last_sld; 31 27 r = core_radius; -
sasmodels/models/core_multi_shell.py
r925ad6e r5a0b3d7 107 107 Returns the SLD profile *r* (Ang), and *rho* (1e-6/Ang^2). 108 108 """ 109 n = int(n+0.5) 109 110 z = [] 110 111 rho = [] … … 133 134 def ER(radius, n, thickness): 134 135 """Effective radius""" 135 n = int(n[0] ) # n cannot bepolydisperse136 n = int(n[0]+0.5) # n is a control parameter and is not polydisperse 136 137 return np.sum(thickness[:n], axis=0) + radius 137 138 -
sasmodels/models/core_shell_parallelepiped.py
r797a8e3 rcb0dc22 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" 7 can be different on all three (pairs) of faces.** 6 The thickness and the scattering length density of the shell or 7 "rim" can be different on each (pair) of faces. However at this time 8 the model does **NOT** actually calculate a c face rim despite the presence of 9 the parameter. 10 11 .. note:: 12 This model was originally ported from NIST IGOR macros. However,t is not 13 yet fully understood by the SasView developers and is currently review. 8 14 9 15 The form factor is normalized by the particle volume $V$ such that … … 35 41 V = ABC + 2t_ABC + 2t_BAC + 2t_CAB 36 42 37 **meaning that there are "gaps" at the corners of the solid.** 43 **meaning that there are "gaps" at the corners of the solid.** Again note that 44 $t_C = 0$ currently. 38 45 39 46 The intensity calculated follows the :ref:`parallelepiped` model, with the … … 41 48 amplitudes of the core and shell, in the same manner as a core-shell model. 42 49 43 .. math::44 45 F_{a}(Q,\alpha,\beta)=46 \Bigg(\frac{sin(Q(L_A+2t_A)/2sin\alpha sin\beta)}{Q(L_A+2t_A)/2sin\alpha47 sin\beta)}48 - \frac{sin(QL_A/2sin\alpha sin\beta)}{QL_A/2sin\alpha sin\beta)} \Bigg)49 + \frac{sin(QL_B/2sin\alpha sin\beta)}{QL_B/2sin\alpha sin\beta)}50 + \frac{sin(QL_C/2sin\alpha sin\beta)}{QL_C/2sin\alpha sin\beta)}51 50 52 51 .. note:: … … 93 92 detector plane. 94 93 95 Validation96 ----------97 98 The model uses the form factor calculations implemented in a c-library provided99 by the NIST Center for Neutron Research (Kline, 2006).100 101 94 References 102 95 ---------- … … 113 106 114 107 * **Author:** NIST IGOR/DANSE **Date:** pre 2010 115 * **Last Modified by:** Paul Butler **Date:** September 30, 2016 116 * **Last Reviewed by:** Miguel Gonzales **Date:** March 21, 2016 108 * **Converted to sasmodels by:** Miguel Gonzales **Date:** February 26, 2016 109 * **Last Modified by:** Wojciech Potrzebowski **Date:** January 11, 2017 110 * **Currently Under review by:** Paul Butler 117 111 """ 118 112 -
sasmodels/models/ellipsoid.c
r925ad6e r130d4c7 4 4 double radius_polar, double radius_equatorial, double theta, double phi); 5 5 6 double _ellipsoid_kernel(double q, double radius_polar, double radius_equatorial, double sin_alpha); 7 double _ellipsoid_kernel(double q, double radius_polar, double radius_equatorial, double sin_alpha)6 static double 7 _ellipsoid_kernel(double q, double radius_polar, double radius_equatorial, double cos_alpha) 8 8 { 9 9 double ratio = radius_polar/radius_equatorial; 10 // Given the following under the radical: 11 // 1 + sin^2(T) (v^2 - 1) 12 // we can expand to match the form given in Guinier (1955) 13 // = (1 - sin^2(T)) + v^2 sin^2(T) = cos^2(T) + sin^2(T) 10 // Using ratio v = Rp/Re, we can expand the following to match the 11 // form given in Guinier (1955) 12 // r = Re * sqrt(1 + cos^2(T) (v^2 - 1)) 13 // = Re * sqrt( (1 - cos^2(T)) + v^2 cos^2(T) ) 14 // = Re * sqrt( sin^2(T) + v^2 cos^2(T) ) 15 // = sqrt( Re^2 sin^2(T) + Rp^2 cos^2(T) ) 16 // 14 17 // Instead of using pythagoras we could pass in sin and cos; this may be 15 18 // slightly better for 2D which has already computed it, but it introduces … … 17 20 // leave it as is. 18 21 const double r = radius_equatorial 19 * sqrt(1.0 + sin_alpha*sin_alpha*(ratio*ratio - 1.0));22 * sqrt(1.0 + cos_alpha*cos_alpha*(ratio*ratio - 1.0)); 20 23 const double f = sas_3j1x_x(q*r); 21 24 … … 39 42 double total = 0.0; 40 43 for (int i=0;i<76;i++) { 41 //const double sin_alpha = (Gauss76Z[i]*(upper-lower) + upper + lower)/2;42 const double sin_alpha = Gauss76Z[i]*zm + zb;43 total += Gauss76Wt[i] * _ellipsoid_kernel(q, radius_polar, radius_equatorial, sin_alpha);44 //const double cos_alpha = (Gauss76Z[i]*(upper-lower) + upper + lower)/2; 45 const double cos_alpha = Gauss76Z[i]*zm + zb; 46 total += Gauss76Wt[i] * _ellipsoid_kernel(q, radius_polar, radius_equatorial, cos_alpha); 44 47 } 45 48 // translate dx in [-1,1] to dx in [lower,upper] … … 59 62 double q, sin_alpha, cos_alpha; 60 63 ORIENT_SYMMETRIC(qx, qy, theta, phi, q, sin_alpha, cos_alpha); 61 const double form = _ellipsoid_kernel(q, radius_polar, radius_equatorial, sin_alpha);64 const double form = _ellipsoid_kernel(q, radius_polar, radius_equatorial, cos_alpha); 62 65 const double s = (sld - sld_solvent) * form_volume(radius_polar, radius_equatorial); 63 66 -
sasmodels/models/flexible_cylinder.c
r592343f rc3ccaec 1 1 static double 2 form_volume( length, kuhn_length,radius)2 form_volume(double length, double kuhn_length, double radius) 3 3 { 4 4 return 1.0; -
sasmodels/models/fractal.c
r925ad6e r4788822 1 1 #define INVALID(p) (p.fractal_dim < 0.0) 2 3 static double 4 form_volume(double radius) 5 { 6 return M_4PI_3 * cube(radius); 7 } 2 8 3 9 static double … … 13 19 14 20 //calculate P(q) for the spherical subunits 15 const double V = M_4PI_3*cube(radius);16 const double pq = V * square((sld_block-sld_solvent)*sas_3j1x_x(q*radius));21 const double pq = square(form_volume(radius) * (sld_block-sld_solvent) 22 *sas_3j1x_x(q*radius)); 17 23 18 24 // scale to units cm-1 sr-1 (assuming data on absolute scale) -
sasmodels/models/fractal.py
r925ad6e rdf89d77 20 20 .. math:: 21 21 22 P(q)&= F(qR_0)^2 23 24 F(q)&= \frac{3 (\sin x - x \cos x)}{x^3} 25 26 V_\text{particle} &= \frac{4}{3}\ \pi R_0 27 22 P(q)&= F(qR_0)^2 \\ 23 F(q)&= \frac{3 (\sin x - x \cos x)}{x^3} \\ 24 V_\text{particle} &= \frac{4}{3}\ \pi R_0 \\ 28 25 S(q) &= 1 + \frac{D_f\ \Gamma\!(D_f-1)}{[1+1/(q \xi)^2\ ]^{(D_f -1)/2}} 29 26 \frac{\sin[(D_f-1) \tan^{-1}(q \xi) ]}{(q R_0)^{D_f}} … … 32 29 is the fractal dimension, representing the self similarity of the structure. 33 30 Note that S(q) here goes negative if $D_f$ is too large, and the Gamma function 34 diverges at $D_f $=0 and $D_f$=1.31 diverges at $D_f=0$ and $D_f=1$. 35 32 36 33 **Polydispersity on the radius is provided for.** … … 47 44 ---------- 48 45 49 J Teixeira, *J. Appl. Cryst.*, 21 (1988) 781-78546 .. [#] J Teixeira, *J. Appl. Cryst.*, 21 (1988) 781-785 50 47 51 **Author:** NIST IGOR/DANSE **on:** pre 2010 48 Authorship and Verification 49 ---------------------------- 52 50 53 **Last Modified by:** Paul Butler **on:** March 20, 2016 54 55 **Last Reviewed by:** Paul Butler **on:** March 20, 2016 51 * **Author:** NIST IGOR/DANSE **Date:** pre 2010 52 * **Converted to sasmodels by:** Paul Butler **Date:** March 19, 2016 53 * **Last Modified by:** Paul Butler **Date:** March 12, 2017 54 * **Last Reviewed by:** Paul Butler **Date:** March 12, 2017 56 55 57 56 """ … … 84 83 parameters = [["volfraction", "", 0.05, [0.0, 1], "", 85 84 "volume fraction of blocks"], 86 ["radius", "Ang", 5.0, [0.0, inf], " ",85 ["radius", "Ang", 5.0, [0.0, inf], "volume", 87 86 "radius of particles"], 88 87 ["fractal_dim", "", 2.0, [0.0, 6.0], "", -
sasmodels/models/hayter_msa.c
r4962519 r3fc5d27 70 70 SofQ=sqhcal(Qdiam, gMSAWave); 71 71 }else{ 72 //SofQ=NaN; 73 SofQ=-1.0; 72 SofQ=NAN; 74 73 // print "Error Level = ",ierr 75 74 // print "Please report HPMSA problem with above error code" -
sasmodels/models/lamellar_hg_stack_caille.c
ra807206 r1c6286d 3 3 */ 4 4 5 double Iq(double qval, 6 double length_tail, 7 double length_head, 8 double Nlayers, 9 double dd, 10 double Cp, 11 double tail_sld, 12 double head_sld, 13 double solvent_sld); 14 15 double Iq(double qval, 16 double length_tail, 17 double length_head, 18 double Nlayers, 19 double dd, 20 double Cp, 21 double tail_sld, 22 double head_sld, 23 double solvent_sld) 5 static double 6 Iq(double qval, 7 double length_tail, 8 double length_head, 9 double fp_Nlayers, 10 double dd, 11 double Cp, 12 double tail_sld, 13 double head_sld, 14 double solvent_sld) 24 15 { 25 double NN; //local variables of coefficient wave16 int Nlayers = (int)(fp_Nlayers+0.5); //cast to an integer for the loop 26 17 double inten,Pq,Sq,alpha,temp,t2; 27 18 //double dQ, dQDefault, t1, t3; 28 int ii,NNint;29 19 // from wikipedia 0.577215664901532860606512090082402431042159335 30 20 const double Euler = 0.577215664901533; // Euler's constant, increased sig figs for new models Feb 2015 … … 32 22 //dQ = dQDefault; // REMOVED UNUSED dQ calculations for new models Feb 2015 33 23 34 NN = trunc(Nlayers); //be sure that NN is an integer 35 36 Pq = (head_sld-solvent_sld)*(sin(qval*(length_head+length_tail))-sin(qval*length_tail)) + 37 (tail_sld-solvent_sld)*sin(qval*length_tail); 24 Pq = (head_sld-solvent_sld)*(sin(qval*(length_head+length_tail))-sin(qval*length_tail)) 25 + (tail_sld-solvent_sld)*sin(qval*length_tail); 38 26 Pq *= Pq; 39 27 Pq *= 4.0/(qval*qval); 40 28 41 NNint = (int)NN; //cast to an integer for the loop42 ii=0;43 29 Sq = 0.0; 44 for(ii=1;ii<=(NNint-1);ii+=1) { 45 46 //fii = (double)ii; //do I really need to do this? - unused variable, removed 18Feb2015 47 30 for(int ii=1; ii < Nlayers; ii++) { 48 31 temp = 0.0; 49 32 alpha = Cp/4.0/M_PI/M_PI*(log(M_PI*ii) + Euler); … … 52 35 //t3 = dQ*dQ*dd*dd*ii*ii; 53 36 54 temp = 1.0- ii/NN;37 temp = 1.0-(double)ii/(double)Nlayers; 55 38 //temp *= cos(dd*qval*ii/(1.0+t1)); 56 39 temp *= cos(dd*qval*ii); 57 40 //if (temp < 0) printf("q=%g: ii=%d, cos(dd*q*ii)=cos(%g) < 0\n",qval,ii,dd*qval*ii); 58 41 //temp *= exp(-1.0*(t2 + t3)/(2.0*(1.0+t1)) ); 59 temp *= exp(-t2/2.0 42 temp *= exp(-t2/2.0); 60 43 //temp /= sqrt(1.0+t1); 61 44 … … 71 54 72 55 inten *= 1.0e-04; // 1/A to 1/cm 73 return (inten);56 return inten; 74 57 } 75 58 -
sasmodels/models/lamellar_hg_stack_caille.py
r7c57861 ra57b31d 98 98 ["length_head", "Ang", 2, [0, inf], "volume", 99 99 "head thickness"], 100 ["Nlayers", "", 30, [ 0, inf], "",100 ["Nlayers", "", 30, [1, inf], "", 101 101 "Number of layers"], 102 102 ["d_spacing", "Ang", 40., [0.0, inf], "volume", -
sasmodels/models/lamellar_stack_caille.c
r0bef47b r1c6286d 3 3 */ 4 4 5 double Iq(double qval, 6 double del, 7 double Nlayers, 8 double dd, 9 double Cp, 10 double sld, 11 double solvent_sld); 12 13 double Iq(double qval, 14 double del, 15 double Nlayers, 16 double dd, 17 double Cp, 18 double sld, 19 double solvent_sld) 5 static double 6 Iq(double qval, 7 double del, 8 double fp_Nlayers, 9 double dd, 10 double Cp, 11 double sld, 12 double solvent_sld) 20 13 { 21 double contr,NN; //local variables of coefficient wave 14 int Nlayers = (int)(fp_Nlayers+0.5); //cast to an integer for the loop 15 double contr; //local variables of coefficient wave 22 16 double inten,Pq,Sq,alpha,temp,t2; 23 17 //double dQ, dQDefault, t1, t3; 24 int ii,NNint;25 18 // from wikipedia 0.577215664901532860606512090082402431042159335 26 19 const double Euler = 0.577215664901533; // Euler's constant, increased sig figs for new models Feb 2015 … … 28 21 //dQ = dQDefault; // REMOVED UNUSED dQ calculations for new models Feb 2015 29 22 30 NN = trunc(Nlayers); //be sure that NN is an integer31 32 23 contr = sld - solvent_sld; 33 24 34 25 Pq = 2.0*contr*contr/qval/qval*(1.0-cos(qval*del)); 35 26 36 NNint = (int)NN; //cast to an integer for the loop37 ii=0;38 27 Sq = 0.0; 39 // the vital "=" in ii<= added March 2015 40 for(ii=1;ii<=(NNint-1);ii+=1) { 41 42 //fii = (double)ii; //do I really need to do this? - unused variable, removed 18Feb2015 43 28 for (int ii=1; ii < Nlayers; ii++) { 44 29 temp = 0.0; 45 30 alpha = Cp/4.0/M_PI/M_PI*(log(M_PI*ii) + Euler); … … 48 33 //t3 = dQ*dQ*dd*dd*ii*ii; 49 34 50 temp = 1.0 -ii/NN;35 temp = 1.0 - (double)ii / (double)Nlayers; 51 36 //temp *= cos(dd*qval*ii/(1.0+t1)); 52 37 temp *= cos(dd*qval*ii); 53 38 //temp *= exp(-1.0*(t2 + t3)/(2.0*(1.0+t1)) ); 54 temp *= exp(-t2/2.0 39 temp *= exp(-t2/2.0); 55 40 //temp /= sqrt(1.0+t1); 56 41 -
sasmodels/models/lamellar_stack_caille.py
r7c57861 ra57b31d 88 88 parameters = [ 89 89 ["thickness", "Ang", 30.0, [0, inf], "volume", "sheet thickness"], 90 ["Nlayers", "", 20, [ 0, inf], "", "Number of layers"],90 ["Nlayers", "", 20, [1, inf], "", "Number of layers"], 91 91 ["d_spacing", "Ang", 400., [0.0,inf], "volume", "lamellar d-spacing of Caille S(Q)"], 92 92 ["Caille_parameter", "1/Ang^2", 0.1, [0.0,0.8], "", "Caille parameter"], -
sasmodels/models/lamellar_stack_paracrystal.c
r4962519 r5467cd8 2 2 3 3 */ 4 double Iq(double qval, 5 double th, 6 double Nlayers, 7 double davg, 8 double pd, 9 double sld, 10 double solvent_sld); 11 double paraCryst_sn(double ww, double qval, double davg, long Nlayers, double an); 12 double paraCryst_an(double ww, double qval, double davg, long Nlayers); 4 double paraCryst_sn(double ww, double qval, double davg, int Nlayers, double an); 5 double paraCryst_an(double ww, double qval, double davg, int Nlayers); 13 6 14 double Iq(double qval, 15 double th, 16 double Nlayers, 17 double davg, 18 double pd, 19 double sld, 20 double solvent_sld) 7 static double 8 Iq(double qval, 9 double th, 10 double fp_Nlayers, 11 double davg, 12 double pd, 13 double sld, 14 double solvent_sld) 21 15 { 22 23 double inten,contr,xn;24 double xi,ww,Pbil,Znq,Snq,an;25 long n1,n2;16 //get the fractional part of Nlayers, to determine the "mixing" of N's 17 int n1 = (int)(fp_Nlayers); //truncate towards zero 18 int n2 = n1 + 1; 19 const double xn = (double)n2 - fp_Nlayers; //fractional contribution of n1 26 20 27 contr = sld - solvent_sld; 28 //get the fractional part of Nlayers, to determine the "mixing" of N's 29 30 n1 = (long)trunc(Nlayers); //rounds towards zero 31 n2 = n1 + 1; 32 xn = (double)n2 - Nlayers; //fractional contribution of n1 33 34 ww = exp(-qval*qval*pd*pd*davg*davg/2.0); 21 const double ww = exp(-0.5*square(qval*pd*davg)); 35 22 36 23 //calculate the n1 contribution 24 double Znq,Snq,an; 37 25 an = paraCryst_an(ww,qval,davg,n1); 38 26 Snq = paraCryst_sn(ww,qval,davg,n1,an); 39 27 40 28 Znq = xn*Snq; 41 29 … … 52 40 // Zq = (1-ww^2)/(1+ww^2-2*ww*cos(qval*davg)) 53 41 54 xi = th/2.0; //use 1/2 the bilayer thickness55 Pbil = (sin(qval*xi)/(qval*xi))*(sin(qval*xi)/(qval*xi));42 const double xi = th/2.0; //use 1/2 the bilayer thickness 43 const double Pbil = square(sas_sinx_x(qval*xi)); 56 44 57 inten = 2.0*M_PI*contr*contr*Pbil*Znq/(qval*qval);58 inten *= 1.0e-04;45 const double contr = sld - solvent_sld; 46 const double inten = 2.0*M_PI*contr*contr*Pbil*Znq/(qval*qval); 59 47 //printf("q=%.7e wwm1=%g ww=%.5e an=% 12.5e Snq=% 12.5e Znq=% 12.5e Pbil=% 12.5e\n",qval,wwm1,ww,an,Snq,Znq,Pbil); 60 return (inten);48 return 1.0e-4*inten; 61 49 } 62 50 63 51 // functions for the lamellar paracrystal model 64 52 double 65 paraCryst_sn(double ww, double qval, double davg, longNlayers, double an) {53 paraCryst_sn(double ww, double qval, double davg, int Nlayers, double an) { 66 54 67 55 double Snq; … … 69 57 Snq = an/( (double)Nlayers*square(1.0+ww*ww-2.0*ww*cos(qval*davg)) ); 70 58 71 return (Snq);59 return Snq; 72 60 } 73 61 74 62 double 75 paraCryst_an(double ww, double qval, double davg, long Nlayers) { 76 63 paraCryst_an(double ww, double qval, double davg, int Nlayers) { 77 64 double an; 78 65 … … 82 69 an += 2.0*pow(ww,(Nlayers+1))*cos((double)(Nlayers+1)*qval*davg); 83 70 84 return (an);71 return an; 85 72 } 86 73 -
sasmodels/models/lamellar_stack_paracrystal.py
r7c57861 ra0168e8 113 113 parameters = [["thickness", "Ang", 33.0, [0, inf], "volume", 114 114 "sheet thickness"], 115 ["Nlayers", "", 20, [ 0, inf], "",115 ["Nlayers", "", 20, [1, inf], "", 116 116 "Number of layers"], 117 117 ["d_spacing", "Ang", 250., [0.0, inf], "", -
sasmodels/models/linear_pearls.c
r925ad6e rc3ccaec 4 4 double radius, 5 5 double edge_sep, 6 double num_pearls,6 double fp_num_pearls, 7 7 double pearl_sld, 8 8 double solvent_sld); … … 11 11 double radius, 12 12 double edge_sep, 13 doublenum_pearls,13 int num_pearls, 14 14 double pearl_sld, 15 15 double solvent_sld); 16 16 17 17 18 double form_volume(double radius, double num_pearls)18 double form_volume(double radius, double fp_num_pearls) 19 19 { 20 int num_pearls = (int)(fp_num_pearls + 0.5); 20 21 // Pearl volume 21 22 double pearl_vol = M_4PI_3 * cube(radius); … … 27 28 double radius, 28 29 double edge_sep, 29 doublenum_pearls,30 int num_pearls, 30 31 double pearl_sld, 31 32 double solvent_sld) 32 33 { 33 double n_contrib;34 34 //relative sld 35 35 double contrast_pearl = pearl_sld - solvent_sld; … … 46 46 double psi = sas_3j1x_x(q * radius); 47 47 48 // N pearls contribution 49 int n_max = num_pearls - 1; 50 n_contrib = num_pearls; 51 for(int num=1; num<=n_max; num++) { 52 n_contrib += (2.0*(num_pearls-num)*sas_sinx_x(q*separation*num)); 48 // N pearls interaction terms 49 double structure_factor = (double)num_pearls; 50 for(int num=1; num<num_pearls; num++) { 51 structure_factor += 2.0*(num_pearls-num)*sas_sinx_x(q*separation*num); 53 52 } 54 53 // form factor for num_pearls 55 double form_factor = 1.0e-4 * n_contrib* square(m_s*psi) / tot_vol;54 double form_factor = 1.0e-4 * structure_factor * square(m_s*psi) / tot_vol; 56 55 57 56 return form_factor; … … 61 60 double radius, 62 61 double edge_sep, 63 double num_pearls,62 double fp_num_pearls, 64 63 double pearl_sld, 65 64 double solvent_sld) 66 65 { 67 66 67 int num_pearls = (int)(fp_num_pearls + 0.5); 68 68 double result = linear_pearls_kernel(q, 69 69 radius, -
sasmodels/models/linear_pearls.py
r925ad6e rc3ccaec 16 16 .. math:: 17 17 18 P(Q) = \frac{ scale}{V}\left[ m_{p}^219 \left(N+2\sum_{n-1}^{N-1}(N-n)\frac{ sin(qnl)}{qnl}\right)20 \left( 3\frac{ sin(qR)-qRcos(qR)}{(qr)^3}\right)^2\right]18 P(Q) = \frac{\text{scale}}{V}\left[ m_{p}^2 19 \left(N+2\sum_{n-1}^{N-1}(N-n)\frac{\sin(qnl)}{qnl}\right) 20 \left( 3\frac{\sin(qR)-qR\cos(qR)}{(qr)^3}\right)^2\right] 21 21 22 22 where the mass $m_p$ is $(SLD_{pearl}-SLD_{solvent})*(volume\ of\ N\ pearls)$. … … 56 56 ["radius", "Ang", 80.0, [0, inf], "", "Radius of the pearls"], 57 57 ["edge_sep", "Ang", 350.0, [0, inf], "", "Length of the string segment - surface to surface"], 58 ["num_pearls", "", 3.0, [ 0, inf], "", "Number of the pearls"],58 ["num_pearls", "", 3.0, [1, inf], "", "Number of the pearls"], 59 59 ["sld", "1e-6/Ang^2", 1.0, [-inf, inf], "sld", "SLD of the pearl spheres"], 60 60 ["sld_solvent", "1e-6/Ang^2", 6.3, [-inf, inf], "sld", "SLD of the solvent"], -
sasmodels/models/multilayer_vesicle.c
r925ad6e rec1d4bc 1 static 2 double multilayer_vesicle_kernel(double q, 1 static double 2 form_volume(double radius, 3 double thick_shell, 4 double thick_solvent, 5 double fp_n_shells) 6 { 7 int n_shells = (int)(fp_n_shells + 0.5); 8 double R_N = radius + n_shells*(thick_shell+thick_solvent) - thick_solvent; 9 return M_4PI_3*cube(R_N); 10 } 11 12 static double 13 multilayer_vesicle_kernel(double q, 3 14 double volfraction, 4 15 double radius, … … 7 18 double sld_solvent, 8 19 double sld, 9 double n_pairs)20 int n_shells) 10 21 { 11 22 //calculate with a loop, two shells at a time … … 29 40 30 41 //do 2 layers at a time 31 ii += 1;42 ii++; 32 43 33 } while(ii <= n_ pairs-1); //change to make 0 < n_pairs < 2 correspond to44 } while(ii <= n_shells-1); //change to make 0 < n_shells < 2 correspond to 34 45 //unilamellar vesicles (C. Glinka, 11/24/03) 35 46 36 fval *= volfraction*1.0e-4*fval/voli; 37 38 return(fval); 47 return 1.0e-4*volfraction*fval*fval; // Volume normalization happens in caller 39 48 } 40 49 41 static 42 doubleIq(double q,50 static double 51 Iq(double q, 43 52 double volfraction, 44 53 double radius, … … 47 56 double sld_solvent, 48 57 double sld, 49 double n_pairs)58 double fp_n_shells) 50 59 { 60 int n_shells = (int)(fp_n_shells + 0.5); 51 61 return multilayer_vesicle_kernel(q, 52 62 volfraction, … … 56 66 sld_solvent, 57 67 sld, 58 n_ pairs);68 n_shells); 59 69 } 60 70 -
sasmodels/models/multilayer_vesicle.py
r925ad6e r5d23de2 3 3 ---------- 4 4 5 This model is a trivial extension of the core_shell_sphere function to include6 *N* shells where the core is filled with solvent and the shells are interleaved 7 with layers of solvent. For *N = 1*, this returns the same as the vesicle model, 8 except for the normalisation, which here is to outermost volume. 9 The shell thicknessess and SLD are constant for all shells as expected for 10 a multilayer vesicle.5 This model is a trivial extension of the core_shell_sphere function where the 6 core is filled with solvent and is surrounded by $N$ shells of material 7 (such as lipids) interleaved with $N - 1$ layers of solvent. For $N = 1$, this 8 returns the same as the vesicle model, except for the normalisation, which here 9 is to outermost volume. The shell thicknesses and SLD are constant for all 10 shells as expected for a multilayer vesicle. 11 11 12 12 .. figure:: img/multi_shell_geometry.jpg … … 19 19 20 20 .. math:: 21 22 P(q) = \frac{\text{scale.volfraction}}{V_t} F^2(q) + \text{background} 21 P(q) = \text{scale} \cdot \frac{\phi}{V(R_N)} F^2(q) + \text{background} 23 22 24 23 where 25 24 26 25 .. math:: 27 28 F(q) = (\rho_{shell}-\rho_{solv}) \sum_{i=1}^{n\_pairs} \left[ 29 3V(R_i)\frac{\sin(qR_i)-qR_i\cos(qR_i)}{(qR_i)^3} \\ 30 - 3V(R_i+t_s)\frac{\sin(q(R_i+t_s))-q(R_i+t_s)\cos(q(R_i+t_s))}{(q(R_i+t_s))^3} 26 F(q) = (\rho_\text{shell}-\rho_\text{solv}) \sum_{i=1}^{N} \left[ 27 3V(r_i)\frac{\sin(qr_i) - qr_i\cos(qr_i)}{(qr_i)^3} 28 - 3V(R_i)\frac{\sin(qR_i) - qR_i\cos(qR_i)}{(qR_i)^3} 31 29 \right] 32 30 31 for 33 32 34 where $R_i = r_c + (i-1)(t_s + t_w)$ 35 36 where $V_t$ is the volume of the whole particle, $V(R)$ is the volume of a sphere 37 of radius $R$, $r_c$ is the radius of the core, $\rho_{shell}$ is the scattering length 38 density of a shell, $\rho_{solv}$ is the scattering length density of the solvent. 33 .. math:: 39 34 35 r_i &= r_c + (i-1)(t_s + t_w) && \text{ solvent radius before shell } i \\ 36 R_i &= r_i + t_s && \text{ shell radius for shell } i 37 38 $\phi$ is the volume fraction of particles, $V(r)$ is the volume of a sphere 39 of radius $r$, $r_c$ is the radius of the core, $t_s$ is the thickness of 40 the shell, $t_w$ is the thickness of the solvent layer between the shells, 41 $\rho_\text{shell}$ is the scattering length density of a shell, and 42 $\rho_\text{solv}$ is the scattering length density of the solvent. 43 44 USAGE NOTES 45 46 * The outer-most shell radius $R_N$ is used as the effective radius 47 for $P(Q)$ when $P(Q) * S(Q)$ is applied. 48 calculations rather slow. 49 * The number of shells is always rounded to an integer value as a non interger 50 number of layers is not physical. 51 * Thus Polydispersity should only be applied to number of shells **VERY 52 CAREFULLY**. A possible legitimate use would be for mixed systems in which 53 some vesicles have 1 shell, some have 2, etc. A polydispersity on $N$ can be 54 used to model the data by using the "array distriubtion" feature. First 55 create a file such as *shell_dist.txt* containing the relative portion 56 of each vesicle size:: 57 58 1 20 59 2 4 60 3 1 61 62 Turn on polydispersity and select an array distribution for the *n_shells* 63 parameter. Choose the above *shell_dist.txt* file, and the model will be 64 computed with 80% 1-shell vesicles, 16% 2-shell vesicles and 4% 65 3-shell vesicles. 66 * This is a highly non-linear, highly oscillatory (especially around the 67 q-values that correspond to the repeat distance of the layers), model 68 function complicated by the fact that the number of water/shell pairs must 69 physically be an integer value, although the optimization treats it as a 70 floating point value. Thus it may be that the resolution interpolation is not 71 sufficiently fine grained in certain cases. Please report any such occurences 72 to the SasView team. Generally, for the best possible experience: 73 * Start with the best possible guess 74 * Using a priori knowledge, hold as many parameters fixed as possible 75 * if N=1, tw (water thickness) must by definition be zero. Both N and tw should 76 be fixed during fitting. 77 * If N>1, use constraints to keep N > 1 78 * Because N only really moves in integer steps, it may get "stuck" if the 79 optimizer step size is too small so care should be taken 80 If you experience problems with this please contact the SasView team and let 81 them know the issue preferably with example data and model which fail to 82 converge. 40 83 41 84 The 2D scattering intensity is the same as 1D, regardless of the orientation … … 46 89 q = \sqrt{q_x^2 + q_y^2} 47 90 48 49 The outer most radius50 51 $radius + n\_pairs * thick\_shell + (n\_pairs- 1) * thick\_solvent$52 53 is used for both the volume fraction normalization and for the54 effective radius for *S(Q)* when $P(Q) * S(Q)$ is applied.55 56 91 For information about polarised and magnetic scattering, see 57 92 the :ref:`magnetism` documentation. 58 59 This code is based on the form factor calculations implemented in the NIST60 Center for Neutron Research provided c-library (Kline, 2006).61 93 62 94 References 63 95 ---------- 64 96 65 B Cabane, *Small Angle Scattering Methods*, 66 in *Surfactant Solutions: New Methods of Investigation*, 67 Ch.2, Surfactant Science Series Vol. 22, Ed. R Zana and M Dekker, 68 New York, (1987). 97 .. [#] B Cabane, *Small Angle Scattering Methods*, in *Surfactant Solutions: 98 New Methods of Investigation*, Ch.2, Surfactant Science Series Vol. 22, Ed. 99 R Zana and M Dekker, New York, (1987). 69 100 70 **Author:** NIST IGOR/DANSE **on:** pre 2010 101 Authorship and Verification 102 ---------------------------- 71 103 72 **Last Modified by:** Piotr Rozyczko**on:** Feb 24, 2016 73 74 **Last Reviewed by:** Paul Butler **on:** March 20, 2016 104 * **Author:** NIST IGOR/DANSE **Date:** pre 2010 105 * **Converted to sasmodels by:** Piotr Rozyczko **Date:** Feb 24, 2016 106 * **Last Modified by:** Paul Kienzle **Date:** Feb 7, 2017 107 * **Last Reviewed by:** Paul Butler **Date:** March 12, 2017 75 108 76 109 """ … … 89 122 sld_solvent: solvent scattering length density 90 123 sld: shell scattering length density 91 n_ pairs:number of "shell plus solvent" layer pairs124 n_shells:number of "shell plus solvent" layer pairs 92 125 background: incoherent background 93 126 """ … … 98 131 parameters = [ 99 132 ["volfraction", "", 0.05, [0.0, 1], "", "volume fraction of vesicles"], 100 ["radius", "Ang", 60.0, [0.0, inf], " ", "radius of solvent filled core"],101 ["thick_shell", "Ang", 10.0, [0.0, inf], " ", "thickness of one shell"],102 ["thick_solvent", "Ang", 10.0, [0.0, inf], " ", "solvent thickness between shells"],133 ["radius", "Ang", 60.0, [0.0, inf], "volume", "radius of solvent filled core"], 134 ["thick_shell", "Ang", 10.0, [0.0, inf], "volume", "thickness of one shell"], 135 ["thick_solvent", "Ang", 10.0, [0.0, inf], "volume", "solvent thickness between shells"], 103 136 ["sld_solvent", "1e-6/Ang^2", 6.4, [-inf, inf], "sld", "solvent scattering length density"], 104 137 ["sld", "1e-6/Ang^2", 0.4, [-inf, inf], "sld", "Shell scattering length density"], 105 ["n_ pairs", "", 2.0, [1.0, inf], "", "Number of shell plus solvent layer pairs"],138 ["n_shells", "", 2.0, [1.0, inf], "volume", "Number of shell plus solvent layer pairs"], 106 139 ] 107 140 # pylint: enable=bad-whitespace, line-too-long 108 141 142 # TODO: proposed syntax for specifying which parameters can be polydisperse 143 #polydispersity = ["radius", "thick_shell"] 144 109 145 source = ["lib/sas_3j1x_x.c", "multilayer_vesicle.c"] 110 146 111 polydispersity = ["radius", "n_pairs"] 147 def ER(radius, thick_shell, thick_solvent, n_shells): 148 n_shells = int(n_shells+0.5) 149 return radius + n_shells * (thick_shell + thick_solvent) - thick_solvent 112 150 113 151 demo = dict(scale=1, background=0, … … 118 156 sld_solvent=6.4, 119 157 sld=0.4, 120 n_ pairs=2.0)158 n_shells=2.0) 121 159 122 160 tests = [ … … 127 165 'sld_solvent': 6.4, 128 166 'sld': 0.4, 129 'n_ pairs': 2.0,167 'n_shells': 2.0, 130 168 'scale': 1.0, 131 169 'background': 0.001, … … 138 176 'sld_solvent': 6.4, 139 177 'sld': 0.4, 140 'n_ pairs': 2.0,178 'n_shells': 2.0, 141 179 'scale': 1.0, 142 180 'background': 0.001, -
sasmodels/models/onion.c
r925ad6e rc3ccaec 30 30 31 31 static double 32 form_volume(double radius_core, double n , double thickness[])32 form_volume(double radius_core, double n_shells, double thickness[]) 33 33 { 34 int i;34 int n = (int)(n_shells+0.5); 35 35 double r = radius_core; 36 for (i =0; i < n; i++) {36 for (int i=0; i < n; i++) { 37 37 r += thickness[i]; 38 38 } -
sasmodels/models/onion.py
r925ad6e rc3ccaec 323 323 Returns shape profile with x=radius, y=SLD. 324 324 """ 325 325 n_shells = int(n_shells+0.5) 326 326 total_radius = 1.25*(sum(thickness[:n_shells]) + radius_core + 1) 327 327 dz = total_radius/400 # 400 points for a smooth plot … … 366 366 return np.asarray(z), np.asarray(rho) 367 367 368 def ER(radius_core, n , thickness):368 def ER(radius_core, n_shells, thickness): 369 369 """Effective radius""" 370 return np.sum(thickness[:int(n[0])], axis=0) + radius_core 370 n = int(n_shells[0]+0.5) 371 return np.sum(thickness[:n], axis=0) + radius_core 371 372 372 373 demo = { -
sasmodels/models/pearl_necklace.c
r4b541ac r3f853beb 1 1 double form_volume(double radius, double edge_sep, 2 double thick_string, double num_pearls);2 double thick_string, double fp_num_pearls); 3 3 double Iq(double q, double radius, double edge_sep, 4 double thick_string, double num_pearls, double sld,4 double thick_string, double fp_num_pearls, double sld, 5 5 double string_sld, double solvent_sld); 6 6 … … 9 9 // From Igor library 10 10 static double 11 _pearl_necklace_kernel(double q, double radius, double edge_sep, double thick_string,12 doublenum_pearls, double sld_pearl, double sld_string, double sld_solv)11 pearl_necklace_kernel(double q, double radius, double edge_sep, double thick_string, 12 int num_pearls, double sld_pearl, double sld_string, double sld_solv) 13 13 { 14 14 // number of string segments 15 num_pearls = floor(num_pearls + 0.5); //Force integer number of pearls 16 const double num_strings = num_pearls - 1.0; 15 const int num_strings = num_pearls - 1; 17 16 18 17 //each masses: contrast * volume … … 69 68 70 69 double form_volume(double radius, double edge_sep, 71 double thick_string, double num_pearls)70 double thick_string, double fp_num_pearls) 72 71 { 73 num_pearls = floor(num_pearls + 0.5); //Force integer number of pearls 74 75 const double num_strings = num_pearls - 1.0; 72 const int num_pearls = (int)(fp_num_pearls + 0.5); //Force integer number of pearls 73 const int num_strings = num_pearls - 1; 76 74 const double string_vol = edge_sep * M_PI_4 * thick_string * thick_string; 77 75 const double pearl_vol = M_4PI_3 * radius * radius * radius; … … 82 80 83 81 double Iq(double q, double radius, double edge_sep, 84 double thick_string, double num_pearls, double sld,82 double thick_string, double fp_num_pearls, double sld, 85 83 double string_sld, double solvent_sld) 86 84 { 87 const double form = _pearl_necklace_kernel(q, radius, edge_sep, 85 const int num_pearls = (int)(fp_num_pearls + 0.5); //Force integer number of pearls 86 const double form = pearl_necklace_kernel(q, radius, edge_sep, 88 87 thick_string, num_pearls, sld, string_sld, solvent_sld); 89 88 -
sasmodels/models/pearl_necklace.py
r4b541ac r1bd1ea2 82 82 ["thick_string", "Ang", 2.5, [0, inf], "volume", 83 83 "Thickness of the chain linkage"], 84 ["num_pearls", "none", 3, [ 0, inf], "volume",84 ["num_pearls", "none", 3, [1, inf], "volume", 85 85 "Number of pearls in the necklace (must be integer)"], 86 86 ["sld", "1e-6/Ang^2", 1.0, [-inf, inf], "sld", … … 100 100 Redundant with form_volume. 101 101 """ 102 num_pearls = int(num_pearls + 0.5) 102 103 number_of_strings = num_pearls - 1.0 103 104 string_vol = edge_sep * pi * pow((thick_string / 2.0), 2.0) … … 111 112 Calculation for effective radius. 112 113 """ 114 num_pearls = int(num_pearls + 0.5) 113 115 tot_vol = volume(radius, edge_sep, thick_string, num_pearls) 114 116 rad_out = (tot_vol/(4.0/3.0*pi)) ** (1./3.) -
sasmodels/models/raspberry.py
r8e68ea0 rc3ccaec 10 10 Schematic of the raspberry model 11 11 12 In order to calculate the form factor of the entire complex, the self-13 correlation of the large droplet, the self-correlation of the particles, the 14 correlation terms between different particles and the cross terms between large 15 droplet and small particles all need to be calculated.12 In order to calculate the form factor of the entire complex, the 13 self-correlation of the large droplet, the self-correlation of the particles, 14 the correlation terms between different particles and the cross terms between 15 large droplet and small particles all need to be calculated. 16 16 17 Consider two infinitely thin shells of radii R1 and R2 separated by distance r.18 The general structure of the equation is then the form factor of the two shells 19 multiplied by the phase factor that accounts for the separation of their 20 centers.17 Consider two infinitely thin shells of radii $R_1$ and $R_2$ separated by 18 distance $r$. The general structure of the equation is then the form factor 19 of the two shells multiplied by the phase factor that accounts for the 20 separation of their centers. 21 21 22 22 .. math:: -
sasmodels/models/rpa.c
r6351bfa reb63414 1 double Iq(double q, double case_num,1 double Iq(double q, double fp_case_num, 2 2 double N[], double Phi[], double v[], double L[], double b[], 3 3 double Kab, double Kac, double Kad, … … 5 5 ); 6 6 7 double Iq(double q, double case_num,7 double Iq(double q, double fp_case_num, 8 8 double N[], // DEGREE OF POLYMERIZATION 9 9 double Phi[], // VOL FRACTION … … 15 15 ) 16 16 { 17 int icase = (int) case_num;17 int icase = (int)(fp_case_num+0.5); 18 18 19 19 double Nab,Nac,Nad,Nbc,Nbd,Ncd; … … 39 39 double S31,S32,S33,S34,S41,S42,S43,S44; 40 40 double Lad,Lbd,Lcd,Nav,Intg; 41 41 42 // Set values for non existent parameters (eg. no A or B in case 0 and 1 etc) 42 43 //icase was shifted to N-1 from the original code 43 44 if (icase <= 1){ … … 57 58 Kab = Kac = Kad = -0.0004; 58 59 } 59 60 61 // Set volume fraction of component D based on constraint that sum of vol frac =1 62 Phi[3]=1.0-Phi[0]-Phi[1]-Phi[2]; 63 64 //set up values for cross terms in case of block copolymers (1,3,4,6,7,8,9) 60 65 Nab=sqrt(N[0]*N[1]); 61 66 Nac=sqrt(N[0]*N[2]); … … 79 84 Phicd=sqrt(Phi[2]*Phi[3]); 80 85 86 // Calculate Q^2 * Rg^2 for each homopolymer assuming random walk 81 87 Xa=q*q*b[0]*b[0]*N[0]/6.0; 82 88 Xb=q*q*b[1]*b[1]*N[1]/6.0; … … 84 90 Xd=q*q*b[3]*b[3]*N[3]/6.0; 85 91 86 Paa=2.0*(exp(-Xa)-1.0+Xa)/(Xa*Xa); 87 S0aa=N[0]*Phi[0]*v[0]*Paa; 88 Pab=((1.0-exp(-Xa))/Xa)*((1.0-exp(-Xb))/Xb); 92 //calculate all partial structure factors Pij and normalize n^2 93 Paa=2.0*(exp(-Xa)-1.0+Xa)/(Xa*Xa); // free A chain form factor 94 S0aa=N[0]*Phi[0]*v[0]*Paa; // Phi * Vp * P(Q)= I(Q0)/delRho^2 95 Pab=((1.0-exp(-Xa))/Xa)*((1.0-exp(-Xb))/Xb); //AB diblock (anchored Paa * anchored Pbb) partial form factor 89 96 S0ab=(Phiab*vab*Nab)*Pab; 90 Pac=((1.0-exp(-Xa))/Xa)*exp(-Xb)*((1.0-exp(-Xc))/Xc); 97 Pac=((1.0-exp(-Xa))/Xa)*exp(-Xb)*((1.0-exp(-Xc))/Xc); //ABC triblock AC partial form factor 91 98 S0ac=(Phiac*vac*Nac)*Pac; 92 Pad=((1.0-exp(-Xa))/Xa)*exp(-Xb-Xc)*((1.0-exp(-Xd))/Xd); 99 Pad=((1.0-exp(-Xa))/Xa)*exp(-Xb-Xc)*((1.0-exp(-Xd))/Xd); //ABCD four block 93 100 S0ad=(Phiad*vad*Nad)*Pad; 94 101 95 102 S0ba=S0ab; 96 Pbb=2.0*(exp(-Xb)-1.0+Xb)/(Xb*Xb); 103 Pbb=2.0*(exp(-Xb)-1.0+Xb)/(Xb*Xb); // free B chain 97 104 S0bb=N[1]*Phi[1]*v[1]*Pbb; 98 Pbc=((1.0-exp(-Xb))/Xb)*((1.0-exp(-Xc))/Xc); 105 Pbc=((1.0-exp(-Xb))/Xb)*((1.0-exp(-Xc))/Xc); // BC diblock 99 106 S0bc=(Phibc*vbc*Nbc)*Pbc; 100 Pbd=((1.0-exp(-Xb))/Xb)*exp(-Xc)*((1.0-exp(-Xd))/Xd); 107 Pbd=((1.0-exp(-Xb))/Xb)*exp(-Xc)*((1.0-exp(-Xd))/Xd); // BCD triblock 101 108 S0bd=(Phibd*vbd*Nbd)*Pbd; 102 109 103 110 S0ca=S0ac; 104 111 S0cb=S0bc; 105 Pcc=2.0*(exp(-Xc)-1.0+Xc)/(Xc*Xc); 112 Pcc=2.0*(exp(-Xc)-1.0+Xc)/(Xc*Xc); // Free C chain 106 113 S0cc=N[2]*Phi[2]*v[2]*Pcc; 107 Pcd=((1.0-exp(-Xc))/Xc)*((1.0-exp(-Xd))/Xd); 114 Pcd=((1.0-exp(-Xc))/Xc)*((1.0-exp(-Xd))/Xd); // CD diblock 108 115 S0cd=(Phicd*vcd*Ncd)*Pcd; 109 116 … … 111 118 S0db=S0bd; 112 119 S0dc=S0cd; 113 Pdd=2.0*(exp(-Xd)-1.0+Xd)/(Xd*Xd); 120 Pdd=2.0*(exp(-Xd)-1.0+Xd)/(Xd*Xd); // free D chain 114 121 S0dd=N[3]*Phi[3]*v[3]*Pdd; 122 123 // Reset all unused partial structure factors to 0 (depends on case) 115 124 //icase was shifted to N-1 from the original code 116 125 switch(icase){ … … 193 202 S0dc=S0cd; 194 203 204 // self chi parameter is 0 ... of course 195 205 Kaa=0.0; 196 206 Kbb=0.0; … … 243 253 ZZ=S0ad*(T11*S0ad+T12*S0bd+T13*S0cd)+S0bd*(T21*S0ad+T22*S0bd+T23*S0cd)+S0cd*(T31*S0ad+T32*S0bd+T33*S0cd); 244 254 255 // D is considered the matrix or background component so enters here 245 256 m=1.0/(S0dd-ZZ); 246 257 … … 297 308 S44=S11+S22+S33+2.0*S12+2.0*S13+2.0*S23; 298 309 310 //calculate contrast where L[i] is the scattering length of i and D is the matrix 311 //Note that should multiply by Nav to get units of SLD which will become 312 // Nav*2 in the next line (SLD^2) but then normalization in that line would 313 //need to divide by Nav leaving only Nav or sqrt(Nav) before squaring. 299 314 Nav=6.022045e+23; 300 315 Lad=(L[0]/v[0]-L[3]/v[3])*sqrt(Nav); … … 303 318 304 319 Intg=Lad*Lad*S11+Lbd*Lbd*S22+Lcd*Lcd*S33+2.0*Lad*Lbd*S12+2.0*Lbd*Lcd*S23+2.0*Lad*Lcd*S13; 320 321 //rescale for units of Lij^2 (fm^2 to cm^2) 322 Intg *= 1.0e-26; 305 323 306 324 return Intg; -
sasmodels/models/rpa.py
r40a87fa r4f9e288 1 1 r""" 2 Definition 3 ---------- 4 2 5 Calculates the macroscopic scattering intensity for a multi-component 3 6 homogeneous mixture of polymers using the Random Phase Approximation. … … 24 27 Case 9: A-B-C-D tetra-block copolymer 25 28 26 **NB: these case numbers are different from those in the NIST SANS package!** 29 .. note:: 30 These case numbers are different from those in the NIST SANS package! 27 31 28 Only one case can be used at any one time. 32 The models are based on the papers by Akcasu et al. [#Akcasu]_ and by 33 Hammouda [#Hammouda]_ assuming the polymer follows Gaussian statistics such 34 that $R_g^2 = n b^2/6$ where $b$ is the statistical segment length and $n$ is 35 the number of statistical segment lengths. A nice tutorial on how these are 36 constructed and implemented can be found in chapters 28 and 39 of Boualem 37 Hammouda's 'SANS Toolbox'[#toolbox]_. 29 38 30 The RPA (mean field) formalism only applies only when the multicomponent 31 polymer mixture is in the homogeneous mixed-phase region. 39 In brief the macroscopic cross sections are derived from the general forms 40 for homopolymer scattering and the multiblock cross-terms while the inter 41 polymer cross terms are described in the usual way by the $\chi$ parameter. 32 42 33 **Component D is assumed to be the "background" component (ie, all contrasts 34 are calculated with respect to component D).** So the scattering contrast 35 for a C/D blend = [SLD(component C) - SLD(component D)]\ :sup:`2`. 43 USAGE NOTES: 36 44 37 Depending on which case is being used, the number of fitting parameters - the 38 segment lengths (ba, bb, etc) and $\chi$ parameters (Kab, Kac, etc) - vary. 39 The *scale* parameter should be held equal to unity. 45 * Only one case can be used at any one time. 46 * The RPA (mean field) formalism only applies only when the multicomponent 47 polymer mixture is in the homogeneous mixed-phase region. 48 * **Component D is assumed to be the "background" component (ie, all contrasts 49 are calculated with respect to component D).** So the scattering contrast 50 for a C/D blend = [SLD(component C) - SLD(component D)]\ :sup:`2`. 51 * Depending on which case is being used, the number of fitting parameters can 52 vary. 40 53 41 The input parameters are the degrees of polymerization, the volume fractions, 42 the specific volumes, and the neutron scattering length densities for each 43 component. 54 .. Note:: 55 * In general the degrees of polymerization, the volume 56 fractions, the molar volumes, and the neutron scattering lengths for each 57 component are obtained from other methods and held fixed while The *scale* 58 parameter should be held equal to unity. 59 * The variables are normally the segment lengths (b\ :sub:`a`, b\ :sub:`b`, 60 etc) and $\chi$ parameters (K\ :sub:`ab`, K\ :sub:`ac`, etc). 44 61 45 62 … … 47 64 ---------- 48 65 49 A Z Akcasu, R Klein and B Hammouda, *Macromolecules*, 26 (1993) 4136 66 .. [#Akcasu] A Z Akcasu, R Klein and B Hammouda, *Macromolecules*, 26 (1993) 67 4136. 68 .. [#Hammouda] B. Hammouda, *Advances in Polymer Science* 106 (1993) 87. 69 .. [#toolbox] https://www.ncnr.nist.gov/staff/hammouda/the_sans_toolbox.pdf 70 71 Authorship and Verification 72 ---------------------------- 73 74 * **Author:** Boualem Hammouda - NIST IGOR/DANSE **Date:** pre 2010 75 * **Converted to sasmodels by:** Paul Kienzle **Date:** July 18, 2016 76 * **Last Modified by:** Paul Butler **Date:** March 12, 2017 77 * **Last Reviewed by:** Paul Butler **Date:** March 12, 2017 50 78 """ 51 79 … … 53 81 54 82 name = "rpa" 55 title = "Random Phase Approximation - unfinished work in progress"83 title = "Random Phase Approximation" 56 84 description = """ 57 85 This formalism applies to multicomponent polymer mixtures in the … … 90 118 ["N[4]", "", 1000.0, [1, inf], "", "Degree of polymerization"], 91 119 ["Phi[4]", "", 0.25, [0, 1], "", "volume fraction"], 92 ["v[4]", "mL/mol", 100.0, [0, inf], "", " specificvolume"],120 ["v[4]", "mL/mol", 100.0, [0, inf], "", "molar volume"], 93 121 ["L[4]", "fm", 10.0, [-inf, inf], "", "scattering length"], 94 122 ["b[4]", "Ang", 5.0, [0, inf], "", "segment length"], … … 107 135 108 136 control = "case_num" 109 HIDE_ NONE = set()110 HIDE_A = set("N1 Phi1 v1 L1 b1 K12 K13 K14".split()) 137 HIDE_ALL = set("Phi4".split()) 138 HIDE_A = set("N1 Phi1 v1 L1 b1 K12 K13 K14".split()).union(HIDE_ALL) 111 139 HIDE_AB = set("N2 Phi2 v2 L2 b2 K23 K24".split()).union(HIDE_A) 112 140 def hidden(case_num): … … 114 142 Return a list of parameters to hide depending on the multiplicity parameter. 115 143 """ 144 case_num = int(case_num+0.5) 116 145 if case_num < 2: 117 146 return HIDE_AB … … 119 148 return HIDE_A 120 149 else: 121 return HIDE_ NONE150 return HIDE_ALL 122 151 -
sasmodels/models/spherical_sld.c
r925ad6e rc3ccaec 1 1 static double form_volume( 2 intn_shells,2 double fp_n_shells, 3 3 double thickness[], 4 4 double interface[]) 5 5 { 6 int n_shells= (int)(fp_n_shells + 0.5); 6 7 double r = 0.0; 7 8 for (int i=0; i < n_shells; i++) { … … 20 21 return pow(z, nu); 21 22 } else if (shape==2) { 22 return 1.0 - pow(1. - z, nu);23 return 1.0 - pow(1.0 - z, nu); 23 24 } else if (shape==3) { 24 25 return expm1(-nu*z)/expm1(-nu); … … 44 45 static double Iq( 45 46 double q, 46 intn_shells,47 double fp_n_shells, 47 48 double sld_solvent, 48 49 double sld[], … … 51 52 double shape[], 52 53 double nu[], 53 intn_steps)54 double fp_n_steps) 54 55 { 55 56 // iteration for # of shells + core + solvent 57 int n_shells = (int)(fp_n_shells + 0.5); 58 int n_steps = (int)(fp_n_steps + 0.5); 56 59 double f=0.0; 57 60 double r=0.0; -
sasmodels/models/spherical_sld.py
r925ad6e rc3ccaec 233 233 """ 234 234 235 n_shells = int(n_shells + 0.5) 236 n_steps = int(n_steps + 0.5) 235 237 z = [] 236 238 rho = [] … … 240 242 rho.append(sld[0]) 241 243 242 for i in range(0, int(n_shells)):244 for i in range(0, n_shells): 243 245 z_next += thickness[i] 244 246 z.append(z_next) … … 261 263 def ER(n_shells, thickness, interface): 262 264 """Effective radius""" 263 n_shells = int(n_shells )265 n_shells = int(n_shells + 0.5) 264 266 total = (np.sum(thickness[:n_shells], axis=1) 265 267 + np.sum(interface[:n_shells], axis=1)) -
sasmodels/models/stacked_disks.c
r6c3e266 r19f996b 1 double form_volume(double thick_core, 2 double thick_layer, 3 double radius, 4 double n_stacking); 5 6 double Iq(double q, 7 double thick_core, 8 double thick_layer, 9 double radius, 10 double n_stacking, 11 double sigma_dnn, 12 double core_sld, 13 double layer_sld, 14 double solvent_sld); 15 16 double Iqxy(double qx, double qy, 17 double thick_core, 18 double thick_layer, 19 double radius, 20 double n_stacking, 21 double sigma_dnn, 22 double core_sld, 23 double layer_sld, 24 double solvent_sld, 25 double theta, 26 double phi); 27 28 static 29 double _kernel(double q, 30 double radius, 31 double core_sld, 32 double layer_sld, 33 double solvent_sld, 34 double halfheight, 35 double thick_layer, 36 double sin_alpha, 37 double cos_alpha, 38 double sigma_dnn, 39 double d, 40 double n_stacking) 1 static double stacked_disks_kernel( 2 double q, 3 double halfheight, 4 double thick_layer, 5 double radius, 6 int n_stacking, 7 double sigma_dnn, 8 double core_sld, 9 double layer_sld, 10 double solvent_sld, 11 double sin_alpha, 12 double cos_alpha, 13 double d) 41 14 42 15 { … … 88 61 89 62 90 static 91 double stacked_disks_kernel(double q,92 93 94 95 doublen_stacking,96 97 98 99 63 static double stacked_disks_1d( 64 double q, 65 double thick_core, 66 double thick_layer, 67 double radius, 68 int n_stacking, 69 double sigma_dnn, 70 double core_sld, 71 double layer_sld, 72 double solvent_sld) 100 73 { 101 74 /* StackedDiscsX : calculates the form factor of a stacked "tactoid" of core shell disks … … 111 84 double sin_alpha, cos_alpha; // slots to hold sincos function output 112 85 SINCOS(zi, sin_alpha, cos_alpha); 113 double yyy = _kernel(q, 86 double yyy = stacked_disks_kernel(q, 87 halfheight, 88 thick_layer, 114 89 radius, 90 n_stacking, 91 sigma_dnn, 115 92 core_sld, 116 93 layer_sld, 117 94 solvent_sld, 118 halfheight,119 thick_layer,120 95 sin_alpha, 121 96 cos_alpha, 122 sigma_dnn, 123 d, 124 n_stacking); 97 d); 125 98 summ += Gauss76Wt[i] * yyy * sin_alpha; 126 99 } … … 132 105 } 133 106 134 double form_volume(double thick_core, 135 double thick_layer, 136 double radius, 137 double n_stacking){ 107 static double form_volume( 108 double thick_core, 109 double thick_layer, 110 double radius, 111 double fp_n_stacking) 112 { 113 int n_stacking = (int)(fp_n_stacking + 0.5); 138 114 double d = 2.0 * thick_layer + thick_core; 139 115 return M_PI * radius * radius * d * n_stacking; 140 116 } 141 117 142 double Iq(double q, 143 double thick_core, 144 double thick_layer, 145 double radius, 146 double n_stacking, 147 double sigma_dnn, 148 double core_sld, 149 double layer_sld, 150 double solvent_sld) 118 static double Iq( 119 double q, 120 double thick_core, 121 double thick_layer, 122 double radius, 123 double fp_n_stacking, 124 double sigma_dnn, 125 double core_sld, 126 double layer_sld, 127 double solvent_sld) 151 128 { 152 return stacked_disks_kernel(q, 129 int n_stacking = (int)(fp_n_stacking + 0.5); 130 return stacked_disks_1d(q, 153 131 thick_core, 154 132 thick_layer, … … 162 140 163 141 164 double 165 Iqxy(double qx, double qy, 166 double thick_core, 167 double thick_layer, 168 double radius, 169 double n_stacking, 170 double sigma_dnn, 171 double core_sld, 172 double layer_sld, 173 double solvent_sld, 174 double theta, 175 double phi) 142 static double Iqxy(double qx, double qy, 143 double thick_core, 144 double thick_layer, 145 double radius, 146 double fp_n_stacking, 147 double sigma_dnn, 148 double core_sld, 149 double layer_sld, 150 double solvent_sld, 151 double theta, 152 double phi) 176 153 { 154 int n_stacking = (int)(fp_n_stacking + 0.5); 177 155 double q, sin_alpha, cos_alpha; 178 156 ORIENT_SYMMETRIC(qx, qy, theta, phi, q, sin_alpha, cos_alpha); … … 180 158 double d = 2.0 * thick_layer + thick_core; 181 159 double halfheight = 0.5*thick_core; 182 double answer = _kernel(q, 160 double answer = stacked_disks_kernel(q, 161 halfheight, 162 thick_layer, 183 163 radius, 164 n_stacking, 165 sigma_dnn, 184 166 core_sld, 185 167 layer_sld, 186 168 solvent_sld, 187 halfheight,188 thick_layer,189 169 sin_alpha, 190 170 cos_alpha, 191 sigma_dnn, 192 d, 193 n_stacking); 171 d); 194 172 195 173 //convert to [cm-1] -
sasmodels/models/stacked_disks.py
rb7e8b94 rc3ccaec 126 126 ["thick_layer", "Ang", 10.0, [0, inf], "volume", "Thickness of layer each side of core"], 127 127 ["radius", "Ang", 15.0, [0, inf], "volume", "Radius of the stacked disk"], 128 ["n_stacking", "", 1.0, [ 0, inf], "volume", "Number of stacked layer/core/layer disks"],128 ["n_stacking", "", 1.0, [1, inf], "volume", "Number of stacked layer/core/layer disks"], 129 129 ["sigma_d", "Ang", 0, [0, inf], "", "Sigma of nearest neighbor spacing"], 130 130 ["sld_core", "1e-6/Ang^2", 4, [-inf, inf], "sld", "Core scattering length density"], -
sasmodels/models/star_polymer.c
r3a48772 r2586093f 3 3 double Iq(double q, double radius2, double arms); 4 4 5 static double _mass_fractal_kernel(double q, double radius2, double arms)5 static double star_polymer_kernel(double q, double radius2, double arms) 6 6 { 7 7 … … 23 23 double Iq(double q, double radius2, double arms) 24 24 { 25 return _mass_fractal_kernel(q, radius2, arms);25 return star_polymer_kernel(q, radius2, arms); 26 26 } -
sasmodels/models/unified_power_Rg.py
r66ca2a6 rc3ccaec 97 97 98 98 def Iq(q, level, rg, power, B, G): 99 ilevel = int(level)100 if ilevel == 0:99 level = int(level + 0.5) 100 if level == 0: 101 101 with errstate(divide='ignore'): 102 102 return 1./q … … 104 104 with errstate(divide='ignore', invalid='ignore'): 105 105 result = np.zeros(q.shape, 'd') 106 for i in range( ilevel):106 for i in range(level): 107 107 exp_now = exp(-(q*rg[i])**2/3.) 108 108 pow_now = (erf(q*rg[i]/sqrt(6.))**3/q)**power[i] 109 if i < ilevel-1:109 if i < level-1: 110 110 exp_next = exp(-(q*rg[i+1])**2/3.) 111 111 else: … … 113 113 result += G[i]*exp_now + B[i]*exp_next*pow_now 114 114 115 result[q == 0] = np.sum(G[: ilevel])115 result[q == 0] = np.sum(G[:level]) 116 116 return result 117 117 -
sasmodels/product.py
r9951a86 rf88e248 45 45 # structure factor calculator. Structure factors should not 46 46 # have any magnetic parameters 47 assert(s_info.parameters.kernel_parameters[0].id == ER_ID) 48 assert(s_info.parameters.kernel_parameters[1].id == VF_ID) 49 assert(s_info.parameters.magnetism_index == []) 47 if not s_info.parameters.kernel_parameters[0].id == ER_ID: 48 raise TypeError("S needs %s as first parameter"%ER_ID) 49 if not s_info.parameters.kernel_parameters[1].id == VF_ID: 50 raise TypeError("S needs %s as second parameter"%VF_ID) 51 if not s_info.parameters.magnetism_index == []: 52 raise TypeError("S should not have SLD parameters") 50 53 p_id, p_name, p_pars = p_info.id, p_info.name, p_info.parameters 51 54 s_id, s_name, s_pars = s_info.id, s_info.name, s_info.parameters 52 p_set = set(p.id for p in p_pars.call_parameters) 53 s_set = set(p.id for p in s_pars.call_parameters) 54 55 if p_set & s_set: 56 # there is some overlap between the parameter names; tag the 57 # overlapping S parameters with name_S. 58 # Skip the first parameter of s, which is effective radius 59 s_list = [(suffix_parameter(par) if par.id in p_set else par) 60 for par in s_pars.kernel_parameters[1:]] 61 else: 62 # Skip the first parameter of s, which is effective radius 63 s_list = s_pars.kernel_parameters[1:] 55 56 # Create list of parameters for the combined model. Skip the first 57 # parameter of S, which we verified above is effective radius. If there 58 # are any names in P that overlap with those in S, modify the name in S 59 # to distinguish it. 60 p_set = set(p.id for p in p_pars.kernel_parameters) 61 s_list = [(_tag_parameter(par) if par.id in p_set else par) 62 for par in s_pars.kernel_parameters[1:]] 63 # Check if still a collision after renaming. This could happen if for 64 # example S has volfrac and P has both volfrac and volfrac_S. 65 if any(p.id in p_set for p in s_list): 66 raise TypeError("name collision: P has P.name and P.name_S while S has S.name") 67 64 68 translate_name = dict((old.id, new.id) for old, new 65 69 in zip(s_pars.kernel_parameters[1:], s_list)) 66 70 demo = {} 67 demo.update((k, v) for k, v in p_info.demo.items() 68 if k not in ("background", "scale")) 71 demo.update(p_info.demo.items()) 69 72 demo.update((translate_name[k], v) for k, v in s_info.demo.items() 70 73 if k not in ("background", "scale") and not k.startswith(ER_ID)) … … 90 93 # Remember the component info blocks so we can build the model 91 94 model_info.composition = ('product', [p_info, s_info]) 92 model_info.demo = {} 95 model_info.demo = demo 96 97 ## Show the parameter table with the demo values 98 #from .compare import get_pars, parlist 99 #print("==== %s ====="%model_info.name) 100 #values = get_pars(model_info, use_demo=True) 101 #print(parlist(model_info, values, is2d=True)) 93 102 return model_info 94 103 95 def suffix_parameter(par, suffix): 104 def _tag_parameter(par): 105 """ 106 Tag the parameter name with _S to indicate that the parameter comes from 107 the structure factor parameter set. This is only necessary if the 108 form factor model includes a parameter of the same name as a parameter 109 in the structure factor. 110 """ 96 111 par = copy(par) 97 par.name = par.name + " S" 112 # Protect against a vector parameter in S by appending the vector length 113 # to the renamed parameter. Note: haven't tested this since no existing 114 # structure factor models contain vector parameters. 115 vector_length = par.name[len(par.id):] 98 116 par.id = par.id + "_S" 117 par.name = par.id + vector_length 99 118 return par 100 119 -
sasmodels/resolution.py
rb397165 rb32caab 17 17 18 18 MINIMUM_RESOLUTION = 1e-8 19 20 21 # When extrapolating to -q, what is the minimum positive q relative to q_min 22 # that we wish to calculate? 23 MIN_Q_SCALE_FOR_NEGATIVE_Q_EXTRAPOLATION = 0.01 19 MINIMUM_ABSOLUTE_Q = 0.02 # relative to the minimum q in the data 24 20 25 21 class Resolution(object): … … 82 78 self.q_calc = (pinhole_extend_q(q, q_width, nsigma=nsigma) 83 79 if q_calc is None else np.sort(q_calc)) 80 81 # Protect against models which are not defined for very low q. Limit 82 # the smallest q value evaluated (in absolute) to 0.02*min 83 cutoff = MINIMUM_ABSOLUTE_Q*np.min(self.q) 84 self.q_calc = self.q_calc[abs(self.q_calc) >= cutoff] 85 86 # Build weight matrix from calculated q values 84 87 self.weight_matrix = pinhole_resolution(self.q_calc, self.q, 85 88 np.maximum(q_width, MINIMUM_RESOLUTION)) 89 self.q_calc = abs(self.q_calc) 86 90 87 91 def apply(self, theory): … … 123 127 self.q_calc = slit_extend_q(q, qx_width, qy_width) \ 124 128 if q_calc is None else np.sort(q_calc) 129 130 # Protect against models which are not defined for very low q. Limit 131 # the smallest q value evaluated (in absolute) to 0.02*min 132 cutoff = MINIMUM_ABSOLUTE_Q*np.min(self.q) 133 self.q_calc = self.q_calc[abs(self.q_calc) >= cutoff] 134 135 # Build weight matrix from calculated q values 125 136 self.weight_matrix = \ 126 137 slit_resolution(self.q_calc, self.q, qx_width, qy_width) 138 self.q_calc = abs(self.q_calc) 127 139 128 140 def apply(self, theory): … … 153 165 # neither trapezoid nor Simpson's rule improved the accuracy. 154 166 edges = bin_edges(q_calc) 155 edges[edges < 0.0] = 0.0 # clip edges below zero167 #edges[edges < 0.0] = 0.0 # clip edges below zero 156 168 cdf = erf((edges[:, None] - q[None, :]) / (sqrt(2.0)*q_width)[None, :]) 157 169 weights = cdf[1:] - cdf[:-1] … … 286 298 # The current algorithm is a midpoint rectangle rule. 287 299 q_edges = bin_edges(q_calc) # Note: requires q > 0 288 q_edges[q_edges < 0.0] = 0.0 # clip edges below zero300 #q_edges[q_edges < 0.0] = 0.0 # clip edges below zero 289 301 weights = np.zeros((len(q), len(q_calc)), 'd') 290 302 … … 392 404 interval. 393 405 394 if *q_min* is zero or less then *q[0]/10* is used instead.406 Note that extrapolated values may be negative. 395 407 """ 396 408 q = np.sort(q) 397 409 if q_min + 2*MINIMUM_RESOLUTION < q[0]: 398 if q_min <= 0: q_min = q_min*MIN_Q_SCALE_FOR_NEGATIVE_Q_EXTRAPOLATION399 410 n_low = np.ceil((q[0]-q_min) / (q[1]-q[0])) if q[1] > q[0] else 15 400 411 q_low = np.linspace(q_min, q[0], n_low+1)[:-1] … … 448 459 log_delta_q = log(10.) / points_per_decade 449 460 if q_min < q[0]: 450 if q_min < 0: q_min = q[0]*MIN _Q_SCALE_FOR_NEGATIVE_Q_EXTRAPOLATION461 if q_min < 0: q_min = q[0]*MINIMUM_ABSOLUTE_Q 451 462 n_low = log_delta_q * (log(q[0])-log(q_min)) 452 463 q_low = np.logspace(log10(q_min), log10(q[0]), np.ceil(n_low)+1)[:-1] -
sasmodels/sasview_model.py
rfe8ff99 r749a7d4 16 16 import logging 17 17 from os.path import basename, splitext 18 import thread 18 19 19 20 import numpy as np # type: ignore … … 38 39 except ImportError: 39 40 pass 41 42 calculation_lock = thread.allocate_lock() 40 43 41 44 SUPPORT_OLD_STYLE_PLUGINS = True … … 605 608 to the card for each evaluation. 606 609 """ 610 ## uncomment the following when trying to debug the uncoordinated calls 611 ## to calculate_Iq 612 #if calculation_lock.locked(): 613 # logging.info("calculation waiting for another thread to complete") 614 # logging.info("\n".join(traceback.format_stack())) 615 616 with calculation_lock: 617 return self._calculate_Iq(qx, qy) 618 619 def _calculate_Iq(self, qx, qy=None): 607 620 #core.HAVE_OPENCL = False 608 621 if self._model is None: … … 721 734 return [self.params[par.name]], [1.0] 722 735 723 def test_ model():736 def test_cylinder(): 724 737 # type: () -> float 725 738 """ 726 Test that a sasview model (cylinder) can be run.739 Test that the cylinder model runs, returning the value at [0.1,0.1]. 727 740 """ 728 741 Cylinder = _make_standard_model('cylinder') … … 733 746 # type: () -> float 734 747 """ 735 Test that a sasview model (cylinder) can be run.748 Test that 2-D hardsphere model runs and doesn't produce NaN. 736 749 """ 737 750 Model = _make_standard_model('hardsphere') … … 744 757 # type: () -> float 745 758 """ 746 Test that a sasview model (cylinder) can be run.759 Test that the 2-D RPA model runs 747 760 """ 748 761 RPA = _make_standard_model('rpa') … … 750 763 return rpa.evalDistribution([0.1, 0.1]) 751 764 765 def test_empty_distribution(): 766 # type: () -> None 767 """ 768 Make sure that sasmodels returns NaN when there are no polydispersity points 769 """ 770 Cylinder = _make_standard_model('cylinder') 771 cylinder = Cylinder() 772 cylinder.setParam('radius', -1.0) 773 cylinder.setParam('background', 0.) 774 Iq = cylinder.evalDistribution(np.asarray([0.1])) 775 assert np.isnan(Iq[0]), "empty distribution fails" 752 776 753 777 def test_model_list(): 754 778 # type: () -> None 755 779 """ 756 Make sure that all models build as sasview models .780 Make sure that all models build as sasview models 757 781 """ 758 782 from .exception import annotate_exception … … 781 805 782 806 if __name__ == "__main__": 783 print("cylinder(0.1,0.1)=%g"%test_model()) 807 print("cylinder(0.1,0.1)=%g"%test_cylinder()) 808 #test_empty_distribution() -
sasmodels/sesans.py
rb397165 r94d13f1 14 14 import numpy as np # type: ignore 15 15 from numpy import pi, exp # type: ignore 16 from scipy.special import jv as besselj 17 #import direct_model.DataMixin as model 18 19 def make_q(q_max, Rmax): 20 r""" 21 Return a $q$ vector suitable for SESANS covering from $2\pi/ (10 R_{\max})$ 22 to $q_max$. This is the integration range of the Hankel transform; bigger range and 23 more points makes a better numerical integration. 24 Smaller q_min will increase reliable spin echo length range. 25 Rmax is the "radius" of the largest expected object and can be set elsewhere. 26 q_max is determined by the acceptance angle of the SESANS instrument. 16 from scipy.special import j0 17 18 class SesansTransform(object): 27 19 """ 28 from sas.sascalc.data_util.nxsunit import Converter 20 Spin-Echo SANS transform calculator. Similar to a resolution function, 21 the SesansTransform object takes I(q) for the set of *q_calc* values and 22 produces a transformed dataset 29 23 30 q_min = dq = 0.1 * 2*pi / Rmax31 return np.arange(q_min, 32 Converter(q_max[1])(q_max[0],33 units="1/A"),34 dq) 35 36 def make_all_q(data): 24 *SElength* (A) is the set of spin-echo lengths in the measured data. 25 26 *zaccept* (1/A) is the maximum acceptance of scattering vector in the spin 27 echo encoding dimension (for ToF: Q of min(R) and max(lam)). 28 29 *Rmax* (A) is the maximum size sensitivity; larger radius requires more 30 computation time. 37 31 """ 38 Return a $q$ vector suitable for calculating the total scattering cross section for 39 calculating the effect of finite acceptance angles on Time of Flight SESANS instruments. 40 If no acceptance is given, or unwanted (set "unwanted" flag in paramfile), no all_q vector is needed. 41 If the instrument has a rectangular acceptance, 2 all_q vectors are needed. 42 If the instrument has a circular acceptance, 1 all_q vector is needed 43 44 """ 45 if not data.has_no_finite_acceptance: 46 return [] 47 elif data.has_yz_acceptance(data): 48 # compute qx, qy 49 Qx, Qy = np.meshgrid(qx, qy) 50 return [Qx, Qy] 51 else: 52 # else only need q 53 # data.has_z_acceptance 54 return [q] 32 #: SElength from the data in the original data units; not used by transform 33 #: but the GUI uses it, so make sure that it is present. 34 q = None # type: np.ndarray 55 35 56 def transform(data, q_calc, Iq_calc, qmono, Iq_mono): 57 """ 58 Decides which transform type is to be used, based on the experiment data file contents (header) 59 (2016-03-19: currently controlled from parameters script) 60 nqmono is the number of q vectors to be used for the detector integration 61 """ 62 nqmono = len(qmono) 63 if nqmono == 0: 64 result = call_hankel(data, q_calc, Iq_calc) 65 elif nqmono == 1: 66 q = qmono[0] 67 result = call_HankelAccept(data, q_calc, Iq_calc, q, Iq_mono) 68 else: 69 Qx, Qy = [qmono[0], qmono[1]] 70 Qx = np.reshape(Qx, nqx, nqy) 71 Qy = np.reshape(Qy, nqx, nqy) 72 Iq_mono = np.reshape(Iq_mono, nqx, nqy) 73 qx = Qx[0, :] 74 qy = Qy[:, 0] 75 result = call_Cosine2D(data, q_calc, Iq_calc, qx, qy, Iq_mono) 36 #: q values to calculate when computing transform 37 q_calc = None # type: np.ndarray 76 38 77 return result 39 # transform arrays 40 _H = None # type: np.ndarray 41 _H0 = None # type: np.ndarray 78 42 79 def call_hankel(data, q_calc, Iq_calc): 80 return hankel((data.x, data.x_unit), 81 (data.lam, data.lam_unit), 82 (data.sample.thickness, 83 data.sample.thickness_unit), 84 q_calc, Iq_calc) 85 86 def call_HankelAccept(data, q_calc, Iq_calc, q_mono, Iq_mono): 87 return hankel(data.x, data.lam * 1e-9, 88 data.sample.thickness / 10, 89 q_calc, Iq_calc) 90 91 def call_Cosine2D(data, q_calc, Iq_calc, qx, qy, Iq_mono): 92 return hankel(data.x, data.y, data.lam * 1e-9, 93 data.sample.thickness / 10, 94 q_calc, Iq_calc) 95 96 def TotalScatter(model, parameters): #Work in progress!! 97 # Calls a model with existing model parameters already in place, then integrate the product of q and I(q) from 0 to (4*pi/lambda) 98 allq = np.linspace(0,4*pi/wavelength,1000) 99 allIq = 1 100 integral = allq*allIq 101 43 def __init__(self, z, SElength, zaccept, Rmax): 44 # type: (np.ndarray, float, float) -> None 45 #import logging; logging.info("creating SESANS transform") 46 self.q = z 47 self._set_hankel(SElength, zaccept, Rmax) 102 48 49 def apply(self, Iq): 50 # tye: (np.ndarray) -> np.ndarray 51 G0 = np.dot(self._H0, Iq) 52 G = np.dot(self._H.T, Iq) 53 P = G - G0 54 return P 103 55 104 def Cosine2D(wavelength, magfield, thickness, qy, qz, Iqy, Iqz, modelname): #Work in progress!! Needs to call model still 105 #============================================================================== 106 # 2D Cosine Transform if "wavelength" is a vector 107 #============================================================================== 108 #allq is the q-space needed to create the total scattering cross-section 56 def _set_hankel(self, SElength, zaccept, Rmax): 57 # type: (np.ndarray, float, float) -> None 58 # Force float32 arrays, otherwise run into memory problems on some machines 59 SElength = np.asarray(SElength, dtype='float32') 109 60 110 Gprime = np.zeros_like(wavelength, 'd') 111 s = np.zeros_like(wavelength, 'd') 112 sd = np.zeros_like(wavelength, 'd') 113 Gprime = np.zeros_like(wavelength, 'd') 114 f = np.zeros_like(wavelength, 'd') 115 for i, wavelength_i in enumerate(wavelength): 116 z = magfield*wavelength_i 117 allq=np.linspace() #for calculating the Q-range of the scattering power integral 118 allIq=np.linspace() # This is the model applied to the allq q-space. Needs to refference the model somehow 119 alldq = (allq[1]-allq[0])*1e10 120 sigma[i]=wavelength[i]^2*thickness/2/pi*np.sum(allIq*allq*alldq) 121 s[i]=1-exp(-sigma) 122 for j, Iqy_j, qy_j in enumerate(qy): 123 for k, Iqz_k, qz_k in enumerate(qz): 124 Iq = np.sqrt(Iqy_j^2+Iqz_k^2) 125 q = np.sqrt(qy_j^2 + qz_k^2) 126 Gintegral = Iq*cos(z*Qz_k) 127 Gprime[i] += Gintegral 128 # sigma = wavelength^2*thickness/2/pi* allq[i]*allIq[i] 129 # s[i] += 1-exp(Totalscatter(modelname)*thickness) 130 # For now, work with standard 2-phase scatter 61 #Rmax = #value in text box somewhere in FitPage? 62 q_max = 2*pi / (SElength[1] - SElength[0]) 63 q_min = 0.1 * 2*pi / (np.size(SElength) * SElength[-1]) 64 q = np.arange(q_min, q_max, q_min, dtype='float32') 65 dq = q_min 131 66 67 H0 = np.float32(dq/(2*pi)) * q 132 68 133 sd[i] += Iq134 f[i] = 1-s[i]+sd[i]135 P[i] = (1-sd[i]/f[i])+1/f[i]*Gprime[i]69 repq = np.tile(q, (SElength.size, 1)).T 70 repSE = np.tile(SElength, (q.size, 1)) 71 H = np.float32(dq/(2*pi)) * j0(repSE*repq) * repq 136 72 137 138 139 140 def HankelAccept(wavelength, magfield, thickness, q, Iq, theta, modelname): 141 #============================================================================== 142 # HankelTransform with fixed circular acceptance angle (circular aperture) for Time of Flight SESANS 143 #============================================================================== 144 #acceptq is the q-space needed to create limited acceptance effect 145 SElength= wavelength*magfield 146 G = np.zeros_like(SElength, 'd') 147 threshold=2*pi*theta/wavelength 148 for i, SElength_i in enumerate(SElength): 149 allq=np.linspace() #for calculating the Q-range of the scattering power integral 150 allIq=np.linspace() # This is the model applied to the allq q-space. Needs to refference the model somehow 151 alldq = (allq[1]-allq[0])*1e10 152 sigma[i]=wavelength[i]^2*thickness/2/pi*np.sum(allIq*allq*alldq) 153 s[i]=1-exp(-sigma) 154 155 dq = (q[1]-q[0])*1e10 156 a = (x<threshold) 157 acceptq = a*q 158 acceptIq = a*Iq 159 160 G[i] = np.sum(besselj(0, acceptq*SElength_i)*acceptIq*acceptq*dq) 161 162 # G[i]=np.sum(integral) 163 164 G *= dq*1e10*2*pi 165 166 P = exp(thickness*wavelength**2/(4*pi**2)*(G-G[0])) 167 168 def hankel(SElength, wavelength, thickness, q, Iq): 169 r""" 170 Compute the expected SESANS polarization for a given SANS pattern. 171 172 Uses the hankel transform followed by the exponential. The values for *zz* 173 (or spin echo length, or delta), wavelength and sample thickness should 174 come from the dataset. $q$ should be chosen such that the oscillations 175 in $I(q)$ are well sampled (e.g., $5 \cdot 2 \pi/d_{\max}$). 176 177 *SElength* [A] is the set of $z$ points at which to compute the 178 Hankel transform 179 180 *wavelength* [m] is the wavelength of each individual point *zz* 181 182 *thickness* [cm] is the sample thickness. 183 184 *q* [A$^{-1}$] is the set of $q$ points at which the model has been 185 computed. These should be equally spaced. 186 187 *I* [cm$^{-1}$] is the value of the SANS model at *q* 188 """ 189 190 from sas.sascalc.data_util.nxsunit import Converter 191 wavelength = Converter(wavelength[1])(wavelength[0],"A") 192 thickness = Converter(thickness[1])(thickness[0],"A") 193 Iq = Converter("1/cm")(Iq,"1/A") # All models default to inverse centimeters 194 SElength = Converter(SElength[1])(SElength[0],"A") 195 196 G = np.zeros_like(SElength, 'd') 197 #============================================================================== 198 # Hankel Transform method if "wavelength" is a scalar; mono-chromatic SESANS 199 #============================================================================== 200 for i, SElength_i in enumerate(SElength): 201 integral = besselj(0, q*SElength_i)*Iq*q 202 G[i] = np.sum(integral) 203 G0 = np.sum(Iq*q) 204 205 # [m^-1] step size in q, needed for integration 206 dq = (q[1]-q[0]) 207 208 # integration step, convert q into [m**-1] and 2 pi circle integration 209 G *= dq*2*pi 210 G0 = np.sum(Iq*q)*dq*2*np.pi 211 212 P = exp(thickness*wavelength**2/(4*pi**2)*(G-G0)) 213 214 return P 73 self.q_calc = q 74 self._H, self._H0 = H, H0
Note: See TracChangeset
for help on using the changeset viewer.