Changeset 6d6508e in sasmodels for sasmodels/kernelpy.py
- Timestamp:
- Apr 7, 2016 4:57:33 PM (8 years ago)
- Branches:
- master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- d2fc9a4
- Parents:
- 3707eee
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/kernelpy.py
ra8a7f08 r6d6508e 17 17 """ 18 18 def __init__(self, model_info): 19 # Make sure Iq and Iqxy are available and vectorized 20 _create_default_functions(model_info) 19 21 self.info = model_info 20 22 21 23 def make_kernel(self, q_vectors): 22 24 q_input = PyInput(q_vectors, dtype=F64) 23 kernel = self.info ['Iqxy'] if q_input.is_2d else self.info['Iq']25 kernel = self.info.Iqxy if q_input.is_2d else self.info.Iq 24 26 return PyKernel(kernel, self.info, q_input) 25 27 … … 94 96 self.dim = '2d' if q_input.is_2d else '1d' 95 97 96 partable = model_info ['parameters']98 partable = model_info.parameters 97 99 kernel_parameters = (partable.iqxy_parameters if q_input.is_2d 98 100 else partable.iq_parameters) … … 129 131 # parameter array. 130 132 if q_input.is_2d: 131 form = model_info ['Iqxy']133 form = model_info.Iqxy 132 134 qx, qy = q_input.q[:,0], q_input.q[:,1] 133 135 self._form = lambda: form(qx, qy, *kernel_args) 134 136 else: 135 form = model_info ['Iq']137 form = model_info.Iq 136 138 q = q_input.q 137 139 self._form = lambda: form(q, *kernel_args) 138 140 139 141 # Generate a closure which calls the form_volume if it exists. 140 form_volume = model_info ['form_volume']142 form_volume = model_info.form_volume 141 143 self._volume = ((lambda: form_volume(*volume_args)) if form_volume 142 144 else (lambda: 1.0)) 143 145 144 def __call__(self, details, weights, values, cutoff):145 # type: (.generate.C oordinationDetails, np.ndarray, np.ndarray, float) -> np.ndarray146 def __call__(self, call_details, weights, values, cutoff): 147 # type: (.generate.CallDetails, np.ndarray, np.ndarray, float) -> np.ndarray 146 148 res = _loops(self._parameter_vector, self._form, self._volume, 147 self.q_input.nq, details, weights, values, cutoff)149 self.q_input.nq, call_details, weights, values, cutoff) 148 150 return res 149 151 … … 158 160 form_volume, # type: Callable[[], float] 159 161 nq, # type: int 160 details, # type: .generate.CoordinationDetails162 call_details,# type: .generate.CallDetails 161 163 weights, # type: np.ndarray 162 164 values, # type: np.ndarray … … 172 174 # # 173 175 ################################################################ 174 parameters[:] = values[ details.par_offset]176 parameters[:] = values[call_details.par_offset] 175 177 scale, background = values[0], values[1] 176 if details.num_active == 0:178 if call_details.num_active == 0: 177 179 norm = float(form_volume()) 178 180 if norm > 0.0: … … 183 185 partial_weight = np.NaN 184 186 spherical_correction = 1.0 185 pd_stride = details.pd_stride[:details.num_active]186 pd_length = details.pd_length[:details.num_active]187 pd_offset = details.pd_offset[:details.num_active]187 pd_stride = call_details.pd_stride[:call_details.num_active] 188 pd_length = call_details.pd_length[:call_details.num_active] 189 pd_offset = call_details.pd_offset[:call_details.num_active] 188 190 pd_index = np.empty_like(pd_offset) 189 offset = np.empty_like( details.par_offset)190 theta = details.theta_par191 offset = np.empty_like(call_details.par_offset) 192 theta = call_details.theta_par 191 193 fast_length = pd_length[0] 192 194 pd_index[0] = fast_length 193 195 total = np.zeros(nq, 'd') 194 196 norm = 0.0 195 for loop_index in range( details.total_pd):197 for loop_index in range(call_details.total_pd): 196 198 # update polydispersity parameter values 197 199 if pd_index[0] == fast_length: 198 200 pd_index[:] = (loop_index/pd_stride)%pd_length 199 201 partial_weight = np.prod(weights[pd_offset+pd_index][1:]) 200 for k in range( details.num_coord):201 par = details.par_coord[k]202 coord = details.pd_coord[k]203 this_offset = details.par_offset[par]202 for k in range(call_details.num_coord): 203 par = call_details.par_coord[k] 204 coord = call_details.pd_coord[k] 205 this_offset = call_details.par_offset[par] 204 206 block_size = 1 205 207 for bit in xrange(32): … … 211 213 offset[par] = this_offset 212 214 parameters[par] = values[this_offset] 213 if par == theta and not ( details.par_coord[k]&1):215 if par == theta and not (call_details.par_coord[k]&1): 214 216 spherical_correction = max(abs(cos(pi/180 * parameters[theta])), 1e-6) 215 for k in range( details.num_coord):216 if details.pd_coord[k]&1:217 #par = details.par_coord[k]217 for k in range(call_details.num_coord): 218 if call_details.pd_coord[k]&1: 219 #par = call_details.par_coord[k] 218 220 parameters[par] = values[offset[par]] 219 221 #print "par",par,offset[par],parameters[par+2] … … 241 243 else: 242 244 return np.ones(nq, 'd')*background 245 246 247 248 def _create_vector_Iq(model_info): 249 """ 250 Define Iq as a vector function if it exists. 251 """ 252 Iq = model_info.Iq 253 if callable(Iq) and not getattr(Iq, 'vectorized', False): 254 def vector_Iq(q, *args): 255 """ 256 Vectorized 1D kernel. 257 """ 258 return np.array([Iq(qi, *args) for qi in q]) 259 vector_Iq.vectorized = True 260 model_info.Iq = vector_Iq 261 262 def _create_vector_Iqxy(model_info): 263 """ 264 Define Iqxy as a vector function if it exists, or default it from Iq(). 265 """ 266 Iq, Iqxy = model_info.Iq, model_info.Iqxy 267 if callable(Iqxy) and not getattr(Iqxy, 'vectorized', False): 268 def vector_Iqxy(qx, qy, *args): 269 """ 270 Vectorized 2D kernel. 271 """ 272 return np.array([Iqxy(qxi, qyi, *args) for qxi, qyi in zip(qx, qy)]) 273 vector_Iqxy.vectorized = True 274 model_info.Iqxy = vector_Iqxy 275 elif callable(Iq): 276 # Iq is vectorized because create_vector_Iq was already called. 277 def default_Iqxy(qx, qy, *args): 278 """ 279 Default 2D kernel. 280 """ 281 return Iq(np.sqrt(qx**2 + qy**2), *args) 282 default_Iqxy.vectorized = True 283 model_info.Iqxy = default_Iqxy 284 285 def _create_default_functions(model_info): 286 """ 287 Autogenerate missing functions, such as Iqxy from Iq. 288 289 This only works for Iqxy when Iq is written in python. :func:`make_source` 290 performs a similar role for Iq written in C. This also vectorizes 291 any functions that are not already marked as vectorized. 292 """ 293 _create_vector_Iq(model_info) 294 _create_vector_Iqxy(model_info) # call create_vector_Iq() first 295
Note: See TracChangeset
for help on using the changeset viewer.