Changes in sasmodels/kernelpy.py [108e70e:5399809] in sasmodels
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/kernelpy.py
r108e70e r5399809 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, 171 self.q_input.nq, call_details, values, cutoff) 172 return res 182 radius = ((lambda: 0.0) if effective_radius_type == 0 183 else (lambda: self._radius(effective_radius_type))) 184 self.result = _loops( 185 self._parameter_vector, self._form, self._volume, radius, 186 self.q_input.nq, call_details, values, cutoff) 173 187 174 188 def release(self): … … 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 … … 198 213 # # 199 214 ################################################################ 215 216 # WARNING: Trickery ahead 217 # The parameters[] vector is embedded in the closures for form(), 218 # form_volume() and form_radius(). We set the initial vector from 219 # the values for the model parameters. As we loop through the polydispesity 220 # mesh, we update the components with the polydispersity values before 221 # calling the respective functions. 200 222 n_pars = len(parameters) 201 223 parameters[:] = values[2:n_pars+2] 224 202 225 if call_details.num_active == 0: 203 pd_norm = float(form_volume()) 204 scale = values[0]/(pd_norm if pd_norm != 0.0 else 1.0) 205 background = values[1] 206 return scale*form() + background 207 208 pd_value = values[2+n_pars:2+n_pars + call_details.num_weights] 209 pd_weight = values[2+n_pars + call_details.num_weights:] 210 211 pd_norm = 0.0 212 partial_weight = np.NaN 213 weight = np.NaN 214 215 p0_par = call_details.pd_par[0] 216 p0_length = call_details.pd_length[0] 217 p0_index = p0_length 218 p0_offset = call_details.pd_offset[0] 219 220 pd_par = call_details.pd_par[:call_details.num_active] 221 pd_offset = call_details.pd_offset[:call_details.num_active] 222 pd_stride = call_details.pd_stride[:call_details.num_active] 223 pd_length = call_details.pd_length[:call_details.num_active] 224 225 total = np.zeros(nq, 'd') 226 for loop_index in range(call_details.num_eval): 227 # update polydispersity parameter values 228 if p0_index == p0_length: 229 pd_index = (loop_index//pd_stride)%pd_length 230 parameters[pd_par] = pd_value[pd_offset+pd_index] 231 partial_weight = np.prod(pd_weight[pd_offset+pd_index][1:]) 232 p0_index = loop_index%p0_length 233 234 weight = partial_weight * pd_weight[p0_offset + p0_index] 235 parameters[p0_par] = pd_value[p0_offset + p0_index] 236 p0_index += 1 237 if weight > cutoff: 238 # Call the scattering function 239 # Assume that NaNs are only generated if the parameters are bad; 240 # exclude all q for that NaN. Even better would be to have an 241 # INVALID expression like the C models, but that is too expensive. 242 Iq = np.asarray(form(), 'd') 243 if np.isnan(Iq).any(): 244 continue 245 246 # update value and norm 247 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 226 total = form() 227 weight_norm = 1.0 228 weighted_volume = form_volume() 229 weighted_radius = form_radius() 230 231 else: 232 pd_value = values[2+n_pars:2+n_pars + call_details.num_weights] 233 pd_weight = values[2+n_pars + call_details.num_weights:] 234 235 weight_norm = 0.0 236 weighted_volume = 0.0 237 weighted_radius = 0.0 238 partial_weight = np.NaN 239 weight = np.NaN 240 241 p0_par = call_details.pd_par[0] 242 p0_length = call_details.pd_length[0] 243 p0_index = p0_length 244 p0_offset = call_details.pd_offset[0] 245 246 pd_par = call_details.pd_par[:call_details.num_active] 247 pd_offset = call_details.pd_offset[:call_details.num_active] 248 pd_stride = call_details.pd_stride[:call_details.num_active] 249 pd_length = call_details.pd_length[:call_details.num_active] 250 251 total = np.zeros(nq, 'd') 252 for loop_index in range(call_details.num_eval): 253 # update polydispersity parameter values 254 if p0_index == p0_length: 255 pd_index = (loop_index//pd_stride)%pd_length 256 parameters[pd_par] = pd_value[pd_offset+pd_index] 257 partial_weight = np.prod(pd_weight[pd_offset+pd_index][1:]) 258 p0_index = loop_index%p0_length 259 260 weight = partial_weight * pd_weight[p0_offset + p0_index] 261 parameters[p0_par] = pd_value[p0_offset + p0_index] 262 p0_index += 1 263 if weight > cutoff: 264 # Call the scattering function 265 # Assume that NaNs are only generated if the parameters are bad; 266 # exclude all q for that NaN. Even better would be to have an 267 # INVALID expression like the C models, but that is expensive. 268 Iq = np.asarray(form(), 'd') 269 if np.isnan(Iq).any(): 270 continue 271 272 # update value and norm 273 total += weight * Iq 274 weight_norm += weight 275 weighted_volume += weight * form_volume() 276 weighted_radius += weight * form_radius() 277 278 result = np.hstack((total, weight_norm, weighted_volume, weighted_radius)) 279 return result 253 280 254 281
Note: See TracChangeset
for help on using the changeset viewer.