Changes in sasmodels/product.py [c0131d44:33d7be3] in sasmodels
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/product.py
rc0131d44 r33d7be3 24 24 # pylint: disable=unused-import 25 25 try: 26 from typing import Tuple, Callable 26 from typing import Tuple, Callable, Union 27 27 except ImportError: 28 28 pass … … 37 37 #] 38 38 39 ER_ID = "radius_effective" 40 VF_ID = "volfraction" 41 39 RADIUS_ID = "radius_effective" 40 VOLFRAC_ID = "volfraction" 42 41 def make_extra_pars(p_info): 43 42 pars = [] 44 43 if p_info.have_Fq: 45 par = parse_parameter( 46 "structure_factor_mode", 47 "", 48 0, 49 [["P*S","P*(1+beta*(S-1))"]], 50 "", 51 "Structure factor calculation") 44 par = parse_parameter("structure_factor_mode", "", 0, [["P*S","P*(1+beta*(S-1))"]], "", 45 "Structure factor calculation") 46 pars.append(par) 47 if p_info.effective_radius_type is not None: 48 par = parse_parameter("radius_effective_mode", "", 0, [["unconstrained"] + p_info.effective_radius_type], "", 49 "Effective radius calculation") 52 50 pars.append(par) 53 51 return pars … … 65 63 # have any magnetic parameters 66 64 if not len(s_info.parameters.kernel_parameters) >= 2: 67 raise TypeError("S needs {} and {} as its first parameters".format( ER_ID, VF_ID))68 if not s_info.parameters.kernel_parameters[0].id == ER_ID:69 raise TypeError("S needs {} as first parameter".format( ER_ID))70 if not s_info.parameters.kernel_parameters[1].id == V F_ID:71 raise TypeError("S needs {} as second parameter".format(V F_ID))65 raise TypeError("S needs {} and {} as its first parameters".format(RADIUS_ID, VOLFRAC_ID)) 66 if not s_info.parameters.kernel_parameters[0].id == RADIUS_ID: 67 raise TypeError("S needs {} as first parameter".format(RADIUS_ID)) 68 if not s_info.parameters.kernel_parameters[1].id == VOLFRAC_ID: 69 raise TypeError("S needs {} as second parameter".format(VOLFRAC_ID)) 72 70 if not s_info.parameters.magnetism_index == []: 73 71 raise TypeError("S should not have SLD parameters") … … 75 73 s_id, s_name, s_pars = s_info.id, s_info.name, s_info.parameters 76 74 77 # Create list of parameters for the combined model. Skip the first 78 # parameter of S, which we verified above is effective radius. If there 75 # Create list of parameters for the combined model. If there 79 76 # are any names in P that overlap with those in S, modify the name in S 80 77 # to distinguish it. 81 78 p_set = set(p.id for p in p_pars.kernel_parameters) 82 79 s_list = [(_tag_parameter(par) if par.id in p_set else par) 83 for par in s_pars.kernel_parameters [1:]]80 for par in s_pars.kernel_parameters] 84 81 # Check if still a collision after renaming. This could happen if for 85 82 # example S has volfrac and P has both volfrac and volfrac_S. … … 87 84 raise TypeError("name collision: P has P.name and P.name_S while S has S.name") 88 85 86 # make sure effective radius is not a polydisperse parameter in product 87 s_list[0] = copy(s_list[0]) 88 s_list[0].polydisperse = False 89 89 90 translate_name = dict((old.id, new.id) for old, new 90 in zip(s_pars.kernel_parameters [1:], s_list))91 in zip(s_pars.kernel_parameters, s_list)) 91 92 combined_pars = p_pars.kernel_parameters + s_list + make_extra_pars(p_info) 92 93 parameters = ParameterTable(combined_pars) … … 94 95 def random(): 95 96 combined_pars = p_info.random() 96 s_names = set(par.id for par in s_pars.kernel_parameters [1:])97 s_names = set(par.id for par in s_pars.kernel_parameters) 97 98 combined_pars.update((translate_name[k], v) 98 99 for k, v in s_info.random().items() … … 157 158 return par 158 159 159 def _intermediates(P, S ):160 # type: (np.ndarray, np.ndarray ) -> OrderedDict[str, np.ndarray]160 def _intermediates(P, S, effective_radius): 161 # type: (np.ndarray, np.ndarray, float) -> OrderedDict[str, np.ndarray] 161 162 """ 162 163 Returns intermediate results for standard product (P(Q)*S(Q)) … … 165 166 ("P(Q)", P), 166 167 ("S(Q)", S), 168 ("effective_radius", effective_radius), 167 169 )) 168 170 169 def _intermediates_beta(F1, F2, S, scale, bg ):170 # type: (np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray ) -> OrderedDict[str, np.ndarray]171 """ 172 Returns intermediate results for beta approximation-enabled product 171 def _intermediates_beta(F1, F2, S, scale, bg, effective_radius): 172 # type: (np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, float) -> OrderedDict[str, Union[np.ndarray, float]] 173 """ 174 Returns intermediate results for beta approximation-enabled product. The result may be an array or a float. 173 175 """ 174 176 # TODO: 1. include calculated Q vector … … 179 181 ("beta(Q)", F1**2 / F2), 180 182 ("S_eff(Q)", 1 + (F1**2 / F2)*(S-1)), 183 ("effective_radius", effective_radius), 181 184 # ("I(Q)", scale*(F2 + (F1**2)*(S-1)) + bg), 182 185 )) … … 262 265 p_values = np.hstack(p_values).astype(self.p_kernel.dtype) 263 266 264 # Call ER and VR for P since these are needed for S.265 p_er, p_vr = calc_er_vr(p_info, p_details, p_values)266 s_vr = (volfrac/p_vr if p_vr != 0. else volfrac)267 #print("volfrac:%g p_er:%g p_vr:%g s_vr:%g"%(volfrac,p_er,p_vr,s_vr))268 269 267 # Construct the calling parameters for S. 270 # The effective radius is not in the combined parameter list, so 271 # the number of 'S' parameters is one less than expected. The 272 # computed effective radius needs to be added into the weights 273 # vector, especially since it is a polydisperse parameter in the 274 # stand-alone structure factor models. We will added it at the 275 # end so the remaining offsets don't need to change. 276 s_npars = s_info.parameters.npars-1 268 s_npars = s_info.parameters.npars 277 269 s_length = call_details.length[p_npars:p_npars+s_npars] 278 270 s_offset = call_details.offset[p_npars:p_npars+s_npars] … … 280 272 s_offset = np.hstack((nweights, s_offset)) 281 273 s_details = make_details(s_info, s_length, s_offset, nweights+1) 282 v, w = weights[:nweights], weights[nweights:]283 274 s_values = [ 284 # scale=1, background=0, radius_effective=p_er, volfraction=s_vr 285 [1., 0., p_er, s_vr], 286 # structure factor parameters start after scale, background and 287 # all the form factor parameters. Skip the volfraction parameter 288 # as well, since it is computed elsewhere, and go to the end of the 289 # parameter list. 290 values[2+p_npars+1:2+p_npars+s_npars], 291 # no magnetism parameters to include for S 292 # add er into the (value, weights) pairs 293 v, [p_er], w, [1.0] 275 # scale=1, background=0, 276 [1., 0.], 277 values[2+p_npars:2+p_npars+s_npars], 278 weights, 294 279 ] 295 280 spacer = (32 - sum(len(v) for v in s_values)%32)%32 … … 298 283 299 284 # beta mode is the first parameter after the structure factor pars 300 beta_index = 2+p_npars+s_npars 301 beta_mode = values[beta_index] 285 extra_offset = 2+p_npars+s_npars 286 if p_info.have_Fq: 287 beta_mode = values[extra_offset] 288 extra_offset += 1 289 else: 290 beta_mode = 0 291 if p_info.effective_radius_type is not None: 292 effective_radius_type = int(values[extra_offset]) 293 extra_offset += 1 294 else: 295 effective_radius_type = 0 302 296 303 297 # Call the kernels 304 s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False)305 298 scale, background = values[0], values[1] 306 299 if beta_mode: 307 F1, F2, volume_avg = self.p_kernel.beta(p_details, p_values, cutoff, magnetic) 300 F1, F2, volume_avg, effective_radius = self.p_kernel.beta( 301 p_details, p_values, cutoff, magnetic, effective_radius_type) 302 if effective_radius_type > 0: 303 # Plug R_eff from p into S model (initial value and pd value) 304 s_values[2] = s_values[2+s_npars+s_offset[0]] = effective_radius 305 s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False) 308 306 combined_scale = scale*volfrac/volume_avg 309 307 310 self.results = lambda: _intermediates_beta(F1, F2, s_result, volfrac/volume_avg, background )308 self.results = lambda: _intermediates_beta(F1, F2, s_result, volfrac/volume_avg, background, effective_radius) 311 309 final_result = combined_scale*(F2 + (F1**2)*(s_result - 1)) + background 312 310 313 311 else: 314 p_result = self.p_kernel.Iq(p_details, p_values, cutoff, magnetic) 315 316 self.results = lambda: _intermediates(p_result, s_result) 312 p_result, effective_radius = self.p_kernel.Pq_Reff( 313 p_details, p_values, cutoff, magnetic, effective_radius_type) 314 if effective_radius_type > 0: 315 # Plug R_eff from p into S model (initial value and pd value) 316 s_values[2] = s_values[2+s_npars+s_offset[0]] = effective_radius 317 s_result = self.s_kernel.Iq(s_details, s_values, cutoff, False) 318 # remember the parts for plotting later 319 self.results = lambda: _intermediates(p_result, s_result, effective_radius) 317 320 final_result = scale*(p_result*s_result) + background 318 321
Note: See TracChangeset
for help on using the changeset viewer.