Changeset 0c2da4b in sasmodels
- Timestamp:
- Mar 5, 2017 10:03:48 PM (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:
- f88e248
- Parents:
- d3e3f756 (diff), acfb094 (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. - Files:
-
- 1 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/conversion_table.py
rd3e3f756 r0c2da4b 5 5 names for each parameter in sasmodels. This is used by :mod:`convert` to 6 6 determine the equivalent parameter set when comparing a sasmodels model to 7 the models defined in SasView 3.1. 7 the models defined in previous versions of SasView and sasmodels. This is now 8 versioned based on the version number of SasView. 9 10 When any sasmodels parameter or model name is changed, this must be modified to 11 account for that. 12 13 Usage: 14 <old_Sasview_version> : { 15 <new_model_name> : [ 16 <old_model_name> , 17 { 18 <new_param_name_1> : <old_param_name_1>, 19 ... 20 <new_param_name_n> : <old_param_name_n> 21 } 22 ] 23 } 24 25 Any future parameter and model name changes can and should be given in this 26 table for future compatibility. 8 27 """ 9 28 10 11 29 CONVERSION_TABLE = { 30 (3,1,2) : { 12 31 "adsorbed_layer": [ 13 32 "Core2ndMomentModel", … … 211 230 ], 212 231 "correlation_length": [ 213 "CorrLength Model",232 "CorrLength", 214 233 { 215 234 "porod_scale": "scale_p", … … 218 237 "lorentz_exp": "exponent_l", 219 238 "cor_length": "length_l" 220 } 239 }, 240 "CorrLengthModel" 221 241 ], 222 242 "cylinder": [ … … 299 319 ], 300 320 "fractal_core_shell": [ 301 "FractalCoreShell Model",321 "FractalCoreShell", 302 322 { 303 323 "sld_core": "core_sld", … … 309 329 "cor_length": "cor_length", 310 330 "volfraction": "volfraction", 311 } 331 }, 332 "FractalCoreShellModel" 312 333 ], 313 334 "fuzzy_sphere": [ … … 321 342 ], 322 343 "gauss_lorentz_gel": [ 323 "GaussLorentzGel Model",344 "GaussLorentzGel", 324 345 { 325 346 "gauss_scale": "scale_g", … … 328 349 "background": "background", 329 350 "lorentz_scale": "scale_l" 330 } 351 }, 352 "GaussLorentzGelModel" 331 353 ], 332 354 "gaussian_peak": [ 333 "Peak GaussModel",355 "Peak Gauss Model", 334 356 { 335 357 "peak_pos": "q0", 336 358 "sigma": "B", 337 } 359 }, 360 "PeakGaussModel", 338 361 ], 339 362 "gel_fit": [ … … 343 366 "lorentz_scale": "lScale", 344 367 "guinier_scale": "gScale", 345 "fractal_dim": " scale",368 "fractal_dim": "FractalExp", 346 369 "cor_length": "zeta", 347 370 } 348 371 ], 349 372 "guinier": [ 373 "Guinier", 374 { 375 "rg": "rg" 376 }, 350 377 "GuinierModel", 351 {352 "rg": "rg"353 }354 378 ], 355 379 "guinier_porod": [ 356 "GuinierPorod Model",380 "GuinierPorod", 357 381 { 358 382 "s": "dim", … … 361 385 "scale": "scale", 362 386 "background": "background" 363 } 387 }, 388 "GuinierPorodModel", 364 389 ], 365 390 "hardsphere": [ … … 454 479 "d_spacing": "spacing", 455 480 "Caille_parameter": "caille", 456 "Nlayers": " N_plates",481 "Nlayers": "n_plates", 457 482 } 458 483 ], … … 486 511 ], 487 512 "lorentz": [ 513 "Lorentz", 514 { 515 "cor_length": "length" 516 }, 488 517 "LorentzModel", 489 {490 "cor_length": "length"491 }492 518 ], 493 519 "mass_fractal": [ … … 510 536 ], 511 537 "mono_gauss_coil": [ 512 "Debye Model",538 "Debye", 513 539 { 514 540 "rg": "rg", 515 541 "i_zero": "scale", 516 542 "background": "background", 517 } 543 }, 544 "DebyeModel", 518 545 ], 519 546 "multilayer_vesicle": [ … … 564 591 ], 565 592 "peak_lorentz": [ 566 "Peak LorentzModel",593 "Peak Lorentz Model", 567 594 { 568 595 "peak_pos": "q0", 569 596 "peak_hwhm": "B" 570 } 597 }, 598 "PeakLorentzModel", 571 599 ], 572 600 "pearl_necklace": [ … … 802 830 ], 803 831 "two_lorentzian": [ 804 "TwoLorentzian Model",832 "TwoLorentzian", 805 833 { 806 834 "lorentz_scale_1": "scale_1", … … 811 839 "lorentz_length_1": "length_1", 812 840 "background": "background" 813 } 841 }, 842 "TwoLorentzianModel", 814 843 ], 815 844 "two_power_law": [ 816 "TwoPowerLaw Model",845 "TwoPowerLaw", 817 846 { 818 847 "coefficent_1": "coef_A", … … 821 850 "background": "background", 822 851 "crossover": "qc" 823 } 852 }, 853 "TwoPowerLawModel", 824 854 ], 825 855 "unified_power_Rg": [ 856 "UnifiedPowerRg", 857 dict(((field_new+str(index), field_old+str(index)) 858 for field_new, field_old in [("rg", "Rg"), 859 ("power", "power"), 860 ("G", "G"), 861 ("B", "B"),] 862 for index in range(11)), 863 **{ 864 "background": "background", 865 "scale": "scale", 866 }), 826 867 "UnifiedPowerRgModel", 827 {828 }829 868 ], 830 869 "vesicle": [ … … 835 874 } 836 875 ] 876 } 837 877 } -
sasmodels/convert.py
rf80f334 r07c8d46 53 53 ("_pd_nsigma", ".nsigmas"), 54 54 ("_pd_type", ".type"), 55 (".lower", ".lower"), 56 (".upper", ".upper"), 57 (".fittable", ".fittable"), 58 (".std", ".std"), 59 (".units", ".units"), 60 ("", "") 55 61 ] 56 62 … … 64 70 if id.startswith('M0:'): 65 71 return True 66 if id.startswith('volfraction') or id.startswith('radius_effective'):67 return False68 72 if '_pd' in id or '.' in id: 69 73 return False … … 75 79 if p.id == id: 76 80 return p.type == 'sld' 77 r aise ValueError("unknown parameter %r in conversion"%id)81 return False 78 82 79 83 def _rescale_sld(model_info, pars, scale): … … 88 92 89 93 90 def _get_translation_table(model_info ):91 _, translation = CONVERSION_TABLE.get(model_info.id, [None, {}])92 translation = translation.copy()94 def _get_translation_table(model_info, version=(3,1,2)): 95 conv_param = CONVERSION_TABLE.get(version, {}).get(model_info.id, [None, {}]) 96 translation = conv_param[1].copy() 93 97 for p in model_info.parameters.kernel_parameters: 94 98 if p.length > 1: … … 119 123 def _pd_to_underscores(pars): 120 124 return dict((_dot_pd_to_underscore_pd(k), v) for k, v in pars.items()) 121 122 def _convert_name(conv_dict, pars):123 """124 Renames parameter values (upper, lower, etc) to v4.0 names125 :param conv_dict: conversion dictionary mapping new name : old name126 :param pars: parameters to convert127 :return:128 """129 new_pars = {}130 i = 0131 j = 0132 for key_par, value_par in pars.iteritems():133 j += 1134 for key_conv, value_conv in conv_dict.iteritems():135 if re.search(value_conv, key_par):136 new_pars[key_par.replace(value_conv, key_conv)] = value_par137 i += 1138 break139 elif re.search("background", key_par) or re.search("scale", key_par):140 new_pars[key_par] = value_par141 i += 1142 break143 if i != j:144 new_pars[key_par] = value_par145 i += 1146 return new_pars147 125 148 126 def _convert_pars(pars, mapping): … … 167 145 return newpars 168 146 169 170 def _conversion_target(model_name): 147 def _conversion_target(model_name, version=(3,1,2)): 171 148 """ 172 149 Find the sasmodel name which translates into the sasview name. … … 176 153 two variants in sasview. 177 154 """ 178 for sasmodels_name, [sasview_name, _] in CONVERSION_TABLE.items(): 179 if sasview_name == model_name: 155 for sasmodels_name, sasview_dict in \ 156 CONVERSION_TABLE.get(version, {}).items(): 157 if sasview_dict[0] == model_name: 180 158 return sasmodels_name 181 159 return None 182 160 183 184 def _hand_convert(name, oldpars): 161 def _hand_convert(name, oldpars, version=(3,1,2)): 162 if version == (3,1,2): 163 oldpars = _hand_convert_3_1_2_to_4_1(name, oldpars) 164 return oldpars 165 166 def _hand_convert_3_1_2_to_4_1(name, oldpars): 185 167 if name == 'core_shell_parallelepiped': 186 168 # Make sure pd on rim parameters defaults to zero … … 215 197 pd = oldpars['radius.width']*oldpars['radius']/thickness 216 198 oldpars['radius.width'] = pd 199 elif name == 'multilayer_vesicle': 200 if 'scale' in oldpars: 201 oldpars['volfraction'] = oldpars['scale'] 202 oldpars['scale'] = 1.0 203 if 'scale.lower' in oldpars: 204 oldpars['volfraction.lower'] = oldpars['scale.lower'] 205 if 'scale.upper' in oldpars: 206 oldpars['volfraction.upper'] = oldpars['scale.upper'] 207 if 'scale.fittable' in oldpars: 208 oldpars['volfraction.fittable'] = oldpars['scale.fittable'] 209 if 'scale.std' in oldpars: 210 oldpars['volfraction.std'] = oldpars['scale.std'] 211 if 'scale.units' in oldpars: 212 oldpars['volfraction.units'] = oldpars['scale.units'] 217 213 elif name == 'pearl_necklace': 218 214 pass … … 236 232 oldpars[p + ".upper"] /= 1e-13 237 233 elif name == 'spherical_sld': 238 oldpars["CONTROL"] += 1 234 j = 0 235 while "func_inter" + str(j) in oldpars: 236 name = "func_inter" + str(j) 237 new_name = "shape" + str(j + 1) 238 if oldpars[name] == 'Erf(|nu|*z)': 239 oldpars[new_name] = int(0) 240 elif oldpars[name] == 'RPower(z^|nu|)': 241 oldpars[new_name] = int(1) 242 elif oldpars[name] == 'LPower(z^|nu|)': 243 oldpars[new_name] = int(2) 244 elif oldpars[name] == 'RExp(-|nu|*z)': 245 oldpars[new_name] = int(3) 246 elif oldpars[name] == 'LExp(-|nu|*z)': 247 oldpars[new_name] = int(4) 248 else: 249 oldpars[new_name] = int(0) 250 oldpars.pop(name) 251 oldpars['n_shells'] = str(j + 1) 252 j += 1 239 253 elif name == 'teubner_strey': 240 254 # basically undoing the entire Teubner-Strey calculations here. … … 281 295 return oldpars 282 296 283 def convert_model(name, pars, use_underscore=False ):297 def convert_model(name, pars, use_underscore=False, model_version=(3,1,2)): 284 298 """ 285 299 Convert model from old style parameter names to new style. 286 300 """ 287 newname = _conversion_target(name) 288 if newname is None: 289 return name, pars 290 if ':' in newname: # core_shell_ellipsoid:1 291 model_info = load_model_info(newname[:-2]) 292 # Know that the table exists and isn't multiplicity so grab it directly 293 # Can't use _get_translation_table since that will return the 'bare' 294 # version. 295 translation = CONVERSION_TABLE[newname][1] 296 else: 297 model_info = load_model_info(newname) 298 translation = _get_translation_table(model_info) 299 newpars = _hand_convert(newname, pars.copy()) 300 newpars = _convert_name(translation, newpars) 301 newpars = _convert_pars(newpars, translation) 302 if not model_info.structure_factor: 303 newpars = _rescale_sld(model_info, newpars, 1e6) 304 newpars.setdefault('scale', 1.0) 305 newpars.setdefault('background', 0.0) 306 if use_underscore: 307 newpars = _pd_to_underscores(newpars) 301 newpars = pars 302 keys = sorted(CONVERSION_TABLE.keys()) 303 for i, version in enumerate(keys): 304 # Don't allow indices outside list 305 next_i = i + 1 306 if next_i == len(keys): 307 next_i = i 308 # If the save state is from a later version, skip the check 309 if model_version <= keys[next_i]: 310 newname = _conversion_target(name, version) 311 else: 312 newname = None 313 # If no conversion is found, move on 314 if newname is None: 315 newname = name 316 continue 317 if ':' in newname: # core_shell_ellipsoid:1 318 model_info = load_model_info(newname[:-2]) 319 # Know the table exists and isn't multiplicity so grab it directly 320 # Can't use _get_translation_table since that will return the 'bare' 321 # version. 322 translation = CONVERSION_TABLE.get(version, {})[newname][1] 323 else: 324 model_info = load_model_info(newname) 325 translation = _get_translation_table(model_info, version) 326 newpars = _hand_convert(newname, newpars, version) 327 newpars = _convert_pars(newpars, translation) 328 # TODO: Still not convinced this is the best check 329 if not model_info.structure_factor and version == (3,1,2): 330 newpars = _rescale_sld(model_info, newpars, 1e6) 331 newpars.setdefault('scale', 1.0) 332 newpars.setdefault('background', 0.0) 333 if use_underscore: 334 newpars = _pd_to_underscores(newpars) 335 name = newname 308 336 return newname, newpars 309 310 337 311 338 # ========= BACKWARD CONVERSION sasmodels => sasview 3.x =========== -
sasmodels/kernelcl.py
r7fcdc9f rd2b939c 465 465 # architectures tested so far. 466 466 if self.is_2d: 467 # Note: 17 rather than 15 because results is 2 elements 468 # longer than input. 469 width = ((self.nq+17)//16)*16 467 # Note: 16 rather than 15 because result is 1 longer than input. 468 width = ((self.nq+16)//16)*16 470 469 self.q = np.empty((width, 2), dtype=dtype) 471 470 self.q[:self.nq, 0] = q_vectors[0] 472 471 self.q[:self.nq, 1] = q_vectors[1] 473 472 else: 474 # Note: 33 rather than 31 because results is 2 elements 475 # longer than input. 476 width = ((self.nq+33)//32)*32 473 # Note: 32 rather than 31 because result is 1 longer than input. 474 width = ((self.nq+32)//32)*32 477 475 self.q = np.empty(width, dtype=dtype) 478 476 self.q[:self.nq] = q_vectors[0] … … 524 522 self.dim = '2d' if q_input.is_2d else '1d' 525 523 # plus three for the normalization values 526 self.result = np.empty(q_input.nq+ 3, dtype)524 self.result = np.empty(q_input.nq+1, dtype) 527 525 528 526 # Inputs and outputs for each kernel call -
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/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/rpa.c
r6351bfa racfb094 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 //need to verify why the sqrt of Nav rather than just Nav (assuming v is molar volume) 299 312 Nav=6.022045e+23; 300 313 Lad=(L[0]/v[0]-L[3]/v[3])*sqrt(Nav); … … 303 316 304 317 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; 318 319 //rescale for units of Lij^2 (in 10e-12 m^2 to m^2 ?) 320 Intg *= 1.0e-24; 305 321 306 322 return Intg; -
sasmodels/models/rpa.py
r40a87fa rbb73096 107 107 108 108 control = "case_num" 109 HIDE_ NONE = set()110 HIDE_A = set("N1 Phi1 v1 L1 b1 K12 K13 K14".split()) 109 HIDE_ALL = set("Phi4".split()) 110 HIDE_A = set("N1 Phi1 v1 L1 b1 K12 K13 K14".split()).union(HIDE_ALL) 111 111 HIDE_AB = set("N2 Phi2 v2 L2 b2 K23 K24".split()).union(HIDE_A) 112 112 def hidden(case_num): … … 119 119 return HIDE_A 120 120 else: 121 return HIDE_ NONE121 return HIDE_ALL 122 122 -
sasmodels/sasview_model.py
r64614ad 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 … … 39 40 pass 40 41 42 calculation_lock = thread.allocate_lock() 43 41 44 SUPPORT_OLD_STYLE_PLUGINS = True 42 45 … … 57 60 import sas.models 58 61 from sasmodels.conversion_table import CONVERSION_TABLE 59 for new_name, conversion in CONVERSION_TABLE. items():62 for new_name, conversion in CONVERSION_TABLE.get((3,1,2), {}).items(): 60 63 # CoreShellEllipsoidModel => core_shell_ellipsoid:1 61 64 new_name = new_name.split(':')[0] 62 old_name = conversion[0] 65 old_name = conversion[0] if len(conversion) < 3 else conversion[2] 63 66 module_attrs = {old_name: find_model(new_name)} 64 67 ConstructedModule = type(old_name, (), module_attrs) … … 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 -
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 rec1d4bc 20 20 .. math:: 21 21 22 P(q) = \ frac{\text{scale.volfraction}}{V_t} F^2(q) + \text{background}22 P(q) = \text{scale}\frac{\phi}{V(R_N)} F^2(q) + \text{background} 23 23 24 24 where … … 26 26 .. math:: 27 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}28 F(q) = (\rho_\text{shell}-\rho_\text{solv}) \sum_{i=1}^{N} \left[ 29 3V(r_i)\frac{\sin(qr_i) - qr_i\cos(qr_i)}{(qr_i)^3} 30 - 3V(R_i)\frac{\sin(qR_i) - qR_i\cos(qR_i)}{(qR_i)^3} 31 31 \right] 32 32 33 for 33 34 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. 35 .. math:: 39 36 37 r_i &= r_c + (i-1)(t_s + t_w) && \text{ solvent radius before shell } i \\ 38 R_i &= r_i + t_s && \text{ shell radius for shell } i 39 40 $\phi$ is the volume fraction of particles, $V(r)$ is the volume of a sphere 41 of radius $r$, $r_c$ is the radius of the core, $t_s$ is the thickness of 42 the shell, $t_w$ is the thickness of the solvent layer between the shells, 43 $\rho_\text{shell}$ is the scattering length density of a shell, and 44 $\rho_\text{solv}$ is the scattering length density of the solvent. 40 45 41 46 The 2D scattering intensity is the same as 1D, regardless of the orientation … … 46 51 q = \sqrt{q_x^2 + q_y^2} 47 52 48 49 The outer most radius 50 51 $radius + n\_pairs * thick\_shell + (n\_pairs- 1) * thick\_solvent$ 52 53 is used for both the volume fraction normalization and for the 54 effective radius for *S(Q)* when $P(Q) * S(Q)$ is applied. 53 The outer-most shell radius $R_N$ is used as the effective radius 54 for $P(Q)$ when $P(Q) * S(Q)$ is applied. 55 55 56 56 For information about polarised and magnetic scattering, see … … 89 89 sld_solvent: solvent scattering length density 90 90 sld: shell scattering length density 91 n_ pairs:number of "shell plus solvent" layer pairs91 n_shells:number of "shell plus solvent" layer pairs 92 92 background: incoherent background 93 93 """ … … 98 98 parameters = [ 99 99 ["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"],100 ["radius", "Ang", 60.0, [0.0, inf], "volume", "radius of solvent filled core"], 101 ["thick_shell", "Ang", 10.0, [0.0, inf], "volume", "thickness of one shell"], 102 ["thick_solvent", "Ang", 10.0, [0.0, inf], "volume", "solvent thickness between shells"], 103 103 ["sld_solvent", "1e-6/Ang^2", 6.4, [-inf, inf], "sld", "solvent scattering length density"], 104 104 ["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"],105 ["n_shells", "", 2.0, [1.0, inf], "volume", "Number of shell plus solvent layer pairs"], 106 106 ] 107 107 # pylint: enable=bad-whitespace, line-too-long … … 109 109 source = ["lib/sas_3j1x_x.c", "multilayer_vesicle.c"] 110 110 111 polydispersity = ["radius", "n_pairs"] 111 def ER(radius, thick_shell, thick_solvent, n_shells): 112 n_shells = int(n_shells+0.5) 113 return radius + n_shells * (thick_shell + thick_solvent) - thick_solvent 112 114 113 115 demo = dict(scale=1, background=0, … … 118 120 sld_solvent=6.4, 119 121 sld=0.4, 120 n_ pairs=2.0)122 n_shells=2.0) 121 123 122 124 tests = [ … … 127 129 'sld_solvent': 6.4, 128 130 'sld': 0.4, 129 'n_ pairs': 2.0,131 'n_shells': 2.0, 130 132 'scale': 1.0, 131 133 'background': 0.001, … … 138 140 'sld_solvent': 6.4, 139 141 'sld': 0.4, 140 'n_ pairs': 2.0,142 'n_shells': 2.0, 141 143 'scale': 1.0, 142 144 'background': 0.001,
Note: See TracChangeset
for help on using the changeset viewer.