Changeset 6e7ba14 in sasmodels
- Timestamp:
- Aug 20, 2018 8:52:21 AM (6 years ago)
- Branches:
- master, core_shell_microgels, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- aa44a6a
- Parents:
- bad3093
- Location:
- sasmodels
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/generate.py
rc036ddb r6e7ba14 805 805 refs = _call_pars("_v.", partable.form_volume_parameters) 806 806 call_volume = "#define CALL_VOLUME(_v) form_volume(%s)"%(",".join(refs)) 807 call_effective_radius = "#define CALL_EFFECTIVE_RADIUS(mode, _v) effective_radius(mode, %s)"%(",".join(refs)) 807 808 else: 808 809 # Model doesn't have volume. We could make the kernel run a little … … 810 811 # the ifdef's reduce readability more than is worthwhile. 811 812 call_volume = "#define CALL_VOLUME(v) 1.0" 813 call_effective_radius = "#define CALL_EFFECTIVE_RADIUS(mode, v) 0.0" 812 814 source.append(call_volume) 815 source.append(call_effective_radius) 813 816 model_refs = _call_pars("_v.", partable.iq_parameters) 814 817 -
sasmodels/kernel.py
r2d81cfe r6e7ba14 41 41 dtype = None # type: np.dtype 42 42 43 def __call__(self, call_details, values, cutoff, magnetic):43 def Iq(self, call_details, values, cutoff, magnetic): 44 44 # type: (CallDetails, np.ndarray, np.ndarray, float, bool) -> np.ndarray 45 raise NotImplementedError("need to implement __call__") 45 Pq, Reff = self.Pq_Reff(call_details, values, cutoff, magnetic, effective_radius_type=0) 46 scale = values[0] 47 background = values[1] 48 return scale*Pq + background 49 __call__ = Iq 50 51 def Pq_Reff(self, call_details, values, cutoff, magnetic, effective_radius_type): 52 # type: (CallDetails, np.ndarray, np.ndarray, float, bool, int) -> np.ndarray 53 self._call_kernel(call_details, values, cutoff, magnetic, effective_radius_type) 54 #print("returned",self.q_input.q, self.result) 55 nout = 2 if self.info.have_Fq else 1 56 total_weight = self.result[nout*self.q_input.nq + 0] 57 if total_weight == 0.: 58 total_weight = 1. 59 weighted_volume = self.result[nout*self.q_input.nq + 1] 60 weighted_radius = self.result[nout*self.q_input.nq + 2] 61 effective_radius = weighted_radius/total_weight 62 # compute I = scale*P + background 63 # = scale*(sum(w*F^2)/sum w)/(sum (w*V)/sum w) + background 64 # = scale/sum (w*V) * sum(w*F^2) + background 65 scale = values[0]/(weighted_volume if weighted_volume != 0.0 else 1.0) 66 background = values[1] 67 #print("scale",scale,background) 68 return self.result[0:nout*self.q_input.nq:nout], effective_radius 69 70 def beta(self, call_details, values, cutoff, magnetic, effective_radius_type): 71 # type: (CallDetails, np.ndarray, np.ndarray, float, bool, int) -> np.ndarray 72 if self.dim == '2d': 73 raise NotImplementedError("beta not yet supported for 2D") 74 if not self.info.have_Fq: 75 raise NotImplementedError("beta not yet supported for "+self.info.id) 76 self._call_kernel(call_details, values, cutoff, magnetic, effective_radius_type) 77 total_weight = self.result[2*self.q_input.nq + 0] 78 if total_weight == 0.: 79 total_weight = 1. 80 weighted_volume = self.result[2*self.q_input.nq + 1] 81 weighted_radius = self.result[2*self.q_input.nq + 2] 82 volume_average = weighted_volume/total_weight 83 effective_radius = weighted_radius/total_weight 84 F2 = self.result[0:2*self.q_input.nq:2]/total_weight 85 F1 = self.result[1:2*self.q_input.nq:2]/total_weight 86 return F1, F2, volume_average, effective_radius 46 87 47 88 def release(self): 48 89 # type: () -> None 49 90 pass 91 92 def _call_kernel(self, call_details, values, cutoff, magnetic, effective_radius_type): 93 # type: (CallDetails, np.ndarray, np.ndarray, float, bool, int) -> np.ndarray 94 raise NotImpmentedError() -
sasmodels/kernel_iq.c
rc036ddb r6e7ba14 27 27 // parameters in the parameter table. 28 28 // CALL_VOLUME(table) : call the form volume function 29 // CALL_EFFECTIVE_RADIUS(type, table) : call the R_eff function 29 30 // CALL_IQ(q, table) : call the Iq function for 1D calcs. 30 31 // CALL_IQ_A(q, table) : call the Iq function with |q| for 2D data. … … 284 285 global const double *q, // nq q values, with padding to boundary 285 286 global double *result, // nq+1 return values, again with padding 286 const double cutoff // cutoff in the dispersity weight product 287 const double cutoff, // cutoff in the dispersity weight product 288 int effective_radius_type // which effective radius to compute 287 289 ) 288 290 { … … 344 346 #ifdef USE_OPENCL 345 347 #if COMPUTE_F1_F2 346 double pd_norm = (pd_start == 0 ? 0.0 : result[nq]); 347 double weight_norm = (pd_start == 0 ? 0.0 : result[2*nq+1]); 348 double this_F2 = (pd_start == 0 ? 0.0 : result[q_index]); 349 double this_F1 = (pd_start == 0 ? 0.0 : result[q_index+nq+1]); 348 double weight_norm = (pd_start == 0 ? 0.0 : result[2*nq]); 349 double weighted_volume = (pd_start == 0 ? 0.0 : result[2*nq+1]); 350 double weighted_radius = (pd_start == 0 ? 0.0 : result[2*nq+2]); 351 double this_F2 = (pd_start == 0 ? 0.0 : result[2*q_index+0]); 352 double this_F1 = (pd_start == 0 ? 0.0 : result[2*q_index+1]); 350 353 #else 351 double pd_norm = (pd_start == 0 ? 0.0 : result[nq]); 354 double weight_norm = (pd_start == 0 ? 0.0 : result[nq]); 355 double weighted_volume = (pd_start == 0 ? 0.0 : result[nq+1]); 356 double weighted_radius = (pd_start == 0 ? 0.0 : result[nq+2]); 352 357 double this_result = (pd_start == 0 ? 0.0 : result[q_index]); 353 358 #endif 354 359 #else // !USE_OPENCL 355 360 #if COMPUTE_F1_F2 356 double pd_norm = (pd_start == 0 ? 0.0 : result[nq]); 357 double weight_norm = (pd_start == 0 ? 0.0 : result[2*nq+1]); 361 double weight_norm = (pd_start == 0 ? 0.0 : result[2*nq]); 362 double weighted_volume = (pd_start == 0 ? 0.0 : result[2*nq+1]); 363 double weighted_radius = (pd_start == 0 ? 0.0 : result[2*nq+2]); 358 364 #else 359 double pd_norm = (pd_start == 0 ? 0.0 : result[nq]); 365 double weight_norm = (pd_start == 0 ? 0.0 : result[nq]); 366 double weighted_volume = (pd_start == 0 ? 0.0 : result[nq+1]); 367 double weighted_radius = (pd_start == 0 ? 0.0 : result[nq+2]); 360 368 #endif 361 369 if (pd_start == 0) { … … 364 372 #endif 365 373 #if COMPUTE_F1_F2 366 for (int q_index=0; q_index < 2*nq+2; q_index++) result[q_index] = 0.0; 374 // 2*nq for F^2,F pairs 375 for (int q_index=0; q_index < 2*nq; q_index++) result[q_index] = 0.0; 367 376 #else 368 377 for (int q_index=0; q_index < nq; q_index++) result[q_index] = 0.0; 369 378 #endif 370 379 } 371 //if (q_index==0) printf("start %d %g %g\n", pd_start, pd_norm, result[0]);380 //if (q_index==0) printf("start %d %g %g\n", pd_start, weighted_volume, result[0]); 372 381 #endif // !USE_OPENCL 373 382 … … 684 693 // Note: weight==0 must always be excluded 685 694 if (weight > cutoff) { 686 pd_norm+= weight * CALL_VOLUME(local_values.table);695 weighted_volume += weight * CALL_VOLUME(local_values.table); 687 696 #if COMPUTE_F1_F2 688 697 weight_norm += weight; 689 698 #endif 699 if (effective_radius_type != 0) { 700 weighted_radius += weight * CALL_EFFECTIVE_RADIUS(effective_radius_type, local_values.table); 701 } 690 702 BUILD_ROTATION(); 691 703 … … 745 757 #ifdef USE_OPENCL 746 758 #if COMPUTE_F1_F2 759 this_F2 += weight * F2; 747 760 this_F1 += weight * F1; 748 this_F2 += weight * F2;749 761 #else 750 762 this_result += weight * scattering; … … 752 764 #else // !USE_OPENCL 753 765 #if COMPUTE_F1_F2 754 result[ q_index] += weight * F2;755 result[ q_index+nq+1] += weight * F1;766 result[2*q_index+0] += weight * F2; 767 result[2*q_index+1] += weight * F1; 756 768 #else 757 769 result[q_index] += weight * scattering; … … 782 794 #ifdef USE_OPENCL 783 795 #if COMPUTE_F1_F2 784 result[ q_index] = this_F2;785 result[ q_index+nq+1] = this_F1;796 result[2*q_index+0] = this_F2; 797 result[2*q_index+1] = this_F1; 786 798 if (q_index == 0) { 787 result[nq] = pd_norm; 788 result[2*nq+1] = weight_norm; 799 result[2*nq+0] = weight_norm; 800 result[2*nq+1] = weighted_volume; 801 result[2*nq+2] = weighted_radius; 789 802 } 790 803 #else 791 804 result[q_index] = this_result; 792 if (q_index == 0) result[nq] = pd_norm; 805 if (q_index == 0) { 806 result[nq+0] = weight_norm; 807 result[nq+1] = weighted_volume; 808 result[nq+2] = weighted_radius; 809 } 793 810 #endif 794 811 795 //if (q_index == 0) printf("res: %g/%g\n", result[0], pd_norm);812 //if (q_index == 0) printf("res: %g/%g\n", result[0], weigthed_volume); 796 813 #else // !USE_OPENCL 797 814 #if COMPUTE_F1_F2 798 result[nq] = pd_norm; 799 result[2*nq+1] = weight_norm; 815 result[2*nq] = weight_norm; 816 result[2*nq+1] = weighted_volume; 817 result[2*nq+2] = weighted_radius; 800 818 #else 801 result[nq] = pd_norm; 819 result[nq] = weight_norm; 820 result[nq+1] = weighted_volume; 821 result[nq+2] = weighted_radius; 802 822 #endif 803 //printf("res: %g/%g\n", result[0], pd_norm);823 //printf("res: %g/%g\n", result[0], weighted_volume); 804 824 #endif // !USE_OPENCL 805 825 -
sasmodels/kernelcl.py
rc036ddb r6e7ba14 540 540 # leave room for f1/f2 results in case we need to compute beta for 1d models 541 541 num_returns = 1 if self.dim == '2d' else 2 # 542 # plus 1 for the normalization value 543 self.result = np.empty((q_input.nq+ 1)*num_returns, dtype)542 # plus 1 for the normalization value, plus another for R_eff 543 self.result = np.empty((q_input.nq+2)*num_returns, dtype) 544 544 545 545 # Inputs and outputs for each kernel call … … 558 558 else np.float32) # will never get here, so use np.float32 559 559 560 def Iq(self, call_details, values, cutoff, magnetic): 561 # type: (CallDetails, np.ndarray, np.ndarray, float, bool) -> np.ndarray 562 self._call_kernel(call_details, values, cutoff, magnetic) 563 #print("returned",self.q_input.q, self.result) 564 pd_norm = self.result[self.q_input.nq] 565 scale = values[0]/(pd_norm if pd_norm != 0.0 else 1.0) 566 background = values[1] 567 #print("scale",scale,background) 568 return scale*self.result[:self.q_input.nq] + background 569 __call__ = Iq 570 571 def beta(self, call_details, values, cutoff, magnetic): 572 # type: (CallDetails, np.ndarray, np.ndarray, float, bool) -> np.ndarray 573 if self.dim == '2d': 574 raise NotImplementedError("beta not yet supported for 2D") 575 self._call_kernel(call_details, values, cutoff, magnetic) 576 w_norm = self.result[2*self.q_input.nq + 1] 577 pd_norm = self.result[self.q_input.nq] 578 if w_norm == 0.: 579 w_norm = 1. 580 F2 = self.result[:self.q_input.nq]/w_norm 581 F1 = self.result[self.q_input.nq+1:2*self.q_input.nq+1]/w_norm 582 volume_avg = pd_norm/w_norm 583 return F1, F2, volume_avg 584 585 def _call_kernel(self, call_details, values, cutoff, magnetic): 560 def _call_kernel(self, call_details, values, cutoff, magnetic, effective_radius_type): 586 561 # type: (CallDetails, np.ndarray, np.ndarray, float, bool) -> np.ndarray 587 562 context = self.queue.context … … 597 572 details_b, values_b, self.q_input.q_b, self.result_b, 598 573 self.real(cutoff), 574 np.uint32(effective_radius_type), 599 575 ] 600 576 #print("Calling OpenCL") -
sasmodels/kerneldll.py
r2f8cbb9 r6e7ba14 315 315 316 316 # int, int, int, int*, double*, double*, double*, double*, double 317 argtypes = [ct.c_int32]*3 + [ct.c_void_p]*4 + [float_type ]317 argtypes = [ct.c_int32]*3 + [ct.c_void_p]*4 + [float_type, ct.c_int32] 318 318 names = [generate.kernel_name(self.info, variant) 319 319 for variant in ("Iq", "Iqxy", "Imagnetic")] … … 382 382 self.dim = '2d' if q_input.is_2d else '1d' 383 383 # leave room for f1/f2 results in case we need to compute beta for 1d models 384 n um_returns = 1 if self.dim == '2d' else 2 #385 # plus 1 for the normalization value386 self.result = np.empty( (q_input.nq+1)*num_returns, self.dtype)384 nout = 2 if self.info.have_Fq else 1 385 # plus 3 weight, volume, radius 386 self.result = np.empty(q_input.nq*nout + 3, self.dtype) 387 387 self.real = (np.float32 if self.q_input.dtype == generate.F32 388 388 else np.float64 if self.q_input.dtype == generate.F64 389 389 else np.float128) 390 390 391 def Iq(self, call_details, values, cutoff, magnetic): 392 # type: (CallDetails, np.ndarray, np.ndarray, float, bool) -> np.ndarray 393 self._call_kernel(call_details, values, cutoff, magnetic) 394 #print("returned",self.q_input.q, self.result) 395 pd_norm = self.result[self.q_input.nq] 396 scale = values[0]/(pd_norm if pd_norm != 0.0 else 1.0) 397 background = values[1] 398 #print("scale",scale,background) 399 return scale*self.result[:self.q_input.nq] + background 400 __call__ = Iq 401 402 def beta(self, call_details, values, cutoff, magnetic): 403 # type: (CallDetails, np.ndarray, np.ndarray, float, bool) -> np.ndarray 404 if self.dim == '2d': 405 raise NotImplementedError("beta not yet supported for 2D") 406 self._call_kernel(call_details, values, cutoff, magnetic) 407 w_norm = self.result[2*self.q_input.nq + 1] 408 pd_norm = self.result[self.q_input.nq] 409 if w_norm == 0.: 410 w_norm = 1. 411 F2 = self.result[:self.q_input.nq]/w_norm 412 F1 = self.result[self.q_input.nq+1:2*self.q_input.nq+1]/w_norm 413 volume_avg = pd_norm/w_norm 414 return F1, F2, volume_avg 415 416 def _call_kernel(self, call_details, values, cutoff, magnetic): 391 def _call_kernel(self, call_details, values, cutoff, magnetic, effective_radius_type): 392 # type: (CallDetails, np.ndarray, np.ndarray, float, bool, int) -> np.ndarray 417 393 kernel = self.kernel[1 if magnetic else 0] 418 394 args = [ … … 425 401 self.result.ctypes.data, # results 426 402 self.real(cutoff), # cutoff 403 effective_radius_type, # cutoff 427 404 ] 428 405 #print("Calling DLL") -
sasmodels/kernelpy.py
r108e70e r6e7ba14 12 12 13 13 import numpy as np # type: ignore 14 from numpy import pi 15 try: 16 from numpy import cbrt 17 except ImportError: 18 def cbrt(x): return x ** (1.0/3.0) 14 19 15 20 from .generate import F64 … … 158 163 159 164 # Generate a closure which calls the form_volume if it exists. 160 form_volume = model_info.form_volume 161 self._volume = ((lambda: form_volume(*volume_args)) if form_volume else 162 (lambda: 1.0)) 163 164 def __call__(self, call_details, values, cutoff, magnetic): 165 self._volume_args = volume_args 166 volume = model_info.form_volume 167 radius = model_info.effective_radius 168 self._volume = ((lambda: volume(*volume_args)) if volume 169 else (lambda: 1.0)) 170 self._radius = ((lambda mode: radius(mode, *volume_args)) if radius 171 else (lambda mode: cbrt(0.75/pi*volume(*volume_args))) if volume 172 else (lambda mode: 1.0)) 173 174 175 176 def _call_kernel(self, call_details, values, cutoff, magnetic, effective_radius_type): 165 177 # type: (CallDetails, np.ndarray, np.ndarray, float, bool) -> np.ndarray 166 178 if magnetic: … … 168 180 #print("Calling python kernel") 169 181 #call_details.show(values) 170 res = _loops(self._parameter_vector, self._form, self._volume, 182 radius = ((lambda: 0.0) if effective_radius_type == 0 183 else (lambda: self._radius(effective_radius_type))) 184 res = _loops(self._parameter_vector, self._form, self._volume, radius, 171 185 self.q_input.nq, call_details, values, cutoff) 172 186 return res … … 183 197 form, # type: Callable[[], np.ndarray] 184 198 form_volume, # type: Callable[[], float] 199 form_radius, # type: Callable[[], float] 185 200 nq, # type: int 186 201 call_details, # type: details.CallDetails 187 202 values, # type: np.ndarray 188 cutoff 203 cutoff, # type: float 189 204 ): 190 205 # type: (...) -> None … … 209 224 pd_weight = values[2+n_pars + call_details.num_weights:] 210 225 211 pd_norm = 0.0 226 weight_norm = 0.0 227 weighted_volume = 0.0 228 weighted_radius = 0.0 212 229 partial_weight = np.NaN 213 230 weight = np.NaN … … 246 263 # update value and norm 247 264 total += weight * Iq 248 pd_norm += weight * form_volume() 249 250 scale = values[0]/(pd_norm if pd_norm != 0.0 else 1.0) 251 background = values[1] 252 return scale*total + background 265 weight_norm += weight 266 weighted_volume += weight * form_volume() 267 weighted_radius += weight * form_radius() 268 269 result = np.hstack((total, weight_norm, weighted_volume, weighted_radius)) 270 return result 253 271 254 272 -
sasmodels/modelinfo.py
r7e923c2 r6e7ba14 789 789 info.structure_factor = getattr(kernel_module, 'structure_factor', False) 790 790 # TODO: find Fq by inspection 791 info.effective_radius_type = getattr(kernel_module, 'effective_radius_type', None) 791 792 info.have_Fq = getattr(kernel_module, 'have_Fq', False) 792 793 info.profile_axes = getattr(kernel_module, 'profile_axes', ['x', 'y']) 793 794 info.source = getattr(kernel_module, 'source', []) 794 795 info.c_code = getattr(kernel_module, 'c_code', None) 796 info.ER = None # CRUFT 797 info.VR = None # CRUFT 795 798 # TODO: check the structure of the tests 796 799 info.tests = getattr(kernel_module, 'tests', []) 797 info.ER = getattr(kernel_module, 'ER', None) # type: ignore798 info.VR = getattr(kernel_module, 'VR', None) # type: ignore799 800 info.form_volume = getattr(kernel_module, 'form_volume', None) # type: ignore 800 801 info.Iq = getattr(kernel_module, 'Iq', None) # type: ignore … … 922 923 #: use those functions. Form factors are indicated by providing 923 924 #: an :attr:`ER` function. 925 effective_radius_type = None # type: List[str] 926 #: Returns the occupied volume and the total volume for each parameter set. 927 #: See :attr:`ER` for details on the parameters. 924 928 source = None # type: List[str] 925 929 #: The set of tests that must pass. The format of the tests is described … … 942 946 #: each parameter set. Multiplicity parameters will be received as 943 947 #: arrays, with one row per polydispersity condition. 944 ER = None # type: Optional[Callable[[np.ndarray], np.ndarray]]945 #: Returns the occupied volume and the total volume for each parameter set.946 #: See :attr:`ER` for details on the parameters.947 VR = None # type: Optional[Callable[[np.ndarray], Tuple[np.ndarray, np.ndarray]]]948 #: Arbitrary C code containing supporting functions, etc., to be inserted949 #: after everything in source. This can include Iq and Iqxy functions with950 #: the full function signature, including all parameters.951 948 c_code = None 952 949 #: Returns the form volume for python-based models. Form volume is needed -
sasmodels/models/ellipsoid.c
r71b751d r6e7ba14 4 4 return M_4PI_3*radius_polar*radius_equatorial*radius_equatorial; 5 5 } 6 7 8 static double 9 radius_from_volume(double radius_polar, double radius_equatorial) 10 { 11 return cbrt(radius_polar*radius_equatorial*radius_equatorial); 12 } 13 14 static double 15 radius_from_curvature(double radius_polar, double radius_equatorial) 16 { 17 // Trivial cases 18 if (radius_polar == radius_equatorial) return radius_polar; 19 if (radius_polar * radius_equatorial == 0.) return 0.; 20 21 // see equation (26) in A.Isihara, J.Chem.Phys. 18(1950)1446-1449 22 const double ratio = (radius_polar < radius_equatorial 23 ? radius_polar / radius_equatorial 24 : radius_equatorial / radius_polar); 25 const double e1 = sqrt(1.0 - ratio*ratio); 26 const double b1 = 1.0 + asin(e1) / (e1 * ratio); 27 const double bL = (1.0 + e1) / (1.0 - e1); 28 const double b2 = 1.0 + 0.5 * ratio * ratio / e1 * log(bL); 29 const double delta = 0.75 * b1 * b2; 30 const double ddd = 2.0 * (delta + 1.0) * radius_polar * radius_equatorial * radius_equatorial; 31 return 0.5 * cbrt(ddd); 32 } 33 34 static double 35 effective_radius(int mode, double radius_polar, double radius_equatorial) 36 { 37 if (mode == 1) { 38 return radius_from_curvature(radius_polar, radius_equatorial); 39 } else if (mode == 2) { 40 return radius_from_volume(radius_polar, radius_equatorial); 41 } else if (mode == 3) { 42 return (radius_polar < radius_equatorial ? radius_polar : radius_equatorial); 43 } else { 44 return (radius_polar > radius_equatorial ? radius_polar : radius_equatorial); 45 } 46 } 47 6 48 7 49 static void -
sasmodels/models/ellipsoid.py
r71b751d r6e7ba14 164 164 source = ["lib/sas_3j1x_x.c", "lib/gauss76.c", "ellipsoid.c"] 165 165 have_Fq = True 166 167 def ER(radius_polar, radius_equatorial): 168 # see equation (26) in A.Isihara, J.Chem.Phys. 18(1950)1446-1449 169 ee = np.empty_like(radius_polar) 170 idx = radius_polar > radius_equatorial 171 ee[idx] = (radius_polar[idx] ** 2 - radius_equatorial[idx] ** 2) / radius_polar[idx] ** 2 172 idx = radius_polar < radius_equatorial 173 ee[idx] = (radius_equatorial[idx] ** 2 - radius_polar[idx] ** 2) / radius_equatorial[idx] ** 2 174 idx = radius_polar == radius_equatorial 175 ee[idx] = 2 * radius_polar[idx] 176 valid = (radius_polar * radius_equatorial != 0) 177 bd = 1.0 - ee[valid] 178 e1 = np.sqrt(ee[valid]) 179 b1 = 1.0 + np.arcsin(e1) / (e1 * np.sqrt(bd)) 180 bL = (1.0 + e1) / (1.0 - e1) 181 b2 = 1.0 + bd / 2 / e1 * np.log(bL) 182 delta = 0.75 * b1 * b2 183 184 ddd = np.zeros_like(radius_polar) 185 ddd[valid] = 2.0 * (delta + 1.0) * radius_polar * radius_equatorial ** 2 186 return 0.5 * ddd ** (1.0 / 3.0) 166 effective_radius_type = ["average curvature", "equivalent sphere", "min radius", "max radius"] 187 167 188 168 def random(): -
sasmodels/product.py
r6d90684 r6e7ba14 35 35 #] 36 36 37 ER_ID = "radius_effective" 38 VF_ID = "volfraction" 39 BETA_DEFINITION = ("beta_mode", "", 0, [["P*S"],["P*(1+beta*(S-1))"]], "", 40 "Structure factor dispersion calculation mode") 37 RADIUS_ID = "radius_effective" 38 VOLFRAC_ID = "volfraction" 39 def make_extra_pars(p_info): 40 pars = [] 41 if p_info.have_Fq: 42 par = Parameter("structure_factor_mode", "", 0, [["P*S","P*(1+beta*(S-1))"]], "", 43 "Structure factor calculation") 44 pars.append(par) 45 if p_info.effective_radius_type is not None: 46 par = Parameter("radius_effective_mode", "", 0, 47 [["unconstrained"] + p_info.effective_radius_type], 48 "", "Effective radius calculation") 49 pars.append(par) 50 return pars 41 51 42 52 # TODO: core_shell_sphere model has suppressed the volume ratio calculation … … 52 62 # have any magnetic parameters 53 63 if not len(s_info.parameters.kernel_parameters) >= 2: 54 raise TypeError("S needs {} and {} as its first parameters".format( ER_ID, VF_ID))55 if not s_info.parameters.kernel_parameters[0].id == ER_ID:56 raise TypeError("S needs {} as first parameter".format( ER_ID))57 if not s_info.parameters.kernel_parameters[1].id == V F_ID:58 raise TypeError("S needs {} as second parameter".format(V F_ID))64 raise TypeError("S needs {} and {} as its first parameters".format(RADIUS_ID, VOLFRAC_ID)) 65 if not s_info.parameters.kernel_parameters[0].id == RADIUS_ID: 66 raise TypeError("S needs {} as first parameter".format(RADIUS_ID)) 67 if not s_info.parameters.kernel_parameters[1].id == VOLFRAC_ID: 68 raise TypeError("S needs {} as second parameter".format(VOLFRAC_ID)) 59 69 if not s_info.parameters.magnetism_index == []: 60 70 raise TypeError("S should not have SLD parameters") … … 62 72 s_id, s_name, s_pars = s_info.id, s_info.name, s_info.parameters 63 73 64 # Create list of parameters for the combined model. Skip the first 65 # parameter of S, which we verified above is effective radius. If there 74 # Create list of parameters for the combined model. If there 66 75 # are any names in P that overlap with those in S, modify the name in S 67 76 # to distinguish it. 68 77 p_set = set(p.id for p in p_pars.kernel_parameters) 69 78 s_list = [(_tag_parameter(par) if par.id in p_set else par) 70 for par in s_pars.kernel_parameters [1:]]79 for par in s_pars.kernel_parameters] 71 80 # Check if still a collision after renaming. This could happen if for 72 81 # example S has volfrac and P has both volfrac and volfrac_S. … … 74 83 raise TypeError("name collision: P has P.name and P.name_S while S has S.name") 75 84 85 # make sure effective radius is not a polydisperse parameter in product 86 s_list[0] = copy(s_list[0]) 87 s_list[0].polydisperse = False 88 76 89 translate_name = dict((old.id, new.id) for old, new 77 in zip(s_pars.kernel_parameters[1:], s_list)) 78 beta = [Parameter(*BETA_DEFINITION)] if p_info.have_Fq else [] 79 combined_pars = p_pars.kernel_parameters + s_list + beta 90 in zip(s_pars.kernel_parameters, s_list)) 91 combined_pars = p_pars.kernel_parameters + s_list + make_extra_pars(p_info) 80 92 parameters = ParameterTable(combined_pars) 81 93 parameters.max_pd = p_pars.max_pd + s_pars.max_pd 82 94 def random(): 83 95 combined_pars = p_info.random() 84 s_names = set(par.id for par in s_pars.kernel_parameters [1:])96 s_names = set(par.id for par in s_pars.kernel_parameters) 85 97 combined_pars.update((translate_name[k], v) 86 98 for k, v in s_info.random().items() … … 225 237 p_values = np.hstack(p_values).astype(self.p_kernel.dtype) 226 238 227 # Call ER and VR for P since these are needed for S.228 p_er, p_vr = calc_er_vr(p_info, p_details, p_values)229 s_vr = (volfrac/p_vr if p_vr != 0. else volfrac)230 #print("volfrac:%g p_er:%g p_vr:%g s_vr:%g"%(volfrac,p_er,p_vr,s_vr))231 232 239 # Construct the calling parameters for S. 233 # The effective radius is not in the combined parameter list, so 234 # the number of 'S' parameters is one less than expected. The 235 # computed effective radius needs to be added into the weights 236 # vector, especially since it is a polydisperse parameter in the 237 # stand-alone structure factor models. We will added it at the 238 # end so the remaining offsets don't need to change. 239 s_npars = s_info.parameters.npars-1 240 s_npars = s_info.parameters.npars 240 241 s_length = call_details.length[p_npars:p_npars+s_npars] 241 242 s_offset = call_details.offset[p_npars:p_npars+s_npars] … … 243 244 s_offset = np.hstack((nweights, s_offset)) 244 245 s_details = make_details(s_info, s_length, s_offset, nweights+1) 245 v, w = weights[:nweights], weights[nweights:]246 246 s_values = [ 247 # scale=1, background=0, radius_effective=p_er, volfraction=s_vr 248 [1., 0., p_er, s_vr], 249 # structure factor parameters start after scale, background and 250 # all the form factor parameters. Skip the volfraction parameter 251 # as well, since it is computed elsewhere, and go to the end of the 252 # parameter list. 253 values[2+p_npars+1:2+p_npars+s_npars], 254 # no magnetism parameters to include for S 255 # add er into the (value, weights) pairs 256 v, [p_er], w, [1.0] 247 # scale=1, background=0, 248 [1., 0.], 249 values[2+p_npars:2+p_npars+s_npars], 250 weights, 257 251 ] 258 252 spacer = (32 - sum(len(v) for v in s_values)%32)%32 … … 261 255 262 256 # beta mode is the first parameter after the structure factor pars 263 beta_index = 2+p_npars+s_npars 264 beta_mode = values[beta_index] 257 extra_offset = 2+p_npars+s_npars 258 if p_info.have_Fq: 259 beta_mode = values[extra_offset] 260 extra_offset += 1 261 else: 262 beta_mode = 0 263 if p_info.effective_radius_type is not None: 264 effective_radius_type = values[extra_offset] 265 extra_offset += 1 266 else: 267 effective_radius_type = 0 265 268 266 269 # Call the kernels 267 s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False)268 270 scale, background = values[0], values[1] 269 271 if beta_mode: 270 F1, F2, volume_avg = self.p_kernel.beta(p_details, p_values, cutoff, magnetic) 272 F1, F2, volume_avg, effective_radius = self.p_kernel.beta( 273 p_details, p_values, cutoff, magnetic, effective_radius_type) 274 if effective_radius_type > 0: 275 s_values[2] = s_values[2+s_npars+s_offset[0]] = effective_radius 276 s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False) 271 277 combined_scale = scale*volfrac/volume_avg 272 278 # Define lazy results based on intermediate values. … … 297 303 final_result = combined_scale*(F2 + (F1**2)*(s_result - 1)) + background 298 304 else: 299 p_result = self.p_kernel.Iq(p_details, p_values, cutoff, magnetic) 305 p_result, effective_radius = self.p_kernel.Pq_Reff( 306 p_details, p_values, cutoff, magnetic, effective_radius_type) 307 if effective_radius_type > 0: 308 s_values[2] = s_values[2+s_npars+s_offset[0]] = effective_radius 309 s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False) 300 310 # remember the parts for plotting later 301 311 self.results = [p_result, s_result] -
sasmodels/sasview_model.py
rd533590 r6e7ba14 272 272 attrs['category'] = model_info.category 273 273 attrs['is_structure_factor'] = model_info.structure_factor 274 attrs['is_form_factor'] = model_info. ERis not None274 attrs['is_form_factor'] = model_info.effective_radius_type is not None 275 275 attrs['is_multiplicity_model'] = variants[0] > 1 276 276 attrs['multiplicity_info'] = variants
Note: See TracChangeset
for help on using the changeset viewer.