Changeset c0c3393 in sasmodels
- Timestamp:
- Mar 21, 2016 4:57:19 AM (9 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:
- 9f51b0e
- Parents:
- d148fbc (diff), 7ff3cf3 (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. - Location:
- sasmodels
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/core.py
r303d8d6 r7ff3cf3 226 226 weights = np.array([1.0]) 227 227 details = kernel.info['mono_details'] 228 return kernel( pars, weights, details, cutoff)228 return kernel(details, pars, weights, cutoff) 229 229 else: 230 230 pairs = [get_weights(p, values) for p in kernel.info['parameters']] … … 232 232 details = generate.poly_details(kernel.info, weights, pars) 233 233 weights, pars = [np.hstack(v) for v in (weights, pars)] 234 return kernel( pars, weights, details, cutoff)234 return kernel(details, pars, weights, cutoff) 235 235 236 236 def call_ER_VR(model_info, vol_pars): -
sasmodels/generate.py
r4a72d1a r7ff3cf3 650 650 model_info['has_2d'] = par_type['orientation'] or par_type['magnetic'] 651 651 652 def mono_details(max_pd, npars): 652 def mono_details(model_info): 653 max_pd = model_info['max_pd'] 654 npars = len(model_info['parameters']) - 2 653 655 p = 5*max_pd 654 656 c = p + 3*npars 655 657 656 mono = np.zeros(c + 3, 'i')657 mono[0*max_pd:1*max_pd] = range(max_pd) # pd_par: arbitrary order; use first658 mono[1*max_pd:2*max_pd] = [1]*max_pd # pd_length: only one element659 mono[2*max_pd:3*max_pd] = range(2, max_pd+2) # pd_offset: skip scale and background660 mono[3*max_pd:4*max_pd] = [1]*max_pd # pd_stride: vectors of length 1661 mono[4*max_pd:5*max_pd] = [0]*max_pd # pd_isvol: doens't matter if no norm662 mono[p+0*npars:p+1*npars] = range(2, npars+2) # par_offset663 mono[p+1*npars:p+2*npars] = [0]*npars # no coordination664 # mono[p+npars] = 1 # par_coord[0] is coordinated with the first par?665 mono[p+2*npars:p+3*npars] = 0 # fast coord with 0666 mono[c] = 1 # fast_coord_count: one fast index667 mono[c+1] = -1 # theta_var: None668 mono[c+2] = 0 # fast_theta: False669 return mono670 671 def poly_details(model_info, weights, pars,constraints=None):658 details = np.zeros(c + 3, 'int32') 659 details[0*max_pd:1*max_pd] = range(max_pd) # pd_par: arbitrary order; use first 660 details[1*max_pd:2*max_pd] = [1]*max_pd # pd_length: only one element 661 details[2*max_pd:3*max_pd] = range(2, max_pd+2) # pd_offset: skip scale and background 662 details[3*max_pd:4*max_pd] = [1]*max_pd # pd_stride: vectors of length 1 663 details[4*max_pd:5*max_pd] = [0]*max_pd # pd_isvol: doens't matter if no norm 664 details[p+0*npars:p+1*npars] = range(2, npars+2) # par_offset 665 details[p+1*npars:p+2*npars] = [0]*npars # no coordination 666 #details[p+npars] = 1 # par_coord[0] is coordinated with the first par? 667 details[p+2*npars:p+3*npars] = 0 # fast coord with 0 668 details[c] = 1 # fast_coord_count: one fast index 669 details[c+1] = -1 # theta_var: None 670 details[c+2] = 0 # fast_theta: False 671 return details 672 673 def poly_details(model_info, weights, constraints=None): 672 674 if constraints is not None: 673 675 # Need to find the independently varying pars and sort them … … 676 678 # and weights, returning par blocks 677 679 raise ValueError("Can't handle constraints yet") 680 681 max_pd = model_info['max_pd'] 682 npars = len(model_info['parameters']) - 2 683 p = 5*max_pd 684 c = p + 3*npars 685 686 # Decreasing list of polydispersity lengths 687 # Note: the reversing view, x[::-1], does not require a copy 688 idx = np.argsort([len(w) for w in weights])[::-1] 689 details = np.zeros(c + 3, 'int32') 690 details[0*max_pd:1*max_pd] = idx[:max_pd] # pd_par: arbitrary order; use first 691 details[1*max_pd:2*max_pd] = [1]*max_pd # pd_length: only one element 692 details[2*max_pd:3*max_pd] = range(2, max_pd+2) # pd_offset: skip scale and background 693 details[3*max_pd:4*max_pd] = [1]*max_pd # pd_stride: vectors of length 1 694 details[4*max_pd:5*max_pd] = [0]*max_pd # pd_isvol: doens't matter if no norm 695 details[p+0*npars:p+1*npars] = range(2, npars+2) # par_offset 696 details[p+1*npars:p+2*npars] = [0]*npars # no coordination 697 #details[p+npars] = 1 # par_coord[0] is coordinated with the first par? 698 details[p+2*npars:p+3*npars] = 0 # fast coord with 0 699 details[c] = 1 # fast_coord_count: one fast index 700 details[c+1] = -1 # theta_var: None 701 details[c+2] = 0 # fast_theta: False 702 return details 703 704 678 705 679 706 raise ValueError("polydispersity not supported") … … 768 795 oldpars=getattr(kernel_module, 'oldpars', {}), 769 796 tests=getattr(kernel_module, 'tests', []), 770 mono_details = mono_details(MAX_PD, len(kernel_module.parameters))771 797 ) 772 798 process_parameters(model_info) … … 775 801 model_info.update((k, getattr(kernel_module, k, None)) for k in functions) 776 802 create_default_functions(model_info) 803 # Precalculate the monodisperse parameters 804 # TODO: make this a lazy evaluator 805 # make_model_info is called for every model on sasview startup 806 model_info['mono_details'] = mono_details(model_info) 777 807 return model_info 778 808 -
sasmodels/kernel_iq.c
re1bdc7e r7ff3cf3 50 50 ) 51 51 { 52 printf("aliasing\n");53 52 // Storage for the current parameter values. These will be updated as we 54 53 // walk the polydispersity cube. … … 56 55 double *pvec = (double *)(&local_pars); // Alias named parameters with a vector 57 56 58 printf("allocating\n");59 57 local int offset[NPARS-2]; 60 58 61 59 #if 1 // defined(USE_SHORTCUT_OPTIMIZATION) 62 printf("dereferencing %p as %d\n", problem, problem->pd_length[0]);63 60 if (problem->pd_length[0] == 1) { 64 61 // Shouldn't need to copy!! -
sasmodels/kerneldll.py
r4a72d1a r7ff3cf3 50 50 import tempfile 51 51 import ctypes as ct 52 from ctypes import c_void_p, c_int , c_longdouble, c_double, c_float52 from ctypes import c_void_p, c_int32, c_longdouble, c_double, c_float 53 53 54 54 import numpy as np … … 205 205 206 206 # int, int, int, int*, double*, double*, double*, double*, double*, double 207 argtypes = [c_int ]*3 + [c_void_p]*5 + [fp]207 argtypes = [c_int32]*3 + [c_void_p]*5 + [fp] 208 208 self.Iq = self.dll[generate.kernel_name(self.info, False)] 209 209 self.Iqxy = self.dll[generate.kernel_name(self.info, True)] -
sasmodels/kernelpy.py
rd5ac45f r31d22de 128 128 129 129 def __call__(self, fixed, pd, cutoff=1e-5): 130 print("fixed",fixed)131 print("pd", pd)130 #print("fixed",fixed) 131 #print("pd", pd) 132 132 args = self.args[:] # grab a copy of the args 133 133 form, form_volume = self.kernel, self.info['form_volume'] … … 187 187 ################################################################ 188 188 189 #TODO: Wojtek's notes190 #TODO: The goal is to restructure polydispersity loop191 #so it allows fitting arbitrary polydispersity parameters192 #and it accepts cases like coupled parameters193 189 weight = np.empty(len(pd), 'd') 194 190 if weight.size > 0: … … 264 260 result = scale * ret / norm + background 265 261 return result 266 267 """268 Python driver for python kernels269 270 Calls the kernel with a vector of $q$ values for a single parameter set.271 Polydispersity is supported by looping over different parameter sets and272 summing the results. The interface to :class:`PyModel` matches those for273 :class:`kernelcl.GpuModel` and :class:`kerneldll.DllModel`.274 """275 import numpy as np276 from numpy import pi, cos277 278 from .generate import F64279 280 class PyModel(object):281 """282 Wrapper for pure python models.283 """284 def __init__(self, model_info):285 self.info = model_info286 287 def __call__(self, q_vectors):288 q_input = PyInput(q_vectors, dtype=F64)289 kernel = self.info['Iqxy'] if q_input.is_2d else self.info['Iq']290 return PyKernel(kernel, self.info, q_input)291 292 def release(self):293 """294 Free resources associated with the model.295 """296 pass297 298 class PyInput(object):299 """300 Make q data available to the gpu.301 302 *q_vectors* is a list of q vectors, which will be *[q]* for 1-D data,303 and *[qx, qy]* for 2-D data. Internally, the vectors will be reallocated304 to get the best performance on OpenCL, which may involve shifting and305 stretching the array to better match the memory architecture. Additional306 points will be evaluated with *q=1e-3*.307 308 *dtype* is the data type for the q vectors. The data type should be309 set to match that of the kernel, which is an attribute of310 :class:`GpuProgram`. Note that not all kernels support double311 precision, so even if the program was created for double precision,312 the *GpuProgram.dtype* may be single precision.313 314 Call :meth:`release` when complete. Even if not called directly, the315 buffer will be released when the data object is freed.316 """317 def __init__(self, q_vectors, dtype):318 self.nq = q_vectors[0].size319 self.dtype = dtype320 self.is_2d = (len(q_vectors) == 2)321 self.q_vectors = [np.ascontiguousarray(q, self.dtype) for q in q_vectors]322 self.q_pointers = [q.ctypes.data for q in self.q_vectors]323 324 def release(self):325 """326 Free resources associated with the model inputs.327 """328 self.q_vectors = []329 330 class PyKernel(object):331 """332 Callable SAS kernel.333 334 *kernel* is the DllKernel object to call.335 336 *model_info* is the module information337 338 *q_input* is the DllInput q vectors at which the kernel should be339 evaluated.340 341 The resulting call method takes the *pars*, a list of values for342 the fixed parameters to the kernel, and *pd_pars*, a list of (value,weight)343 vectors for the polydisperse parameters. *cutoff* determines the344 integration limits: any points with combined weight less than *cutoff*345 will not be calculated.346 347 Call :meth:`release` when done with the kernel instance.348 """349 def __init__(self, kernel, model_info, q_input):350 self.info = model_info351 self.q_input = q_input352 self.res = np.empty(q_input.nq, q_input.dtype)353 dim = '2d' if q_input.is_2d else '1d'354 # Loop over q unless user promises that the kernel is vectorized by355 # taggining it with vectorized=True356 if not getattr(kernel, 'vectorized', False):357 if dim == '2d':358 def vector_kernel(qx, qy, *args):359 """360 Vectorized 2D kernel.361 """362 return np.array([kernel(qxi, qyi, *args)363 for qxi, qyi in zip(qx, qy)])364 else:365 def vector_kernel(q, *args):366 """367 Vectorized 1D kernel.368 """369 return np.array([kernel(qi, *args)370 for qi in q])371 self.kernel = vector_kernel372 else:373 self.kernel = kernel374 fixed_pars = model_info['partype']['fixed-' + dim]375 pd_pars = model_info['partype']['pd-' + dim]376 vol_pars = model_info['partype']['volume']377 378 # First two fixed pars are scale and background379 pars = [p.name for p in model_info['parameters'][2:]]380 offset = len(self.q_input.q_vectors)381 self.args = self.q_input.q_vectors + [None] * len(pars)382 self.fixed_index = np.array([pars.index(p) + offset383 for p in fixed_pars[2:]])384 self.pd_index = np.array([pars.index(p) + offset385 for p in pd_pars])386 self.vol_index = np.array([pars.index(p) + offset387 for p in vol_pars])388 try: self.theta_index = pars.index('theta') + offset389 except ValueError: self.theta_index = -1390 391 # Caller needs fixed_pars and pd_pars392 self.fixed_pars = fixed_pars393 self.pd_pars = pd_pars394 395 def __call__(self, fixed, pd, cutoff=1e-5):396 #print("fixed",fixed)397 #print("pd", pd)398 args = self.args[:] # grab a copy of the args399 form, form_volume = self.kernel, self.info['form_volume']400 # First two fixed401 scale, background = fixed[:2]402 for index, value in zip(self.fixed_index, fixed[2:]):403 args[index] = float(value)404 res = _loops(form, form_volume, cutoff, scale, background, args,405 pd, self.pd_index, self.vol_index, self.theta_index)406 407 return res408 409 def release(self):410 """411 Free resources associated with the kernel.412 """413 self.q_input = None414 415 def _loops(form, form_volume, cutoff, scale, background,416 args, pd, pd_index, vol_index, theta_index):417 """418 *form* is the name of the form function, which should be vectorized over419 q, but otherwise have an interface like the opencl kernels, with the420 q parameters first followed by the individual parameters in the order421 given in model.parameters (see :mod:`sasmodels.generate`).422 423 *form_volume* calculates the volume of the shape. *vol_index* gives424 the list of volume parameters425 426 *cutoff* ignores the corners of the dispersion hypercube427 428 *scale*, *background* multiplies the resulting form and adds an offset429 430 *args* is the prepopulated set of arguments to the form function, starting431 with the q vectors, and including slots for all the parameters. The432 values for the parameters will be substituted with values from the433 dispersion functions.434 435 *pd* is the list of dispersion parameters436 437 *pd_index* are the indices of the dispersion parameters in *args*438 439 *vol_index* are the indices of the volume parameters in *args*440 441 *theta_index* is the index of the theta parameter for the sasview442 spherical correction, or -1 if there is no angular dispersion443 """444 445 ################################################################446 # #447 # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #448 # !! !! #449 # !! KEEP THIS CODE CONSISTENT WITH KERNEL_TEMPLATE.C !! #450 # !! !! #451 # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #452 # #453 ################################################################454 455 weight = np.empty(len(pd), 'd')456 if weight.size > 0:457 # weight vector, to be populated by polydispersity loops458 459 # identify which pd parameters are volume parameters460 vol_weight_index = np.array([(index in vol_index) for index in pd_index])461 462 # Sort parameters in decreasing order of pd length463 Npd = np.array([len(pdi[0]) for pdi in pd], 'i')464 order = np.argsort(Npd)[::-1]465 stride = np.cumprod(Npd[order])466 pd = [pd[index] for index in order]467 pd_index = pd_index[order]468 vol_weight_index = vol_weight_index[order]469 470 fast_value = pd[0][0]471 fast_weight = pd[0][1]472 else:473 stride = np.array([1])474 vol_weight_index = slice(None, None)475 # keep lint happy476 fast_value = [None]477 fast_weight = [None]478 479 ret = np.zeros_like(args[0])480 norm = np.zeros_like(ret)481 vol = np.zeros_like(ret)482 vol_norm = np.zeros_like(ret)483 for k in range(stride[-1]):484 # update polydispersity parameter values485 fast_index = k % stride[0]486 if fast_index == 0: # bottom loop complete ... check all other loops487 if weight.size > 0:488 for i, index, in enumerate(k % stride):489 args[pd_index[i]] = pd[i][0][index]490 weight[i] = pd[i][1][index]491 else:492 args[pd_index[0]] = fast_value[fast_index]493 weight[0] = fast_weight[fast_index]494 495 # Computes the weight, and if it is not sufficient then ignore this496 # parameter set.497 # Note: could precompute w1*...*wn so we only need to multiply by w0498 w = np.prod(weight)499 if w > cutoff:500 # Note: can precompute spherical correction if theta_index is not501 # the fast index. Correction factor for spherical integration502 #spherical_correction = abs(cos(pi*args[phi_index])) if phi_index>=0 else 1.0503 spherical_correction = (abs(cos(pi * args[theta_index])) * pi / 2504 if theta_index >= 0 else 1.0)505 #spherical_correction = 1.0506 507 # Call the scattering function and adds it to the total.508 I = form(*args)509 if np.isnan(I).any(): continue510 ret += w * I * spherical_correction511 norm += w512 513 # Volume normalization.514 # If there are "volume" polydispersity parameters, then these515 # will be used to call the form_volume function from the user516 # supplied kernel, and accumulate a normalized weight.517 # Note: can precompute volume norm if fast index is not a volume518 if form_volume:519 vol_args = [args[index] for index in vol_index]520 vol_weight = np.prod(weight[vol_weight_index])521 vol += vol_weight * form_volume(*vol_args)522 vol_norm += vol_weight523 524 positive = (vol * vol_norm != 0.0)525 ret[positive] *= vol_norm[positive] / vol[positive]526 result = scale * ret / norm + background527 return result
Note: See TracChangeset
for help on using the changeset viewer.